簡體   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