Search code examples
javascripttypescriptspritegame-physics

Typescript sprite animation


I am working on a small mario game.

But I can't figure out how to anime sprites. As per example, I have a running mario.gif file (mario is not runnning in the gif)

Click here for the mario picture.

The picture is 60 x 20 pixels. At the moment, this is my code.

class Character {

    public y_: number;
    public x_: number;
    public nFrames: number = 30;

    constructor(public _x: number, public _y: number) {
        this._x = _x;
        this._y = _y;
    };

 sprite: HTMLImageElement;

    setSpriteUrl(input: string) : void {
        this.sprite = new Image();
        this.sprite.src = input;
    }

drawSprite(): void {
        ctx.save();
        ctx.beginPath();
        ctx.drawImage(this.sprite, 0, 0, 15, 20, this._x, this._y, 20, 20);
            ctx.restore;
      }
}

and after that

var mario = new Character(40, 50);
mario.setSpriteUrl("graphics/mario/small/Running-mario.gif");

the width of the picture is 60 pixels and there are 4 running images of mario. The height of the picture is also 20 pixels.
60/4 = 15.

ctx.drawImage(this.sprite, 0, 0, 15, 20, this._x, this._y, 20, 20);

This would make me think that it I can go from 15 to 30 and it would select the next mario image. Instead it gives me 2 running mario's from the picture.
How does it work? How can select every running stage of mario?


If that is done, should the sprite be animated with a for loop and a timer to do that? To me it doesn't seem like the best practice.. Since I have more sprites to animate then only mario and running.


Solution

  •     class Character {
    
        frameWidth: number;
        frameHeight: number; 
        tickCount: number;
        ticksPerFrame: number = 1;
        frameIndex: number;
        jump: boolean;
    
        constructor(public position: Vector, public numberOfFrames : number) {}
    
        sprite: HTMLImageElement;
    
    
        setSpriteUrl(input: string) : void {
            this.sprite = new Image();
            this.sprite.src = input;
        }
    
        addGravity(): void {
    
            this.position.y += downForce;
            if (this.position.y >= 415)
                this.position.y = 415;
        }
    
        drawSprite(): void {
    
            this.tickCount = this.ticksPerFrame;
    
            if (this.tickCount >= this.ticksPerFrame) {
                this.tickCount = 0;
                if (this.frameIndex < this.numberOfFrames - 1) {
                    this.frameIndex += 1;
                } else {
                    this.frameIndex = 0;
                }
            }
    
            this.frameHeight = this.sprite.height;
            this.frameWidth = this.sprite.width / this.numberOfFrames;
    
            this.position.setWidth(this.frameWidth);
            this.position.getHeight(this.frameHeight);
            ctx.drawImage(this.sprite,
                this.frameIndex * this.frameWidth, 0,   // Start of slice
                this.frameWidth, this.frameHeight, // Size of slice
                this.position.x, this.position.y, 15, 20);
        }
    
    }
    

    By using sprite this.sprite.height and this.sprite.width I can have the size dynamic. This way I can load any sprite.

    And Setting Mario

    var mario = new Character(new Vector(40,50), 4);
    mario.setSpriteUrl("graphics/mario/small/Standing-mario.gif");
    mario.numberOfFrames = 1;
    

    numberOfFrames is in this case only 1. Since the standing mario gif has only 1 picture in it.

    But if Mario is running.

        function keyboardInput(event: KeyboardEvent) {
    
    
        switch (event.keyCode) {
            case 65: case 37: //a
                mario.setSpriteUrl("graphics/mario/small/Running-mario-left.gif");
                mario.numberOfFrames = 4;
                mario.position.x -= 10;
                break;
    
            case 38: case 87: //w
                mario.numberOfFrames = 1;
                mario.setSpriteUrl("graphics/mario/small/Jumping-mario.gif");
                if(mario.position.y < 415) {
                    return false;
                }
                mario.position.y -= 30;
                break;
            case 39: case 68: //d
                mario.setSpriteUrl("graphics/mario/small/Running-mario.gif");
                mario.numberOfFrames = 4;
                mario.position.x += 10;
                break;
            case 40: case 83: //s
                mario.position.y += 20;
                break;
            case 32: //space
                break;
            default:
                mario.setSpriteUrl("graphics/mario/small/Standing-mario.gif");
                mario.numberOfFrames = 1;
                break;      
        }
    
    }
    

    If Mario is running, another number of frames is used. Running mario has 4 images inside the gif. Making the numberOfFrames 4.