繁体   English   中英

在JavaScript中向左或向右移动时如何运行动画?

[英]How do I run an animation when moving to the left or right in JavaScript?

在JavaScript中按向左或向右箭头键时如何运行Sprite动画? 这是我的代码:

var avatarX = 0;
var avatarY = 240;
var avatarImage;
var counter = 1;
var XWIDTH = 0;
var WIDTH = 400;
var dx = 5;
var tt;
var gameCanvas;
var context;
var moving;
var animationCounter = 1;

window.addEventListener('keydown', KeyDown);

function setUpGame() { //This is the function that is called from the html document.

    gameCanvas = document.getElementById("gameCanvas"); //Declare a new variable & assigns it the id of the CANVAS from the html document.
    context=gameCanvas.getContext("2d");
    context.font = "18px Iceland";
    context.textBaseline = "top";

    avatarImage = new Image(); //Declaring a new variable. This is so that we can store the image at a later date.
    avatarImage.onload=function(){

    // avatarImage is now fully loaded and ready to drawImage
        context.drawImage(avatarImage, Math.random() * 100, avatarY);

    // start the timer
        tt = setInterval(function(){counTer()},1000);
        setInterval(handleTick, 25);


    }
    avatarImage.addEventListener('load', startLoop, false);
    avatarImage.src = "img/ships.png"; //Ditto from above.

}

function startLoop() {
    console.log("Detecting whether moving to the right is: " + moving);
    if(moving == 0) {
        gameLoop();
    }
}

function gameLoop() {

    setTimeout(gameLoop, 100);
    handleTick();

}

function KeyDown(evt) {
  switch (evt.keyCode) {
  case 39: /*Arrow to the right*/
      if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
         avatarX += dx;
         moving = 0;
      }
    break;
   case 37: /*Arrow to the left*/
      if(avatarX - dx >XWIDTH) {
         avatarX -= dx;
         moving = 1;
      } 
    break;
  }
}

function counTer() {
  if(counter == 60) {
    clearInterval(tt);
  } else {
    counter++;
  }
}

function handleTick() {
    context.clearRect(0,0,gameCanvas.width,gameCanvas.height);
    context.drawImage(avatarImage, 32*animationCounter, 0, 32,32, avatarX, avatarY, 64, 64);
    context.fillText("Seconds: " + counter, 5, 5);
    context.fillText("1 is Right, 2 is Left, 0 is idle: " + moving, 20, 20);


    animationCounter++
    if(animationCounter >1) {
        animationCounter = 0;

    }
}

有很多方法可以实现动画。 我使用的一个非常简单,看起来像这样:

var player = {
    x: 0,
    y: 0,
    width: 50,
    height: 100,
    sprite: {
        column: 0,
        row: 0,
        height: 50,
        width: 100
    },
    image: PlayerImage,
    animation: {
        active: true, //Determines if the animation is running or not.
        counter: 0,
        progress: 0,
        sequence: []
    }
}

//This functions fires when the left arrow is pressed.
var onLeft = function(){
    player.animation.sequence = [{column: 0, row: 0, t: 12}, {column: 1, row: 0, t: 12}, {column: 2, row: 0, t: 12}];
    player.animation.active = true;
}

//This functions fires when the right arrow is pressed.
var onRight = function(){
    player.animation.sequence = [{column: 0, row: 1, t: 12}, {column: 1, row: 1, t: 12}, {column: 2, row: 1, t: 12}];
    player.animation.active = true;
}

//This function fires when no arrow are pressed. 
var standingStill = function(){
    player.animation.active = false;
}

var handleTick = function(){

    //Clear the canvas.
    context.canvas.width = context.canvas.width;

    //If the animation is active.
    if(player.animation.active){

        //If the counter >= tick in the sequence. If not, just keep on increasing the counter value.
        if(player.animation.counter >= player.animation.sequence[player.animation.progress]){
            player.animation.counter = 1;

            if(player.animation.progress >= player.animation.sequence.length - 1){
                player.animation.progress = 0;
            }else{
                player.animation.progress++;
            }

            var currentFrame = player.animation.sequence[player.animation.progress];

            //Change player.sprite column and row.(new frame)
            player.sprite.column = currentFrame.column;
            player.sprite.row = currentFrame.row;
        }else{
            player.animation.counter++;
        }

    }

    context.drawImage(player.image, player.sprite.column * player.sprite.width, player.sprite.row * player.sprite.height, player.sprite.width, player.sprite.height, player.x, player.y, player.width, player.height)

}

该序列是一个包含以下对象的数组: {column: 0, row: 0, t: 12}每个对象都是一个框架。 column值是子画面的当前xrow是子画面的y 该脚本会自动创建xy值,因此您只需添加0、1、3、5等值(仅在x或y轴上是哪一帧即可)。例如,如果列为0,行为0,则这是左上角的框架(第一帧)。 t值代表滴答声,它确定动画进入下一帧之前必须发生多少滴答声。

Player.sprite还具有属性widthheight ,即框架的宽度和高度,它通常与播放器对象的宽度和高度相同。

您必须在onLeftonRight函数中onLeft自己的player.animation.sequence ,以便对其进行动画处理。

我希望你明白我的意思。 这可能看起来很复杂,但实际上并非如此,如果您现在不了解它,请不用担心,您最终会得到它。 如果您确实难以理解,请提出。


编辑:首先,我强烈建议使用对象存储有关实体的信息。 它使游戏制作变得更加轻松和整洁。 只需查看player对象,只需编写player.x即可获得x, player.xPlayerX player.x得多。 它看起来也更专业。 :)而且,当您必须提供有关实体的大量信息时,不必传递许多参数,则可以传递整个对象。 例:

//Entity properties stored in separate variable.
function animate(EntityX, EntityY, EntitySpriteX, EntitySpriteY, ...){
    var x = EntityX;
    //And so on...  
}

//Entity stored in an object.
function animate(Entity){
    var x = Entity.x;
    //And so on...
}

无论如何,回到您的问题。 首先,我们必须添加变量来存储有关精灵的信息。

var avatarSpriteColumn = 0; //Sprite frame on the x axis.
var avatarSpriteRow = 0; //Sprite frame on the y axis.
var avatarSpriteWidth = 50; //The width of a frame.
var avatarSpriteHeight = 100; //The height of a frame.

我们还必须添加变量来存储有关动画的信息。

var animationActive = false; //A variable that controls if the animation is 'running'.
var animationCounter = 0; //How many frames(ticks) have passed since the last frame(animation frame) has changed. (I'm not good at describing variables. :P)
var animationProgress = 0; //Current animation frame.
var animationSequence = []; //Array that stores the sequence of animation, as i explained.

然后,在handleTick函数中,您必须添加将使Sprite动画的代码。 在绘制实体之前,您必须添加此代码。

//If the animation is active.
if(animationActive){

    //If the counter >= tick in the sequence. If not, just keep on increasing the counter value.
    if(animationCounter >= animationSequence[animationProgress]){
        animationCounter = 1;

        //Reset the progress, so that next time another animation frame shows up.
        if(animationProgress >= animationSequence.length - 1){
            animationProgress = 0;
        }else{
            animationProgress++;
        }

        //Select information about the current animation frame and store it in a variable so it is easier to access.
        var currentFrame = animationSequence[animationProgress];

        //Change player.sprite column and row.(new frame);
        avatarSpriteColumn = currentFrame.column;
        avatarSpriteRow = currentFrame.row;
    }else{
        animationCounter.counter++;
    }

}

好的,现在您有了使子画面动画的代码,但是我们如何运行它呢? 好吧,我看到您有一个名为moving的变量。 它告诉我们玩家朝哪个方向移动,以及是否根本在移动。 看来您实现了它有点错误。 现在,您操作按键的功能如下所示:

function KeyDown(evt) {
  switch (evt.keyCode) {
  case 39: /*Arrow to the right*/
      if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
         avatarX += dx;
         moving = 0;
      }
    break;
   case 37: /*Arrow to the left*/
      if(avatarX - dx >XWIDTH) {
         avatarX -= dx;
         moving = 1;
      } 
    break;
  }
}

如果实体向右移动,则该变量应返回1;如果实体向左移动,则该变量应返回2;如果实体静止不动,则该变量返回0,对吗? 现在,当实体向右移动时,它显示0;当实​​体向左​​移动时,它显示1。 它也不会显示实体是否空闲。 我们必须修复它。 将其更改为如下所示:

function KeyDown(evt) {
    switch (evt.keyCode) {
        case 39: /*Arrow to the right*/
            if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
                avatarX += dx;
                moving = 1;
            }
        break;
        case 37: /*Arrow to the left*/
            if(avatarX - dx >XWIDTH) {
                avatarX -= dx;
                moving = 2;
            } 
        break;
        default:
            moving = 0;
    }
}

好的,现在我们必须将此代码添加到handleTick函数中。 此代码启动动画并更改序列。:

if(moving == 1){ //Moving in the right direction.
    animationSequence = []; //Animation of moving in the right direction. Change the sequence to your own.
    animationActive = true; //Run the animation.
}else if(moving == 2){ //Moving to the left.
    animationSequence = []; //Animation of moving to the left. Change the sequence to your own.
    animationActive = true; //Run the animation.
}else{
    animationActive = false; //Stops the animation, but the last frame stays.

    /*

    Alternatively, if you want a separate frame or animation that is animating when the entity is standing, you run this code.

    animationSequence = []; // Your sequence. If you want a single frame, with no animation just add one frame to the sequence.
    animationActive = true;

    */
}

现在,我们要做的最后一件事是绘制实体。 您的情况如下所示:

context.drawImage(avatarImage, avatarSpriteColumn * avatarSpriteWidth, avatarSpriteRow * avatarSpriteHeight, avatarWidth, avatarHeight, avatarX, avatarY, 64, 64);

最后,您的整个代码将如下所示:

var avatarX = 0;
var avatarY = 240;
var avatarImage;
var counter = 1;
var XWIDTH = 0;
var WIDTH = 400;
var dx = 5;
var tt;
var gameCanvas;
var context;
var moving;
var animationCounter = 1;

var avatarSpriteColumn = 0; //Sprite frame on the x axis.
var avatarSpriteRow = 0; //Sprite frame on the y axis.
var avatarSpriteWidth = 50; //The width of a frame.
var avatarSpriteHeight = 100; //The height of a frame.

var animationActive = false; //A variable that controls if the animation is 'running'.
var animationCounter = 0; //How many frames(ticks) have passed since the last frame(animation frame) has changed. (I'm not good at describing variables. :P)
var animationProgress = 0; //Current animation frame.
var animationSequence = []; //Array that stores the sequence of animation, as i explained.

window.addEventListener('keydown', KeyDown);

function setUpGame() { //This is the function that is called from the html document.

    gameCanvas = document.getElementById("gameCanvas"); //Declare a new variable & assigns it the id of the CANVAS from the html document.
    context=gameCanvas.getContext("2d");
    context.font = "18px Iceland";
    context.textBaseline = "top";

    avatarImage = new Image(); //Declaring a new variable. This is so that we can store the image at a later date.
    avatarImage.onload=function(){

    // avatarImage is now fully loaded and ready to drawImage
        context.drawImage(avatarImage, Math.random() * 100, avatarY);

    // start the timer
        tt = setInterval(function(){counTer()},1000);
        setInterval(handleTick, 25);


    }
    avatarImage.addEventListener('load', startLoop, false);
    avatarImage.src = "img/ships.png"; //Ditto from above.

}

function startLoop() {
    console.log("Detecting whether moving to the right is: " + moving);
    if(moving == 0) {
        gameLoop();
    }
}

function gameLoop() {

    setTimeout(gameLoop, 100);
    handleTick();

}

function KeyDown(evt) {
    switch (evt.keyCode) {
        case 39: /*Arrow to the right*/
            if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
                avatarX += dx;
                moving = 1;
            }
        break;
        case 37: /*Arrow to the left*/
            if(avatarX - dx >XWIDTH) {
                avatarX -= dx;
                moving = 2;
            } 
        break;
        default:
            moving = 0;
    }
}

function counTer() {
  if(counter == 60) {
    clearInterval(tt);
  } else {
    counter++;
  }
}

function handleTick() {
    context.clearRect(0,0,gameCanvas.width,gameCanvas.height);

    if(moving == 1){ //Moving in the right direction.
        animationSequence = []; //Animation of moving in the right direction. Change the sequence to your own.
        animationActive = true; //Run the animation.
    }else if(moving == 2){ //Moving to the left.
        animationSequence = []; //Animation of moving to the left. Change the sequence to your own.
        animationActive = true; //Run the animation.
    }else{
        animationActive = false; //Stops the animation, but the last frame stays.

        /*

        Alternatively, if you want a separate frame or animation that is animating when the entity is standing, you run this code.

        animationSequence = []; // Your sequence. If you want a single frame, with no animation just add one frame to the sequence.
        animationActive = true;

        */
    }

    //If the animation is active.
    if(animationActive){

        //If the counter >= tick in the sequence. If not, just keep on increasing the counter value.
        if(animationCounter >= animationSequence[animationProgress]){
            animationCounter = 1;

            //Reset the progress, so that next time another animation frame shows up.
            if(animationProgress >= animationSequence.length - 1){
                animationProgress = 0;
            }else{
                animationProgress++;
            }

            //Select information about the current animation frame and store it in a variable so it is easier to access.
            var currentFrame = animationSequence[animationProgress];

            //Change player.sprite column and row.(new frame);
            avatarSpriteColumn = currentFrame.column;
            avatarSpriteRow = currentFrame.row;
        }else{
            animationCounter.counter++;
        }

    }

    context.drawImage(avatarImage, avatarSpriteColumn * avatarSpriteWidth, avatarSpriteRow * avatarSpriteHeight, avatarWidth, avatarHeight, avatarX, avatarY, 64, 64);

    context.fillText("Seconds: " + counter, 5, 5);
    context.fillText("1 is Right, 2 is Left, 0 is idle: " + moving, 20, 20);

}

您现在唯一要做的就是制作自己的animationSequences并检查其是否有效,如果您有任何问题,请告诉我。

当然,我使用的代码更加复杂,具有更多的“功能”,并且易于使用(后面的代码更加复杂),但是希望这会对您有所帮助。

我还必须为使事情看起来如此复杂(如果不是这样)感到不安。 我不好解释。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM