简体   繁体   English

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

[英]How to get a sprite to stop moving while using a setInterval loop in JavaScript

I'm trying to make a game for my friend using sprites i made from a meme. 我正在尝试使用由模因制作的精灵为我的朋友制作游戏。 I decided to use an infinite loop to efficiently run my code, but i am not sure how to use the keyup event listener to stop the sprite from moving because when i press on arrow key, the sprite will continue to move forever. 我决定使用一个无限循环来有效地运行我的代码,但是我不确定如何使用keyup事件侦听器阻止小精灵移动,因为当我按箭头键时,小精灵将永远移动。 How do i fix this? 我该如何解决? Also, how do i make it so that the sprite moves when i hold down the key, rather than pressing it individually after the main problem is fixed? 另外,当我按住键时,如何使子画面移动,而不是在解决主要问题后单独按下它? (Note: the sprite transitions are not an issue, i want to get the movement down first.) (注意:精灵转换不是问题,我想先降低运动速度。)

 // 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> 

I expect the end result to stop moving when i stop holding down the key. 我希望当我停止按住键时最终结果将停止移动。

Instead of setInterval(draw, 50); 代替setInterval(draw, 50); use var loop = setInterval(draw, 50); 使用var loop = setInterval(draw, 50); Then when you want it to stop, use clearInterval(loop); 然后,当您希望它停止时,使用clearInterval(loop);

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

放开按钮,应立即禁用移动。

Both answers don't seem to be of much help. 这两个答案似乎并没有太大帮助。

Animation loop 动画循环

You are correct that an infinite loop is the best way to handle game animation. 您认为无限循环是处理游戏动画的最佳方法是正确的。

However don't use setInverval , use requestAnimationFrame to create the game loop. 但是,请勿使用setInverval ,而应使用requestAnimationFrame创建游戏循环。

You have an interval of 50ms which is 20fps (frames per second). 您有50ms的间隔,即20fps(每秒帧数)。 requestAnimationFrame will try to run at 60fps which you can not change. requestAnimationFrame将尝试以60fps的速度运行,您无法更改。 However you can just skip every 2 out of 3 frames to get 20fps. 但是,您可以每3帧跳过2帧以获得20fps。

The snippet shows a basic game loop using requestAnimationFrame with a adjustable frame rate. 该代码段显示了使用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);
}

The keyboard 键盘

To handle keyboard input you need to listen to both the key down and key up events. 要处理键盘输入,您需要同时监听按键按下和按键按下事件。

The flowing snippet is a simple keyboard state manager that maintains the state of the keys you are interested in. 流畅的代码段是一个简单的键盘状态管理器,用于维护您感兴趣的键的状态。

You can find key codes at KeyboardEvent.code 您可以在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);

Now you just change your game code to move the character only when the key is down. 现在,您只需更改游戏代码即可仅在按键按下时移动角色。

BTW its best to move sprites then draw sprites, rather than draw then move. 顺便说一句,最好先移动精灵然后绘制精灵,而不是先绘制再移动。 This reduces the delay between user input and visual feedback. 这减少了用户输入和视觉反馈之间的延迟。

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

Example

The snippet puts it all together. 该片段将所有内容组合在一起。

I think you got your key mapping back to front, I left it as your code seemed to imply left moves right, up moves down and so on. 我认为您的键映射是从前到后的,我把它保留了下来是因为您的代码似乎暗示着左移右移,上移向下等等。

I also made changes to how the images are loaded and made an object that is the character. 我还更改了图像的加载方式,并更改了作为字符的对象。

Hope it helps and is not to late (I just noticed the question date). 希望它能有所帮助,并且不要迟到(我刚刚注意到问题日期)。

 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> 

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

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