打字稿精灵动画

Typescript sprite animation

我正在开发一款小型马里奥游戏。

但我不知道如何制作精灵动画。根据示例,我有一个 运行 mario.gif 文件(gif 中没有运行马里奥)

Click here for the mario picture.

图片为 60 x 20 像素。 目前,这是我的代码。

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;
      }
}

之后

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

图片宽度为60像素,有4张运行马里奥图片。图片的高度也是20像素。
60/4 = 15。

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

这会让我觉得我可以从 15 到 30,它会 select 下一张马里奥图像。相反,它给了我 2 运行 图片中的马里奥。
它是如何工作的? select 马里奥的每个 运行 阶段如何?


如果这样做了,精灵是否应该用 for 循环和计时器来做动画?对我来说,这似乎不是最好的做法。因为我有更多的精灵要制作动画,所以只有马里奥和 运行.

drawImage的签名是

ctx.drawImage(image, dx, dy)
ctx.drawImage(image, dx, dy, dWidth, dHeight)
ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy)
ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)

(sx, sy)是源图像中切片的起始位置,从这里开始复制。 (sWidth × sHeight) 是该切片的大小。

由于您的 sprite 帧是水平方向的,您需要增加 sx 的值来绘制下一帧。

class Character {

    frameWidth: number = 15;
    frameHeight: number = 20;

    constructor(
        public x: number,
        public y: number) { }

    sprite: HTMLImageElement;

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

    drawSprite(frameIndex: number): void {
        ctx.save();
        ctx.beginPath();
        ctx.drawImage(this.sprite,
            frameIndex * this.frameWidth, 0,   // Start of slice
            this.frameWidth, this.frameHeight, // Size of slice
            this.x, this.y);                   // Destination position
        ctx.restore();
    }
}
    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);
    }

}

通过使用 sprite this.sprite.heightthis.sprite.width 我可以动态调整大小。这样我就可以加载任何精灵。

和设置马里奥

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

numberOfFrames 在这种情况下只有 1。因为站立的马里奥 gif 中只有 1 张图片。

但是如果马里奥是运行。

    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;      
    }

}

如果马里奥是运行,则使用另一个帧数。 运行 mario 在 gif 中有 4 张图像。制作 numberOfFrames 4.