我正在尝试使用我用模因制作的精灵为我的朋友制作游戏。我决定使用无限循环来有效地运行我的代码,但我不知道如何使用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>
当我停止按住键时,我希望最终结果停止移动。
而不是setInterval(draw, 50);
使用var loop = setInterval(draw, 50);
然后当你想要它停止时,使用clearInterval(loop);
document.addEventListener("keyup", () => d = null);
一旦松开按钮,这应该禁用运动。
这两个答案似乎都没有多大帮助。
你是对的,无限循环是处理游戏动画的最佳方式。
但是不要使用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>