Tuesday, 24 May 2011

Simple Game Physics

Even the simplest physics can make a game look and feel so much better. Instead of just suddenly moving full speed to the right when you press right key, it can be that the character builds speed until they reach normal speed. It could be a case of only taking 1-2 seconds to build the speed, or it could take more like 10 seconds.
It all depends on your game.

And there's gravity. There needs to be a fairly realistic rate of falling towards the ground. I don't mean close to earth's gravity, I just mean it can't just fall at a constant speed towards the ground. It needs to accelerate. (Although, this does depend on the game. There may be certain instances where a constant velocity is fine, but in most cases, it will need some sort of acceleration)

That's the simple physics. I'll go into the more complicated stuff in a later post. So let's start with a canvas of width 500x500. So that there will be room to move, to appreciate the physics a bit more.
<canvas id="canvas" width="500" height="500" style="background-color: #A9A9A9;">
Browser not compatible with HTML5 canvas
</canvas>
Now here's the javascript:
const FPS = 30;

var playerPosX = 0;
var playerPosY = 0;
var playerVelX = 0;
var playerVelY = 0;

var onGround = 0;

var playerImg = new Image();
playerImg.src = "http://i.imgur.com/nEYjaIe.png";

var canvas = null;
var context2D = null;
var keys = new Array();

window.onload = init;

window.addEventListener('keydown',keyDown,true);
window.addEventListener('keyup',keyUp,true);
function keyDown(evt){
 keys[evt.keyCode] = true;
}
function keyUp(evt){
 keys[evt.keyCode] = false;
}

function init()
{
 canvas = document.getElementById('canvas');
 context2D = canvas.getContext('2d');
 setInterval(draw, 1000 / FPS);
}

function draw()
{
 // detect user input
 if ((37 in keys && keys[37]) || (65 in keys && keys[65])){ //left
  playerVelX -= 3;
 }
 if ((39 in keys && keys[39]) || (68 in keys && keys[68])){ //right
  playerVelX += 3;
 }
 if ((38 in keys && keys[38]) || (87 in keys && keys[87])){ //up
  jump();
 }
 
 addPhysics();
 
 context2D.clearRect(0, 0, canvas.width, canvas.height);
 context2D.drawImage(playerImg, playerPosX, playerPosY);
}

function jump() {
 if (onGround == 1) {
  playerVelY -= 30;
 }
}

function addPhysics() {

 // because of these two lines, motion can be set using velocity variables
 playerPosX += playerVelX;
 playerPosY += playerVelY;
 
 
if (playerPosY > canvas.height-playerImg.height) {
 onGround = 1;
}
else {
 onGround = 0;
}

// stop character from building up too much speed
// this means the character can realistically accelerate and continue at normal speed
 if (playerVelX >= 10) {
  playerVelX = 10;
 } else if (playerVelX <= -10) {
  playerVelX = -10;
 }
 
// friction
playerVelX *= 0.85;
if (playerVelX < 0.2 && playerVelX > -0.2)
{ // so that it leaves it as a clean zero when it gets to a stop.
 playerVelX = 0;
}

 // gravity (acceleration of the velocity towards the ground)
 if (onGround == 0) {
 playerVelY += 3;
 }
 else {
 playerVelY = 0; // when on ground, gravity doesn't pull you through the floor
 }
 
}

This is correct for the sake of physics, however it is not correctly structured. What I'd like you to do is use your knowledge from this, and from the Game Loop Article to make a properly structured simple game with physics.
If you can do that, then you are on the right track.

I think my next physics post will be on making an object rotate properly when it hits the ground, so that it will land in a realistic manner. (like a box hitting the ground if it's rotated a bit)