Countless times I've implemented physics simulations using Euler integration for little toy games: press arrow key and it sets an acceleration, then integrate acceleration and add to velocity, then integrate velocity and add to position to get final position. I see this everywhere.
But when I thought about kinetic energy, I realized it's not "realistic". If given something like a car, the engine produces power (kW), not force/acceleration. With constant acceleration, the virtual engine's power increases as velocity increases. In my case it's a spaceship but I want to experiment with applying constant power in a direction instead of constant acceleration.
Is my assessment correct that tracking energy is more realistic than acceleration? If so, does it actually make more sense to keep track of energy vector instead of velocity vector? But then I have to convert to velocity to integrate. So I've done this for 1D simulation and it works, of course I can use E=0.5*m*v*v and solve for v. But what about when using vectors, where I can't take the "square root" of energy (vector). I could find the vector whose direction is the same but the magnitude is the square root of the original, but is that physically correct?
I thought surely someone must be doing this, but I've searched and searched the web and don't see it. So maybe I'm off base.
Essentially, what I want to do is take the traditional "push up arrow and spaceship accelerates at a constant acceleration" and change it into "push up arrow and spaceship gains kinetic energy at a constant rate" but handle this in a 2D case instead of a 1D case (I have 1D case working already).
Update: JavaScript code based on Exceptyon's accepted answer:
function sq(x) {
return x * x;
}
//Square cosine, preserving sign
function cos2(x) {
var ret = Math.cos(x);
if (ret >= 0) {
return sq(ret);
} else {
return -sq(ret);
}
}
//Square sine, preserving sign
function sin2(x) {
var ret = Math.sin(x);
if (ret >= 0) {
return sq(ret);
} else {
return -sq(ret);
}
}
function Ship() {
this.x = 20; //m
this.y = 40; //m
this.dx = 0; //m/s
this.dy = 0; //m/s
this.ex = 0; //J
this.ey = 0; //J
this.pangle = Math.PI / 2; //pointing angle
this.mass = 1; //kg
this.power = 200; //W
this.update = function(dt) {/*...*/} //update x/y based on dx/dy
/**
* Direct translation of Exceptyon's equations, but preserving sign in cos^2, sin^2 and sqrt
* operations.
* @param dt delta time in seconds
*/
this.speedup2 = function(dt) {
this.ex += this.power * dt * cos2(this.pangle);
this.ey += this.power * dt * -sin2(this.pangle);
var signx = this.ex > 0 ? 1 : -1;
var signy = this.ey > 0 ? 1 : -1;
this.dx = Math.sqrt(2 * Math.abs(this.ex) / this.mass) * signx;
this.dy = Math.sqrt(2 * Math.abs(this.ey) / this.mass) * signy;
};
/**
* Modified variation of Exception's post where I transform energy "vector" into velocity, that
* I believe is equivalent.
*/
this.speedup = function(dt) {
this.ex += Math.cos(this.pangle) * this.power * dt;
this.ey += -Math.sin(this.pangle) * this.power * dt;
var totalEnergy = Math.sqrt(this.ex * this.ex + this.ey * this.ey);
var speed = Math.sqrt(2 * totalEnergy / this.mass);
var ratio = speed / totalEnergy;
this.dx = this.ex * ratio;
this.dy = this.ey * ratio;
this.speed = Math.sqrt(this.dx * this.dx + this.dy * this.dy);
};
}
You can do that if you want, you just have to keep track of kinetic energy along x and y (and z if you are moving in 3d).
Ex = kinetic energy along x-axis
Ey = kinetic energy along Y-axis
//Etot = Ex + Ey
//dt = 1/fps
ofc if you don't like cartesian Ex, Ey
you could keep Etot, direction
, it's completely equivalent. conversion would be:
Ex = Etot * cos^2(direction)
Ey = Etot * sin^2(direction)
and inverse:
Etot = Ex + Ey
direction = atan2(sqrt(Ey), sqrt(Ex))
at a given frame your engine would give you Power*dt energy, that is
\delta{Ex} = Power*dt * cos^2(direction)
\delta{Ey} = Power*dt * sin^2(direction)
and from there, you should find that every frame:
//Etot = E_x + E_y
//vtot = sqrt(2*Etot/m)
v_x = sqrt(2*Ex/m) // = vtot*cos(direction)
v_y = sqrt(2*Ey/m) // = vtot*sin(direction)