How to do simple physics

From MiniScript Wiki
Revision as of 20:46, 4 May 2020 by JoeStrout (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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:

  1. Change the initial values of vx and vy to something other than zero. What happens?
  2. When self.y < 32 (the object hits the ground), instead of setting self.vy to zero, what if you set it to abs(self.vy) (i.e. make it positive)?
  3. 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


For another example, see the flappyBat demo in /sys/demo/.