diff --git a/articles/dynamic_systems_in_games.article.html b/articles/dynamic_systems_in_games.article.html index b32ff2f..89a6f20 100644 --- a/articles/dynamic_systems_in_games.article.html +++ b/articles/dynamic_systems_in_games.article.html @@ -29,11 +29,12 @@ The dotted lines indicate what the curve will look like if you adjust the fuel flow rate up or down a little bit.

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:

-\[\frac{\partial T}{\partial t} = c_F T F - c_T (T - T_0)\] -

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 2 degrees.

-

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}\). 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.

-

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.)

-

Well. This is terrible. There aren't any stable points! +\[\frac{\partial T}{\partial t} = c_R T F - c_T (T - T_0)\] +

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_R 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_R T F\) factor becomes zero when the temperature is less than 2 degrees.

+

As it turns out, (surprise of surprises!) that differential equation description is pretty useless for actually understanding how this feels. The key was to look at the rate of heating/cooling (\(\frac{\partial T}{\partial t}\)) as a function of the temperature. See, the player changes \(F\), and I want to understand how the temperature's going to change. So I made graphs. On the x-axis is temperature. The slope of the graph, at any point, is given by \(\frac{\partial T}{\partial t}\). 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. What this means is that, to see how the system will behave, you find the current temperature (on the x-axis, remember), look at the corresponding point on the graph, and simply observe which direction it will fall.

+

As a slight digression, this was inspired by the concept of a potential plot, but it's different enough that I don't feel comfortable calling it one. The point is to get a sense for where the temperature is stable and whether it's going to be increasing or decreasing from various points. Since the temperature will always tend to fall down the graph, a stable point is horizontal.

+

Well. This is terrible, and describes why this doesn't feel fun. There are no stable points! That's not quite true - there are stable points under one condition: when the fuel flow rate is exactly 0.5. In those circumstances, the temperature always stays constant everywhere. This is no good! This means that all you have to do is raise the flow rate a little, to make the temperature roll out as far as you want it to go, and then drop it to 0.5 and it will stay exactly where you left it. BORING. Let's try some alternatives!

+\[\frac{\partial T}{\partial t} = c_R T F - c_T\]
- + +
+ + 0 degrees + No ignition + DAMAGE! +
+
+
+

This was actually the first formula I tried. Temperature always decreases by a constant rate, counterbalanced by the reaction rate (\(c_R T F\)) which is defined as before. It's got slightly better behavior - specifically, there is a stable point (the graph peaks somewhere for most flow rates), which moves around when you change the fuel flow rate.

+

On the other hand, it still has a lot of problems.

+ +

Time for another try. There are two directions we can go here - try to describe entirely new behaviors from the ground up, or try to modify the existing system. I'll give both a try, once I have spare time!

+
+
+ +
+ + +
+ + 0 degrees + No ignition + DAMAGE! +
+
+
+
+
+ +
+ +
0 degrees diff --git a/articles/dynamic_systems_in_games/engine.js b/articles/dynamic_systems_in_games/engine.js index e118118..96976a3 100644 --- a/articles/dynamic_systems_in_games/engine.js +++ b/articles/dynamic_systems_in_games/engine.js @@ -1,4 +1,3 @@ -var a=true; function engine(element, reaction_rate_function) { var e = {}; // the engine object! e.container = $(element); @@ -9,6 +8,7 @@ function engine(element, reaction_rate_function) { var old_value = this.value; this.value += reaction_rate_function(q)*timestep/1000 if (this.value < 0) { this.value = 0; } + if (old_value != this.value) { return true; } }, "out": function () { @@ -46,6 +46,7 @@ function engine(element, reaction_rate_function) { "update": function () { var old_value = this.value; this.value = parseFloat(e.container.find('[name=fuel]').val()); + if (old_value != this.value) { return true; } @@ -90,7 +91,7 @@ function engine(element, reaction_rate_function) { "value": 0.5, }; - var ghost_count = 2, ghost_separation = 0.05; + var ghost_count = 1, ghost_separation = 0.05; var ghost_data_points = Array(1 + ghost_count*2); var all_graph_data = [{"data": [], lines: {show: true}, points: {show: false}}]; @@ -109,7 +110,7 @@ function engine(element, reaction_rate_function) { colors: ['gray'], }; function generate_graph_points() { - var step_size = 0.4; + var step_size = 0.3; var flow_value = q.fuel_flow_rate.value; @@ -137,23 +138,19 @@ function engine(element, reaction_rate_function) { potentials[s] += -1 * step_size * reaction_rate_function(ghost_data_points[s]); } } - //console.log("regenerated graph"); + //console.log("regenerated graph points"); } function update_graph() { e.graph_plot.setData(all_graph_data); e.graph_plot.draw(); - if (a) { console.log(all_graph_data); a=false; } } var a, b; - var timestep=10; + var timestep = 30; e.container.ready(function () { e.graph = e.container.find('.potential_plot'); e.graph_plot = $.plot(e.graph, [[]], e.graph_config); - jQuery.each(q, function(name, x) { x.update(); }); - jQuery.each(q, function(name, x) { x.out(); }); - jQuery.each(q, function(name, x) { x.update(); }); jQuery.each(q, function(name, x) { x.out(); }); e.container.find('[name=ignition]').on('click', function() { q.temperature.value += q.ignition_boost.value; }); a = setInterval(jQuery.each, timestep, q, function(name, x) { if (x.update()) { x.out(); } });