Saturday, September 11, 2010

Tutorial: Simple game with HTML5 Canvas - part 2

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 2. CHARACTER
It is time now to add main character to the awesome background created in the last part. In StH it was cute little angel with simple wing flapping animation in just two frames, saved in .png with transparent background. Exactly like this one:
Let's create object representing main character with all necessarily methods and attributes. I will call it 'player'. The way of creating objects I present here is not the best one, all the attributes are visible from outside the object, there is no privacy at all. But that was simplest and shortest solution I was able to implement to fit 10KB, and most importantly - it works. If you want to know how to define proper objects with private attributes, inheritance, etc. read about Javascript Closures. Also it's important to remember, when you want to shrink your code with tools like Closure Compiler, that names of object's arguments won't change. That why in original code I use 2 letters shortcuts for describing player object, like 'player.im' instead of 'player.image', etc. SO, the object:
var player = new (function(){
//create new object based on function and assign 
//what it returns to the 'player' variable

    var that = this;
//'that' will be the context now

//attributes
    that.image = new Image();
    that.image.src = "angel.png";
//create new Image and set it's source to the 
//'angel.png' image I upload above

    that.width = 65;
//width of the single frame
    that.height = 95;
//height of the single frame

    that.X = 0;
    that.Y = 0;
//X&Y position

//methods 
    that.setPosition = function(x, y){
    that.X = x;
    that.Y = y;
}

    that.draw = function(){
        try {
            ctx.drawImage(that.image, 0, 0, that.width, that.height, that.X, that.Y, that.width, that.height);
//cutting source image and pasting it into destination one, drawImage(Image Object, source X, source Y, source Width, source Height, destination X (X position), destination Y (Y position), Destination width, Destination height)
        } catch (e) {
//sometimes, if character's image is too big and will not load until the drawing of the first frame, Javascript will throws error and stop executing everything. To avoid this we have to catch an error and retry painting in another frame. It is invisible for the user with 50 frames per second.
        }
    }
})();
//we immediately execute the function above and 
//assign its result to the 'player' variable
//as a new object 

player.setPosition(~~((width-player.width)/2),  ~~((height - player.height)/2));
//our character is ready, let's move it 
//to the center of the screen,
//'~~' returns nearest lower integer from
//given float, equivalent of Math.floor()
Ok, so now the angel needs to be redrawn on each frame. GameLoop() will be updated with player.draw() function:
var GameLoop = function(){
    clear();
    MoveCircles(5);
    DrawCircles();
    player.draw();
    gLoop = setTimeout(GameLoop, 1000 / 50);
}
But what about animation? Angel sprite has 2 frames, but only one is redrawn on each frame. To make an animation, our player needs additional attributes and a little changes in draw() method.
var player = new (function(){
(...)
    that.frames = 1;
//number of frames indexed from zero
    that.actualFrame = 0;
//start from which frame
    that.interval = 0;
//we don't need to switch animation frame
//on each game loop, interval will helps
//with this.

    that.draw = function(){
        try {
            ctx.drawImage(that.image, 0, that.height * that.actualFrame, that.width, that.height, that.X, that.Y, that.width, that.height);
//3rd agument needs to be multiplied by number of frames, so on each loop different frame will be cut from the source image
        } catch (e) {};

        if (that.interval == 4 ) {
            if (that.actualFrame == that.frames) {
                that.actualFrame = 0;
            } else {
                that.actualFrame++;
            }
            that.interval = 0;
        }
    that.interval++;
//all that logic above just
//switch frames every 4 loops  
    }
})();
Thanks for your attention. As usual, you can find final result in here: [Simple game with HTML5 Canvas] and all the sources on my Github account: [MichalBe].

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

17 comments:

  1. great tutorial, thanks!

    ReplyDelete
  2. what is this? '~~' , Yeah equivalent Math.floor()
    but what is?¿?

    ReplyDelete
  3. hm, changing this.width = 32 (in my case) makes my canvas width change in 32, even if i'm calling this 32 from players object. any ideas?

    ReplyDelete
  4. I completely don't understand what do you mean:).

    ReplyDelete
  5. var that = this;
    //'that' will be the context now

    can you please explain why this statement is necessary?

    ReplyDelete
    Replies
    1. But surely, because we are using the 'new' keyword, 'this' refers the the current object (or instance, if you want to give it that name).

      Delete
    2. This comment has been removed by the author.

      Delete
  6. I changed 'that' to 'this' and everything worked. However, later in the tutorial, 'this' is referenced inside of forEach iterators and when that happens, you're generally getting the wrong 'this'. Renaming 'this' to 'that' or extracting the data you need before the iterator resolves this issue.

    ReplyDelete
  7. Maybe a dumb question but... how do you get the angel.png image? I am using JSBin, can I upload it there? Thanks (I'm a newb btw)

    ReplyDelete
  8. Please suggest the way how to make this angle like image ...i am a new bie please help

    ReplyDelete
  9. Thanks for sharing this informative information...You may also refer....
    How to migrate from a typical HTML4 page to a typical HTML5 page.
    www.s4techno.com/blog/2016/08/30/html5-migration/

    ReplyDelete