How to do simple physics
Games often need simple Newtonian physics to make things move in a believable manner. That basically means, objects have inertia and tend to stay in motion once they're in motion, affected by forces like gravity. Examples include the ship and rocks in Asteroids, the projectiles in any artillery game, and even the characters in a platformer.
Fortunately, simple physics are easy to do! The key concept is: in addition to the object's position, you must also keep track of its velocity. This is normally done by adding two new properties, vx
and vy
, to your object.
- vx is the object's horizontal velocity: how much its x position changes per second.
- vy is the object's vertical velocity: how much its y position changes per second.
If we were updating the position of our object once per second, we could just add vx
to its x
position, and vy
to its y
position. But usually we're updating the screen much faster than that (typically 60 frames per second). The time step (usually called dt
) is much smaller than 1 second, so the object won't move as far on each step. We accomplish this by simply multiplying vx
and vy
by dt
, before adding them to x
and y
.
Example
The code below loads a sprite in the center of the screen, initially stationary. Then it falls due to gravity, until it hits the bottom of the screen.
clear
gravity = 100 // acceleration, in pixels/sec^2
obj = new Sprite
obj.image = file.loadImage("/sys/pics/Block.png")
display(4).sprites.push obj
obj.x = 480
obj.y = 320
obj.vx = 0
obj.vy = 0
obj.update = function(dt=0.016)
// update velocity (applying gravity)
self.vy = self.vy - gravity * dt
// update position (applying velocity)
self.x = self.x + self.vx * dt
self.y = self.y + self.vy * dt
// apply any limits, collision checks, etc.
if self.y < 32 then
self.y = 32
self.vy = 0
self.vx = floor(self.vx / 2)
end if
end function
while true // press control-C to exit
obj.update
yield
end while
Things to try:
- Change the initial values of
vx
andvy
to something other than zero. What happens? - When
self.y < 32
(the object hits the ground), instead of settingself.vy
to zero, what if you set it toabs(self.vy)
(i.e. make it positive)? - Try adding a thruster you can control, by adding this to the "update velocity" section:
if key.pressed("space") then self.vy = self.vy + 500*dt