Thursday, September 16, 2010

Tutorial: Simple game with HTML5 Canvas - part 3

Tutorial: Simple game with HTML5 Canvas
Part 1 - Introduction & Background
Part 2 - Character & Animation
Part 3 - Physics & Controls
Part 4 - Platforms & Collisions
Part 5 - Scrolling & Game States

Part 3a. PHYSICS
Because physics in StH is very simple, there is no need to include any Physics Engine such as Box2d. Jumping is so uncomplicated that it is possible to implement it just in few code lines.
Let's divide it into two unrelated parts - jumping and falling. When object start to jump, it has some initial velocity, deceased by gravity. It phase ends when that velocity is completely reduced and gravity starts to attract object down with increasing force. That is the second part of the jump - falling. To teach angel how to behave in such situations, let's expand player object with few more attributes:
var player = new (function(){
var that = this;
that.image = new Image();
(...)

//new attributes
that.isJumping = false;
that.isFalling = false;
//state of the object described by bool variables - is it rising or falling?

that.jumpSpeed = 0;
that.fallSpeed = 0;
//each - jumping & falling should have its speed values

(...) //rest of the code
})();
Now lets introduce methods responsible for jumping. Further expanding of player object:
that.jump = function() {
//initiation of the jump
if (!that.isJumping && !that.isFalling) {
//if objects isn't currently jumping or falling (preventing of 'double jumps', or bouncing from the air
that.fallSpeed = 0;
that.isJumping = true;
that.jumpSpeed = 17;
// initial velocity
}
}

that.checkJump = function() {
//when 'jumping' action was initiated by jump() method, initiative is taken by this one.
that.setPosition(that.X, that.Y - that.jumpSpeed);
//move object by number of pixels equal to current value of 'jumpSpeed'
that.jumpSpeed--;
//and decease it (simulation of gravity)
if (that.jumpSpeed == 0) {
//start to falling, similar to jump() function
that.isJumping = false;
that.isFalling = true;
that.fallSpeed = 1;
}

}

that.checkFall = function(){
//same situation as in checkJump()
if (that.Y < height - that.height) {
//check if the object meets the bottom of the screen, if not just change the position and increase fallSpeed (simulation of gravity acceleration)...
that.setPosition(that.X, that.Y + that.fallSpeed);
that.fallSpeed++;
} else {
//..if yes - bounce
that.fallStop();
}
}

that.fallStop = function(){
//stop falling, start jumping again
that.isFalling = false;
that.fallSpeed = 0;
that.jump();    
}
It's necessarily to update main loop function to redraw player's position while jumping and falling. Update GameLoop() with this code, just before drawing the character:
if (player.isJumping) player.checkJump();
if (player.isFalling) player.checkFall();
I think above code is clear enough to understand. Last action we have to take with all that physics stuff is simply initiation of the first jump, right after placing player on the stage.
player.setPosition(~~((width-player.width)/2), ~~((height - player.height)/2));
player.jump(); //here
Ok, it's jumping beautifully, piece of awesome pseudo-physics code. Now let's make some controls. Part 3b. CONTROLLS Main character of StH can move sideways only. It jumps automatically, up/down movement depends of platforms. User can only command angel to move left or right. One more time it could be achieved by with extension player object with additional methods.
var player = new(function(){
(...)
that.moveLeft = function(){
if (that.X > 0) {
//check whether the object is inside the screen
that.setPosition(that.X - 5, that.Y);
}
}

that.moveRight = function(){
if (that.X + that.width < width) {
//check whether the object is inside the screen
that.setPosition(that.X + 5, that.Y);
}
}
(...)
})();
Now bind that functions to the mouse pointer position (angel will follow it).
document.onmousemove = function(e){
if (player.X + c.offsetLeft > e.pageX) {
//if mouse is on the left side of the player.
player.moveLeft();
} else if (player.X + c.offsetLeft < e.pageX) {
//or on right?
player.moveRight();
}
}
It's everything for today. In next episode I will introduce platform drawing and collisions. As usual: [demo with jumping & controls] [source in GitHub repo]

Tutorial: Simple game with HTML5 Canvas
Part 1 - Introduction & Background
Part 2 - Character & Animation
Part 3 - Physics & Controls
Part 4 - Platforms & Collisions
Part 5 - Scrolling & Game States

21 comments:

  1. There is a shorter solution for the mouse controlling. Instead of moving the player 5px every loop (which can cause some delay if you move fast), you update the players x-position directly (this is the only piece of code you will need to get mouse controlling work):

    document.onmousemove = function(e) {
    if(e.pageX > 0 && e.pageX + player.width < width) {
    player.X = e.pageX;
    }
    };

    ReplyDelete
  2. i don't get why you would want a laggy moveLeft & moveRight function assigned to onmousemove instead of something as simple as:

    document.onmousemove = function(e){
    player.x = e.pageX - c.offsetLeft - player.x / 2;
    }

    ?

    ReplyDelete
  3. That's the porper way to write games - you update informations during the frames only. It doesn't really matter in tiny projects like this one, but there are always some design patters you should learn about since the very beginning.

    ReplyDelete
  4. could you please allow me to use this game in my facebook application

    ReplyDelete
  5. sure, use it, just link to the tutorial or my twitter and give me the link when you will finish it.

    ReplyDelete
  6. Thanks .. here is the link of the app http://apps.facebook.com/jumpingangel/ i have written your name and link to your blog on the front page thanks again

    ReplyDelete
  7. I understand the pattern you mentioned as response to awef idea, but in your code you do not follow it. You simply attach left and right move to mousemove event.

    gorn (PS: openid login failed)

    ReplyDelete
  8. haha, you are right, I'm not sure why it looks like this. I will fix it in my free time, thanks for catching it.

    ReplyDelete
  9. I realize your pattern anyone mentioned since a reaction to awef idea.

    ReplyDelete
  10. don´t be such a häusel

    ReplyDelete
  11. followed fine up to creating the new functions. now sure where to put those. tried before and after player function, but everything stops working no matter where I put them.

    ReplyDelete
    Replies
    1. Oh- duh. those are methods that are part of the player. They are IN the player construct - not outside it.

      Delete
    2. Should the jump function come before or after the draw function?

      Delete
  12. Thanks for the great tutorial :D
    As a short note, I tested this on an Android app browser (Chrome) and notices that the mouse part doesn't trigger, causing the character to stay in the same position forever. Probably the document.onmousemove function doesn't translate well on touchpad devices.

    ReplyDelete
  13. I'm trying to figure out a way to call the functions using the arrows on the keyboard. I manage to figure out one way, but that only worked in Firefox and Safari, and it really didn't work that well either.

    ReplyDelete
  14. is it possible to make the player control the character with the arrow keys? and if so how would the code look?

    ReplyDelete