Externalize engine function. Still ugly as balls.

main
Shoofle Munroe 11 years ago
parent 3429b69bdf
commit aecddee95f
  1. 74
      articles/dynamic_systems_in_games.article.html
  2. 67
      articles/dynamic_systems_in_games/engine.js

@ -2,57 +2,19 @@
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script> <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/javascript" src="/static/flot/jquery.flot.js"></script> <script type="text/javascript" src="/static/flot/jquery.flot.js"></script>
<script type="text/javascript" src="/static/flot/jquery.flot.resize.js"></script> <script type="text/javascript" src="/static/flot/jquery.flot.resize.js"></script>
<script type="text/javascript" src="engine.js"></script>
<h1>Dynamic Systems in Games</h1> <h1>Dynamic Systems in Games</h1>
<p>Here, take a look at this simple game I coded up. Your task is to keep an engine's temperature as high as possible, to maximize power output, without dmaaging the engine. The threshhold for damage is at <span data-var="damage_threshhold">10</span> degrees, and the engine will stop burning and deignite if it goes under <span data-var="ignition_threshhold">2</span> degrees.</p> <p>Here, take a look at this simple game I coded up. Your task is to keep an engine's temperature as high as possible, to maximize power output, without dmaaging the engine. The threshhold for damage is at <span data-var="damage_threshhold">10</span> degrees, and the engine will stop burning and deignite if it goes under <span data-var="ignition_threshhold">2</span> degrees.</p>
<div class="row-fluid"> <div class="row-fluid">
<div id="fuel-management-1" class="span4 offset4"> <div id="fuel-management-1" class="span4 offset4">
<script type="text/javascript"> <script type="text/javascript">
var first_graph = (function (element) { function heyo(q) {
var container = $(element); if (q.temperature.value < q.ignition_threshhold.value) {
var T = { return -0.5*q.temperature.value;
"update": function () { }
this.value += RR.value*timestep/1000; return q.temperature.value*q.fuel_flow_rate.value - 0.5*q.temperature.value;
this.value -= this.value*temperature_decay*timestep/1000; }
if (this.value < 0) { this.value = 0; } engine($('#fuel-management-1'), heyo);
},
"out": function () {
container.find('#temp-out').html(this.value.toFixed(2));
if (this.value > damage_threshhold) { container.find('#damage').show();}
else { container.find('#damage').hide(); }
if (this.value < ignition_threshhold) { container.find('#noignition').show(); }
else { container.find('#noignition').hide(); }
},
"value": 0,
};
var F = {
"update": function () { this.value = container.find('[name=fuel]').val(); },
"out": function () { update_graph_one(this.value); },
"value": 0,
};
var RR = {
"update": function () { this.value = T.value * F.value; },
"out": function () {},
"value": 0,
};
var ignition_threshhold = 2;
var damage_threshhold = 10;
var temperature_decay = 0.5;
var timestep=10;
var quantities = [T, F, RR];
var a, b;
$(element).ready(function () {
container.find('[name=ignition]').on('click', function() { T.value = T.value + 5; });
a = setInterval(jQuery.each, timestep, quantities, function() { this.update(); });
b = setInterval(jQuery.each, timestep, quantities, function() { this.out(); });
});
return {
'container': container,
'quantities': quantities,
};
})($('#fuel-management-1'));
</script> </script>
<div id="flow_rate"> <div id="flow_rate">
<label for="fuel">Fuel Flow Rate</label> <label for="fuel">Fuel Flow Rate</label>
@ -62,31 +24,13 @@
<span><span id="temp-out">0</span> degrees</span> <span><span id="temp-out">0</span> degrees</span>
<span id="noignition" class="label label-info">No ignition</span> <span id="noignition" class="label label-info">No ignition</span>
<span id="damage" class="label label-warning">DAMAGE!</span> <span id="damage" class="label label-warning">DAMAGE!</span>
<div id="potential_plot" style="width:100%;height:400px"></div>
</div> </div>
</div> </div>
<p>It's interesting! Or maybe it's not. I threw this together trying to think of what an interesting way for an engine to work might be. The fundamental relationship here is:</p> <p>It's interesting! Or maybe it's not. I threw this together trying to think of what an interesting way for an engine to work might be. The fundamental relationship here is:</p>
\[\frac{\partial T}{\partial t} = c_F T F - c_T (T - T_0)\] \[\frac{\partial T}{\partial t} = c_F T F - c_T (T - T_0)\]
<p>That is, at any given moment, the temperature is changing (\(\frac{\partial T}{\partial t}\)) by increasing proportional to the temperature times the fuel flow rate (\(c_F T F\)) and decreasing proportional to the difference between the chamber temperature and the ambient temperature (\(c_T (T - T_0)\)). The deignition isn't described in this formula, but it's pretty simple - the \(c_F T F\) factor becomes zero when the temperature is less than <span data-var="ignition_threshhold">2</span> degrees.</p> <p>That is, at any given moment, the temperature is changing (\(\frac{\partial T}{\partial t}\)) by increasing proportional to the temperature times the fuel flow rate (\(c_F T F\)) and decreasing proportional to the difference between the chamber temperature and the ambient temperature (\(c_T (T - T_0)\)). The deignition isn't described in this formula, but it's pretty simple - the \(c_F T F\) factor becomes zero when the temperature is less than <span data-var="ignition_threshhold">2</span> degrees.</p>
<p>As it turns out, (surprise of surprises!) that description in a formula is pretty useless for actually understanding how this feels. The key was to look at it as a function of the temperature. See, the player changes \(F\), and I want to get a feel for how the temperature's going to change. So I made a graph with respect to \(T\) where the slope is given by \(\frac{\partial T}{\partial t}\). <span class="sidenote">Note that this is not just going to undo the partial derivative. In this graph, we're integrating against \(T\), not \(t\). Roughly, this graph should be thought of as one where the temperature would slide down hills. Anyway.</span></p> <p>As it turns out, (surprise of surprises!) that description in a formula is pretty useless for actually understanding how this feels. The key was to look at it as a function of the temperature. See, the player changes \(F\), and I want to get a feel for how the temperature's going to change. So I made a graph with respect to \(T\) where the slope is given by \(\frac{\partial T}{\partial t}\). <span class="sidenote">Note that this is not just going to undo the partial derivative. In this graph, we're integrating against \(T\), not \(t\). Roughly, this graph should be thought of as one where the temperature would slide down hills. Anyway.</span></p>
<script type="text/javascript">
var data=[], step_size=0.5, area;
var config = { xaxis: { min:0, max:15 }, yaxis: { min:-5, max:5} };
var fn = function(T,F) {
if (T < 2) { return -0.5*T; } // ignition threshhold
return T*F - 0.5*T;
}
function update_graph_one(F) {
area = 0; data=[];
for (var i=0; i<15; i+= step_size) {
area = area - step_size*fn(i, F); // fuel flow rate is 0.7
data.push([i, area])
}
$('#first_temperature_fake_potential_graph').data('plot').setData([data]);
$('#first_temperature_fake_potential_graph').data('plot').draw();
}
$(document).ready(function() { $('#first_temperature_fake_potential_graph').plot([[]], config); });
</script>
<div id="first_temperature_fake_potential_graph" style="width:100%;height:400px;clear:both;"></div>
<p>You can feel free to slide around the fuel flow rate slider to play with this. When the graph is flat, that temperature is stable. (Remember: temperature is on the x-axis.)</p> <p>You can feel free to slide around the fuel flow rate slider to play with this. When the graph is flat, that temperature is stable. (Remember: temperature is on the x-axis.)</p>
<p>Well. This is <em>terrible</em>. There aren't any stable points! <p>Well. This is <em>terrible</em>. There aren't any stable points!
</article> </article>

@ -0,0 +1,67 @@
function engine(element, reaction_rate_function) {
var container = $(element);
var graph, graph_plot;
var q = {};
q.temperature = {
"update": function () {
this.value += reaction_rate_function(q)*timestep/1000
if (this.value < 0) { this.value = 0; }
},
"out": function () {
container.find('#temp-out').html(this.value.toFixed(2));
if (this.value > damage_threshhold) { container.find('#damage').show();}
else { container.find('#damage').hide(); }
if (this.value < q.ignition_threshhold.value) { container.find('#noignition').show(); }
else { container.find('#noignition').hide(); }
},
"value": 0,
};
q.fuel_flow_rate = {
"update": function () { this.value = container.find('[name=fuel]').val(); },
"out": function () { update_graph(); },
"value": 0,
};
q.ignition_threshhold = {
"update": function () {},
"out": function() {},
"value": 2,
};
var ignition_boost = 5;
var damage_threshhold = 10;
var temperature_decay = 0.5;
var timestep=10;
var graph_config = { xaxis: { min:0, max:15 }, yaxis: { min:-4, max:4 } };
function update_graph() {
var step_size = 0.2;
var data = [], area=0;
for (var i=0; i<15; i+=step_size) {
area -= step_size * reaction_rate_function({
"fuel_flow_rate": q.fuel_flow_rate,
"temperature": { "value":i },
"ignition_threshhold": q.ignition_threshhold,
});
data.push([i, area]);
}
graph_plot.setData([data]);
graph_plot.draw();
}
var a, b;
container.ready(function () {
container.find('[name=ignition]').on('click', function() { q.temperature.value += ignition_boost; });
a = setInterval(jQuery.each, timestep, q, function(name, x) { x.update(); });
b = setInterval(jQuery.each, timestep, q, function(name, x) { x.out(); });
graph = container.find('#potential_plot');
graph_plot = $.plot(graph, [[]], graph_config);
});
return {
'container': container,
'quantities': q,
'graph_container': graph,
'graph_plot': graph_plot,
};
}
Loading…
Cancel
Save