So in developing a new system of sprite movement, I decided to try a little bit of really basic physics. Adding a few simple members to the sprite class to store values relating to velocity, momentum & friction:
Protected objVelocity As Vector2 Protected sngFriction, sngMass AsSingle
and then, adding method called ApplyForce:
PublicSub ApplyForce(ByVal force As Vector2)
IfMe.sngMass > 0 Then Me.objVelocity += (force / Me.sngMass) Else Me.objVelocity += force EndIf
EndSub
and finally, processing this information during update:
PublicSub UpdatePhysics()
Dim time AsSingle Dim negX, negY AsBoolean
'Our unit of measure is pixles per second time = Me.Game.GameTime.ElapsedGameTime.TotalMilliseconds / 1000
'If there is any velocity...
IfMe.objVelocity <> Vector2.Zero Then
'before we apply friction, let's remember whether 'or not we started out with positive or negative 'velocity value, for both x and y, by setting '"wasNegativeX/Y" booleans
'simulate some psuedo-friction by normalizing the 'velocity vector and multiplying it by the friction 'value. This gives us an amount to "push" the object 'in the exact opposite direction. Multiplied by 'time to do just enough for this frame only. Subtract 'the result from the object's velocity, to slow it down.
Me.objVelocity -= (Vector2.Normalize(Me.objVelocity) * Me.sngFriction) * time
'Because friction is simulated by pushing the object in 'the opposite direction, towards the end when the object 'is almost stopped we don't want the psuedo-friction to 'start pushing the object backwards; at most, friction 'stops something, but it shouldn't ever move it. So using 'or cached "whether or not it was negative" booleans, 'check to see if the polarity of our X/Y velocity changed 'due to friction. If it did, snap the velocity of that 'value to 0.
If (negX AndMe.objVelocity.X > 0) Or (Not negX AndMe.objVelocity.X < 0) Then Me.objVelocity.X = 0 EndIf
If (negY AndMe.objVelocity.Y > 0) Or (Not negY AndMe.objVelocity.Y < 0) Then Me.objVelocity.Y = 0 EndIf
'increment the object's position by the amount of 'velocity appropriate for this frame by multiplying 'by the time value.
Me.Position += (Me.objVelocity * time)
EndIf
EndSub
I haven't really discussed my existing system for movement on the blog yet; we'll get to that eventually, but I was amused by this velocity/friction/mass approach and it's probably more relevant to the needs of gaming anyway.
This is far from an actual simulator, I'm only using mass to resist initial force and not really applying it to friction but that's ok. This is supposed to be simple, and the results aren't too shabby.
In the video, just the new "physics" values introduced are being used to move the spaceship around. While the player holds down the thrust key, the current orientation of the ship * some thrust value determines a parameter for ApplyForce. Using a PlayerShip game object (as described in previous tutorials, it just inherits from sprite), I created a ThrusterOn method. As long as the user holds the truster key down, I call PlayerShip.ThrusterOn
PublicSub ThrusterOn()
Dim time AsSingle
time = Me.Game.GameTime.ElapsedGameTime.TotalMilliseconds / 1000
The ship has a little mass to it, so it resists force somewhat (this gives you a way to tweak acceleration curve vs. thruster power), and the ship's psuedo-friction value constantly pulls it's velocity toward zero. This example was built using my "real" 2D engine (which is a little further along than what the blog has covered so far, i.e. there's keyboard handling & debugging & screen management, etc.), but the movement you see is achieved through the simple additions described above.
0 comments: