我正在尝试使用由模因制作的精灵为我的朋友制作游戏。我决定使用一个无限循环来有效地运行我的代码,但是我不确定如何使用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>
我希望当我停止按住键时最终结果会停止移动。
答案 0 :(得分:0)
使用setInterval(draw, 50);
代替var loop = setInterval(draw, 50);
,然后在停止时使用clearInterval(loop);
答案 1 :(得分:0)
document.addEventListener("keyup", () => d = null);
这将在您释放按钮后立即禁用移动。
答案 2 :(得分:0)
两个答案似乎并没有太大帮助。
您是正确的,无限循环是处理游戏动画的最佳方法。
但是,不要使用setInverval
,请使用requestAnimationFrame
创建游戏循环。
您有50ms的间隔,即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);
}
要处理键盘输入,您需要同时监听按键按下和按键按下事件。
流畅的代码片段是一个简单的键盘状态管理器,用于维护您感兴趣的键的状态。
中找到关键代码。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);
现在,您只需更改游戏代码即可仅在按键按下时移动角色。
顺便说一句,最好先移动精灵然后绘制精灵,而不是先绘制然后再移动。这样可以减少用户输入和视觉反馈之间的延迟。
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>