如何在JavaScript中使用setInterval循环时让精灵停止移动

问题描述 投票:0回答:3

我正在尝试使用我用模因制作的精灵为我的朋友制作游戏。我决定使用无限循环来有效地运行我的代码,但我不知道如何使用keyup事件监听器来阻止精灵移动,因为当我按下箭头键时,精灵将继续永远移动。我该如何解决?另外,当我按住键时,如何使精灵移动,而不是在主要问题修复后单独按下它? (注意:精灵过渡不是问题,我想首先让运动失效。)

// setting up basic canvas
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext('2d');

// defining images and sources for each one
let petscop = new Image();
petscop.src = "https://raw.githubusercontent.com/swedishF1sh/PETSCOP2p/master/petscop-fromside-1.png.png";
let petscop2 = new Image();
petscop2.src = "https://raw.githubusercontent.com/swedishF1sh/PETSCOP2p/master/petscop-fromside-2.png.png";
let petscop3 = new Image();
petscop3.src = "https://raw.githubusercontent.com/swedishF1sh/PETSCOP2p/master/petscop-fromside-3.png.png";
let background1 = new Image();
background1.src = "https://raw.githubusercontent.com/swedishF1sh/PETSCOP2p/master/petscop-background.png"
// setting up the direction variable

let d;

document.addEventListener("keydown", direction);

function direction(event) {
  let key = event.keyCode;
  if (key == 37) {
    d = "RIGHT";
  } else if (key == 38) {
    d = "DOWN";
  } else if (key == 39) {
    d = "LEFT";
  } else if (key == 40) {
    d = "UP";
  }
}

// length & width of one box, in half. (regular as 32)
let halfbox = 16;

// organizing the frames for the current character
let currentframe = petscop;

let frames = {
  front: petscop,
  frontblink: petscop2,
  back: petscop3
}

let petscopsize = {
  height: petscop.height,
  width: petscop.width
}

// setting up the character position
let characterpos = {
  x: halfbox*13,
  y: halfbox*10,
}


// setting up the main function which the game will run on.
function draw() {
  
  currentframe.width = petscop.width;
  currentframe.height = petscop.height;
  ctx.drawImage(background1, 0, 0);
  ctx.drawImage(currentframe, characterpos.x, characterpos.y);
  if (d == "LEFT")  {
    characterpos.x += halfbox;
    currentframe = petscop;
  } else if (d == "UP") {
    characterpos.y += halfbox;
    currentframe = petscop;
  } else if (d == "RIGHT") {
    characterpos.x -= halfbox;
    currentframe = petscop;
  } else if (d == "DOWN") {
    characterpos.y -= halfbox;
    currentframe = petscop3;
  }
}
setInterval(draw, 50);
#canvas {
  border: 5px;
  background-color: white;
}

.canvas-container {
  margin-left: 25%;
}

body {
  background-color: rgb(255, 255, 255);
  // gray: 40, 68, 68
  // white: 255, 255, 255
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>repl.it</title>
    <link href="style.css" rel="stylesheet" type="text/css" />
  </head>
  <body>
    <div class="canvas-container">
      <canvas id="canvas" height="512" width="862"></canvas>
    </div>
    <script src="script.js"></script>
  </body>
</html>

当我停止按住键时,我希望最终结果停止移动。

javascript 2d-games
3个回答
0
投票

而不是setInterval(draw, 50);使用var loop = setInterval(draw, 50);然后当你想要它停止时,使用clearInterval(loop);


0
投票

document.addEventListener("keyup", () => d = null);

一旦松开按钮,这应该禁用运动。


0
投票

这两个答案似乎都没有多大帮助。

动画循环

你是对的,无限循环是处理游戏动画的最佳方式。

但是不要使用setInverval,使用requestAnimationFrame来创建游戏循环。

您的间隔为50毫秒,即20fps(每秒帧数)。 requestAnimationFrame将尝试以60fps运行,你无法改变。但是你可以跳过3帧中的每2帧获得20fps。

该片段显示了使用requestAnimationFrame和可调节帧速率的基本游戏循环。

const frameRate = 20; // only works for frame rates 60,30,20,15,12,10,6,5,4,3,2,1 per second
var frameCount = 0; // counts requested frames @60fps

requestAnimationFrame(gameLoop); // this will start the game loop
function gameLoop(time) { // time is passed to this function by requestAnimationFrame
    if ((frameCount++) % (60 / frameRate)) {
        draw(); // calls your game code
    }

    // Request the next frame
    requestAnimationFrame(gameLoop);
}

键盘

要处理键盘输入,您需要同时收听按键事件和按键事件。

流动的代码片段是一个简单的键盘状态管理器,可以维护您感兴趣的键的状态。

您可以在KeyboardEvent.code找到关键代码

const keys = {  // Name of keys code you want to use
    ArrowUp: false,  // set to off at start
    ArrowDown: false,
    ArrowLeft: false,
    ArrowRight: false,
};
// the event listener
function keyEvent(event) {
    if (keys[event.code] !== undefined) { // is this a key we are using?
        keys[event.code] = event.type === "keydown"; // set true if down false if up
        event.preventDefault(); // stops default action (eg scrolling page)
    }
}
// Add the key events to the window object (window is the default object 
// so dont need to name it)
addEventListener("keyup", keyEvent);
addEventListener("keydown", keyEvent);

现在,您只需更改游戏代码,即可在按键关闭时移动角色。

BTW最好移动精灵然后绘制精灵,而不是绘制然后移动。这减少了用户输入和视觉反馈之间的延迟。

function draw() {
    ctx.drawImage(background1, 0, 0);
    currentframe = petscop;

    if (keys.ArrowLeft) {
       characterpos.x += halfbox;
    }
    if (keys.ArrowRight) {
       characterpos.x -= halfbox;
    }
    if (keys.ArrowUp) {
       characterpos.y += halfbox;
    }
    if (keys.ArrowDown) {
       characterpos.y -= halfbox;
       currentframe = petscop3;
    }
    ctx.drawImage(currentframe, characterpos.x, characterpos.y);
 }

该片段将所有内容整合在一起。

我认为你把你的键映射放回到前面,我把它留下了,因为你的代码似乎暗示左移动,向上移动等等。

我还更改了图像的加载方式,并创建了一个角色对象。

希望它有所帮助而且不会迟到(我刚刚注意到问题日期)。

const frameRate = 20; // only rates 60,30,20,15,12,10,6,5,4,3,2,1 per second
var frameCount = 0; 

const cvs = document.getElementById("canvas");
const ctx = cvs.getContext('2d');
ctx.fillStyle = "#09F";
ctx.textAlign = "center";
ctx.fillText("loading...", cvs.width / 2, cvs.height / 2);

const imgLocation = "https://raw.githubusercontent.com/swedishF1sh/PETSCOP2p/master/petscop-";
const images = {
    forward: "fromside-1.png.png",
    backward: "fromside-3.png.png",
    blink: "fromside-2.png.png",
    background: "background.png",
};

function loadImages(imageList, onAllLoaded) {
    var count = 0;
    for(const name of Object.keys(imageList)) {
        const img = new Image;
        count ++;
        img.src = imgLocation + imageList[name];
        img.onload = () => {
            imageList[name] = img;
            img.onload = null;
            count --;
            if (count === 0 && onAllLoaded) { onAllLoaded() }
        }
    }
}
// loads images and start main loop when all loaded
loadImages(images,() =>requestAnimationFrame(gameLoop));

const keys = { // codes @ https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code
    ArrowUp: false,  
    ArrowDown: false,
    ArrowLeft: false,
    ArrowRight: false,
};
function keyEvent(event) {
    if (keys[event.code] !== undefined) { 
        keys[event.code] = event.type === "keydown";
        event.preventDefault(); 
    }
}
addEventListener("keyup", keyEvent);
addEventListener("keydown", keyEvent);
focus(); // for SO snippet to get keyboard events without clicking first


const halfbox = 16;
const blinkOdds = 1/100; // odds of blinking. 1/100 @ 20fps average blink time is 5 seconds
const character = {
    x: halfbox * 13,
    y: halfbox * 10,
    image: null,
    draw() {
        ctx.drawImage(this.image, this.x, this.y);
    },
    move() {
        this.image = Math.random() < blinkOdds ? images.blink : images.forward;
        if (keys.ArrowLeft) {
           this.x += halfbox;
        }
        if (keys.ArrowRight) {
           this.x -= halfbox;
        }
        if (keys.ArrowUp) {
           this.y += halfbox;
        }
        if (keys.ArrowDown) {
           this.y -= halfbox;
           this.image = images.backward;
        }
    },
}

function draw() {  
    ctx.drawImage(images.background, 0, 0);
    character.move();
    character.draw();
}

function gameLoop(time) {
    if ((frameCount++) % (60 / frameRate)) {
        draw();
    }
    requestAnimationFrame(gameLoop);
}
#canvas {
  border: 5px;
  background-color: white;
}

.canvas-container {
  margin-left: 25%;
}

body {
  background-color: rgb(255, 255, 255);
}
<div class="canvas-container">
  <canvas id="canvas" height="512" width="862"></canvas>
</div>
© www.soinside.com 2019 - 2024. All rights reserved.