🔒 Locked
Weapon overheating
Advertisement
Original Post
I'd like to add a simple algorithm to reduce a weapon's heat each frame, based on time. The weapon's current heat should dictate how fast it cools down (more heat results in slower cooling), but it's also important that the cooling is as independent from the game's update frame-rate as possible. For example, something like this would work with a constant frame rate: Heat -= frame_time * scaler * (1.0 - (Heat*0.4)); But if a huge portion of time jumps by in one frame, the weapon will be cheated out of several iterations where its heat should have been lower during the calculation. My math skills are not my proudest feature, so I could use some help. All of the weapons in my game will use the same general cool-down scaler, and will have tweaked heat-per-shot values for individuality. Any advice?
So are your games updates based on frames or real time? You should probably stick to one for everything like heat or movement.
EDIT:
For your problem I would give each weapon type 3 values: one for how much heat each shot generates, how much heat it can accumulate before malfunctioning and how fast it loses heat. Each weapon instance would have a additional value for its current heat.
float heatValue=0;
//weapon fire
heatValue += //*generated heat*//;
//frame
heatValue -= elapsedSeconds * cooling
if (heatValue < 0){
heatValue = 0;
}
EDIT2:
Wouldn't more heat result in faster cooling since your increasing the temperature difference between it and the environment.
EDIT:
For your problem I would give each weapon type 3 values: one for how much heat each shot generates, how much heat it can accumulate before malfunctioning and how fast it loses heat. Each weapon instance would have a additional value for its current heat.
float heatValue=0;
//weapon fire
heatValue += //*generated heat*//;
//frame
heatValue -= elapsedSeconds * cooling
if (heatValue < 0){
heatValue = 0;
}
EDIT2:
Wouldn't more heat result in faster cooling since your increasing the temperature difference between it and the environment.
Just a quick point:
It actually works the other way in the real-world. The amount of heat transferred is proportional to the difference in temperature, so the hotter the weapon, the faster it would cool down (slowing down as it got closer to room temperature)
As for your other problem, the simplest solution would be to run the simulation in steps. So if you ran it in steps of 5ms (say) then if your frame_time is 20ms, you run it 4 times. If it's 4 seconds, you run it 800 times.
Quote:
Original post by Kest
more heat results in slower cooling
It actually works the other way in the real-world. The amount of heat transferred is proportional to the difference in temperature, so the hotter the weapon, the faster it would cool down (slowing down as it got closer to room temperature)
As for your other problem, the simplest solution would be to run the simulation in steps. So if you ran it in steps of 5ms (say) then if your frame_time is 20ms, you run it 4 times. If it's 4 seconds, you run it 800 times.
Quote:
Original post by Kaze
So are your games updates based on frames or real time? You should probably stick to one for everything like heat or movement.
Real time. Everything updates each frame, based on the amount of time that passed since the last frame. The frame rate isn't locked, so it can be anywhere from 30 FPS to 400 FPS.
Quote:
For your problem I would give each weapon type 3 values: one for how much heat each shot generates, how much heat it can accumulate before malfunctioning and how fast it loses heat. Each weapon instance would have a additional value for its current heat.
I wanted to keep it simple and make overheating occur at 1.0. If I need to change the total magnitude, I can just scale the heating and cooling values (for example, scaling both by 0.25 would be the same as overheating at 4.0).
Quote:
float heatValue=0;
//weapon fire
heatValue += //*generated heat*//;
//frame
heatValue -= elapsedSeconds * cooling
if (heatValue < 0){
heatValue = 0;
}
This still isn't separated from the frame rate. As with my first example, it penalizes the weapon's cooling rate at lower frame rates.
edit: Sorry, I didn't notice you removed heat as part of the cool-down value. This would be separate from the frame rate, but not the type of cooling I was looking for.
Quote:
Wouldn't more heat result in faster cooling since your increasing the temperature difference between it and the environment.
I'm not an expert on ..thermodynamics, but I believe you're correct. However, the weapons use futuristic technology, so I'm hoping that will put a band-aid on the punch to realism. For example, several layers of some material may heat up in sequence, from inside out, then have to cool in the opposite order. When the outer layers are cool, the inner layers cool down much faster. But that's just a random made-up explanation, which I won't be including in the game.
Quote:
Original post by Codeka
As for your other problem, the simplest solution would be to run the simulation in steps. So if you ran it in steps of 5ms (say) then if your frame_time is 20ms, you run it 4 times. If it's 4 seconds, you run it 800 times.
I started to use a loop, but it seemed pretty barbaric. The game has a slow motion feature, so unless the loop-time interval is very small, it still wouldn't be correct. However, it remains an option.
[Edited by - Kest on March 1, 2009 7:35:08 PM]
Quote:
Original post by Kest Quote:
Original post by Codeka
As for your other problem, the simplest solution would be to run the simulation in steps. So if you ran it in steps of 5ms (say) then if your frame_time is 20ms, you run it 4 times. If it's 4 seconds, you run it 800 times.
I started to use a loop, but it seemed pretty barbaric. The game has a slow motion feature, so unless the loop-time interval is very small, it still wouldn't be correct. However, it remains an option.
In slow-motion, you could similarly scale your "micro-loop" factor. So if your "real-time" step is 5ms, you can make your 5x slow-motion step 1ms, etc.
Another option is to just use your regular formala for normal values, and only do the multiple-loops thing if the frame time is sufficiently large.
Quote:
Original post by Codeka Quote:
Original post by Kest Quote:
Original post by Codeka
As for your other problem, the simplest solution would be to run the simulation in steps. So if you ran it in steps of 5ms (say) then if your frame_time is 20ms, you run it 4 times. If it's 4 seconds, you run it 800 times.
I started to use a loop, but it seemed pretty barbaric. The game has a slow motion feature, so unless the loop-time interval is very small, it still wouldn't be correct. However, it remains an option.
In slow-motion, you could similarly scale your "micro-loop" factor. So if your "real-time" step is 5ms, you can make your 5x slow-motion step 1ms, etc.
Another option is to just use your regular formala for normal values, and only do the multiple-loops thing if the frame time is sufficiently large.
That's probably what I'll do if I can't find a better solution. I assumed there would be some type of straight-answer-formula to compute this type of value.
For example, I use powf() to compute weighted averages based on the frame time (change=powf(0.995f,time)), and the results stay reasonably neutral, despite the flexible frame rate. A weighted average moves faster as the start and goal vary, and slower as they become more similar. My brain is pretty taxed, but it seems like there would be a simple way to reverse the effect. I'm either unable to come up with the modification to do it, or unable to realize it can't easily be done. Can anyone tell me which it is? Or even better, can anyone show me how it could be done?
I would perform a weighted average like this:
float change = 1.0f - powf(0.995f,time);
state += (goal - state) * change;
edit: left out part of the above calculation
Using the difference between the objects as the change scaler obviously makes it change faster as they become separated. In my 0.0 to 1.0 situation, would reversing the effect be as simple as state += (1.0f - (goal - state )) * change? Or would that corrupt whatever is making it frame-rate independent?
I appreciate all of your help.
[Edited by - Kest on March 1, 2009 11:16:08 PM]
Assuming the external temperature E remains constant (i.e. weapon heat is dispersed fast), cooling is exponential with temperature tending to E (i.e. equilibrium with the environment): dT/dt= -C(T-E) where C is a positive constant (larger for better dissipators).
Over a time step h, temperature T changes from T0 to E plus (T0-E)exp(-C*h) Meanwhile, if the weapon is cool enough (T <= Tok) it can shoot and heat up; waiting for a large time step h to pass would be indeed unfair.
You can instead, given T0 at the start of the turn, solve for a fractional time step h the equation Tok - E =(T0-E)exp(-C*h): this is the time when the weapon is able to shoot and heat up by a constant amount per shot H, at which point you can compute cooldown times again starting from Tok plus H. The process ends when the next shot would be after the end of the turn, at which point you compute the temperature at the end of the turn instead.
The firing rate of the weapon should be limited independently from cooldown; there is a transient when a cool weapon shoots as fast as possible until it exceeds Tok, and the sustained firing rate might be too fast at low ambient temperatures.
You really need calculus to find the heat H after a time t, given an equation like that. It's a matter of solving a differential equation.
I've quickly worked through it (I haven't included the details here, I'm assuming you aren't familiar with calculus) and found that heat H after a time interval t (starting from H = 1.0) is given by
H = 1.0 + (1 - exp(scaling*t/2.5))*2.5 (1)
and the time t at which the heat will be H is
t = 2.5*log(1.0 - 0.4(H - 1.0))/scaling (2)
From these two equations you should be able to find the heat after any time interval.
For example, if the heat is currently 0.75, and you want to know the heat after another 4.5 time units, then you can find the time that has elapsed so far (i.e. since the heat was 1.0) using (2) (with a scaling of 0.1, it's 2.38). Then add this to the time you're interested in (6.88) and plug it into (1) to get H = 0.21
Hope this helps.
EDIT: The above posters are correct in saying that the weapon really should cool faster when it's hotter, not cooler. Nonetheless, if you want to stick to your model, the equations I've given ought to help you.
EDIT2:
If your weapon's heat can go over 1.0, and you want to find the time at which it will be under 1.0, use a modified version of (2):
t = 2.5*log(overheat - 0.4(H - 1.0))/scaling
Say the gun is at H = 1.4, and it can only shoot at under H = 1.0, then make overheat = 1.4 and H = 0.999. The equation will give you the number of time units until the weapon is usable again. However, this will only work accurately at the exact time the weapon overheats. I would suggest calling this equation whenever the heat goes over 1.0, and setting a timer based on the outcome; once the timer has finished you can set the heat to be 0.999 and allow the gun to be fired again.
I've quickly worked through it (I haven't included the details here, I'm assuming you aren't familiar with calculus) and found that heat H after a time interval t (starting from H = 1.0) is given by
H = 1.0 + (1 - exp(scaling*t/2.5))*2.5 (1)
and the time t at which the heat will be H is
t = 2.5*log(1.0 - 0.4(H - 1.0))/scaling (2)
From these two equations you should be able to find the heat after any time interval.
For example, if the heat is currently 0.75, and you want to know the heat after another 4.5 time units, then you can find the time that has elapsed so far (i.e. since the heat was 1.0) using (2) (with a scaling of 0.1, it's 2.38). Then add this to the time you're interested in (6.88) and plug it into (1) to get H = 0.21
Hope this helps.
EDIT: The above posters are correct in saying that the weapon really should cool faster when it's hotter, not cooler. Nonetheless, if you want to stick to your model, the equations I've given ought to help you.
EDIT2:
If your weapon's heat can go over 1.0, and you want to find the time at which it will be under 1.0, use a modified version of (2):
t = 2.5*log(overheat - 0.4(H - 1.0))/scaling
Say the gun is at H = 1.4, and it can only shoot at under H = 1.0, then make overheat = 1.4 and H = 0.999. The equation will give you the number of time units until the weapon is usable again. However, this will only work accurately at the exact time the weapon overheats. I would suggest calling this equation whenever the heat goes over 1.0, and setting a timer based on the outcome; once the timer has finished you can set the heat to be 0.999 and allow the gun to be fired again.
Quote:
Original post by shaolinspin
I've quickly worked through it (I haven't included the details here, I'm assuming you aren't familiar with calculus) and found that heat H after a time interval t (starting from H = 1.0) is given by
H = 1.0 + (1 - exp(scaling*t/2.5))*2.5 (1)
I work with vector math enough to be decent with it, but calculus is indeed unfamiliar to me. However, I can discern a lot more about a calculation from a programming-style formula than one using math syntax - I really appreciate that.
Will this not function accurately (with a flexible frame rate) if H doesn't start at 1.0? The weapon's heat will fluctuate continuously, and rarely stop at 1.0 before it starts cooling down. Whatever calculation I use needs to be capable of generating a loss of heat based on time from any current heat between 0.0 and 1.0.
However, after experimenting, I believe I do want to make the weapon cool down more realistically. Not because its more realistic, but because I think it will work better for the game. I currently have it set up to use a weighted average with a maximum speed limit. I like that it cools down at a more constant rate when its hot, then slows down the cooling at medium and low levels. Here's the simple math I'm using:
float hfac = FactorTo( WEAPON_COOL_FAC_BAD, WEAPON_COOL_FAC_GOOD, WeaponSpecs.CooldownFac );float hspeed = FactorTo( WEAPON_COOL_SPEED_BAD, WEAPON_COOL_SPEED_GOOD, WeaponSpecs.CooldownFac );float change = -HeatFactor * ( 1.0f - powf(hfac,time) );if( change < hspeed * time ) change = hspeed * time;HeatFactor += change;FactorTo just factors between the first and second parameters by the third parameter (0.0 to 1.0 scaler). I'm considering switching it to a slope calculation that runs nearly horizontal between input values 1.0 and 0.5, then starts sloping very gradually between 0.5 and 0.0.
Heat dissipation, with a lumped model (i.e., you assume the whole gun has the same temperature), is described by a first order linear ODE. It doesn't get simpler than that.
The solution will be,
T(t) = T0 exp(-t/tau)
where T0 is the initial temperature, and tau is the time constant; you'd adjust it to tune how fast the gun cools down. Larger time constants correspond to longer cooldown times. Note that I'm treating zero as "room temperature."
If you're doing this with a variable timestep, then one way to implement this would be, at each timestep, to do,
T := T exp(-(tnow-tlast)/tau)
With this method, you could also easily handle the heat added to the gun by each gunshot: Simply, whenever a shot is fired, add some constant (really the thermal energy divided by the heat capacity of the gun... not that you need to calculate this ratio; just treat it as a single constant) to T.
The solution will be,
T(t) = T0 exp(-t/tau)
where T0 is the initial temperature, and tau is the time constant; you'd adjust it to tune how fast the gun cools down. Larger time constants correspond to longer cooldown times. Note that I'm treating zero as "room temperature."
If you're doing this with a variable timestep, then one way to implement this would be, at each timestep, to do,
T := T exp(-(tnow-tlast)/tau)
With this method, you could also easily handle the heat added to the gun by each gunshot: Simply, whenever a shot is fired, add some constant (really the thermal energy divided by the heat capacity of the gun... not that you need to calculate this ratio; just treat it as a single constant) to T.
Ah, there you go - I hope with Emergent's answer you now have enough information to implement a reasonable model. In general it might well be easier to stick to a realistic (standard) model and just play with the parameters, since most of the mathematical working will already exist online somewhere.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement