drawImage() 在循环外工作,但不在循环内?
drawImage() works outside of loop, but not inside?
我正在制作一款类似飞鸟的游戏。问题是,图像不会在 draw() 函数内的循环中加载。如果我将 drawImage() 放在循环之外(就像其他图像一样),那么它们就可以工作了。
控制台没有报错,for循环里面的两张图片没有出现,只是不明白为什么 >:/
HTML:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="512" height="512">
</canvas>
这是我在 class:
中制作的 JS 代码
const canvas = document.querySelector("#canvas");
class Game {
constructor(c) {
this.c = c; //canvas
this.ctx = c.getContext("2d"); // context
this.sprites = 5;
this.loadedSprites = 0;
this.score = 0;
this.gravity = 1.5
this.player = new Image(); // define images
this.player.reference = this;
this.bg = new Image();
this.bg.reference = this;
this.fg = new Image();
this.fg.reference = this;
this.north = new Image();
this.north.reference = this;
this.south = new Image();
this.south.reference = this;
//obstacle coordinates
this.obstacle = [];
this.obstacle[0] = {
x: this.c.width,
y: 0,
// reference: this
}
this.obstacle.reference = this;
this.pX = 10; // player starting location
this.pY = 150;
// set sprite locations and load.
this.player.onload = this.draw;
this.player.src = "images/crab.png";
this.bg.onload = this.draw;
this.bg.src = "images/bg.png";
this.fg.onload = this.draw;
this.fg.src = "images/fg.png";
this.north.onload = this.draw;
this.north.src = "images/obstacle.png";
this.gap = 85;
this.constant = this.north.height + this.gap;
this.south.onload = this.draw;
this.south.src = "images/obstacle.png";
console.log(`AAA: ${this.obstacle[0].x}`);
console.log(`LAUNCH is: ${this.obstacle[0]}`);
$(document).on('keydown', (e) => { this.moveUp(e.key) });
console.log("Game constructor:", this);
}
loadObstacle() {
return this.obstacle;
}
saveObstacle(obstacle) {
this.obstacle = obstacle;
}
draw() {
let ref = this.reference;
ref.loadedSprites += 1;
if (ref.loadedSprites >= ref.sprites) {
let constant = ref.gap + ref.north.height;
let obstacle = ref.loadObstacle(); // this is actually not needed, since ref.obstacle odes the same thing. Just thought I'd try something else
for (var i = 0; i < obstacle.length; i++) {
ref.ctx.drawImage(ref.north, obstacle[i].x, obstacle[i].y);
ref.ctx.drawImage(ref.south, obstacle[i].x, obstacle[i].y + constant);
// ref.ctx.drawImage(ref.north, 250, 0); even adding these two from below, they do not show up
// ref.ctx.drawImage(ref.south, 250, 0 + constant);
obstacle[i].x--;
if (obstacle[i].x == 125) {
obstacle.push({
x: 512,
y: Math.floor(Math.random() * ref.north.height)
});
}
ref.saveObstacle(obstacle);
console.log(obstacle[0].x); // the values are right, but they do not appear?
}
ref.ctx.drawImage(ref.bg, 0, 0);
// ref.ctx.drawImage(ref.north, 250, 0); uncommenting this makes it show up
// ref.ctx.drawImage(ref.south, 250, 0 + constant);
ref.ctx.drawImage(ref.fg, 0, ref.c.height - ref.fg.height);
ref.ctx.drawImage(ref.player, ref.pX, ref.pY);
ref.pY += ref.gravity
window.requestAnimationFrame(ref.draw.bind(this));
}
}
moveUp(e) {
if (e == "w" || e == " " || e == "ArrowUp") {
this.pY -= 30;
console.log(this.obstacle);
}
}
}
let game = new Game(canvas);
How it looks like with my code
How the working code should look like
首先也是最重要的一点:你在这里混合了两种完全不同的东西。
this.player.onload = this.draw;
和
window.requestAnimationFrame(ref.draw.bind(this));
两者执行相同的功能。从技术上讲,这当然是可能的,但它让事情有点混乱。我建议为 onload 事件设置一个附加函数,这样您就可以在所有图像完成加载后立即触发 requestAnimationFrame。
this.player = new Image();
this.player.reference = this;
this.player.onload = this.loaded;
loaded() {
let ref = this.reference;
ref.loadedSprites += 1;
if (ref.loadedSprites >= ref.sprites) {
// continue
}
}
其次,需要将 this 关键字的正确 'context' 传递给 .bind() 函数。它应该始终是您的游戏 class 的对象。所以将上面的 // continue
替换为:
window.requestAnimationFrame(ref.draw.bind(ref));
现在 draw()
功能需要一些修改。由于我们为 this 关键字提供了正确的上下文,我们不再需要使用引用 - 我们现在可以简单地使用 this。
完整示例如下:
const canvas = document.querySelector("#canvas");
class Game {
constructor(c) {
this.c = c; //canvas
this.ctx = c.getContext("2d"); // context
this.sprites = 5;
this.loadedSprites = 0;
this.score = 0;
this.gravity = 1.5
this.player = new Image();
this.player.reference = this;
this.bg = new Image();
this.bg.reference = this;
this.fg = new Image();
this.fg.reference = this;
this.north = new Image();
this.north.reference = this;
this.south = new Image();
this.south.reference = this;
//obstacle coordinates
this.obstacle = [];
this.obstacle[0] = {
x: this.c.width,
y: 0,
// reference: this
}
this.obstacle.reference = this;
this.pX = 10; // player starting location
this.pY = 150;
// set sprite locations and load.
this.player.onload = this.loaded;
this.player.src = "https://picsum.photos/id/237/20/20";
this.bg.onload = this.loaded;
this.bg.src = "https://picsum.photos/id/22/20/20";
this.fg.onload = this.loaded;
this.fg.src = "https://picsum.photos/id/30/20/20";
this.north.onload = this.loaded;
this.north.src = "https://picsum.photos/id/37/20/20";
this.gap = 85;
this.constant = this.north.height + this.gap;
this.south.onload = this.loaded;
this.south.src = "https://picsum.photos/id/137/20/20";
console.log(`AAA: ${this.obstacle[0].x}`);
console.log(`LAUNCH is: ${this.obstacle[0]}`);
$(document).on('keydown', (e) => {
this.moveUp(e.key)
});
console.log("Game constructor:", this);
}
loadObstacle() {
return this.obstacle;
}
saveObstacle(obstacle) {
this.obstacle = obstacle;
}
loaded() {
let ref = this.reference;
ref.loadedSprites += 1;
if (ref.loadedSprites >= ref.sprites) {
window.requestAnimationFrame(ref.draw.bind(ref));
}
}
draw() {
let constant = this.gap + this.north.height;
let obstacle = this.loadObstacle();
for (var i = 0; i < obstacle.length; i++) {
this.ctx.drawImage(this.north, obstacle[i].x, obstacle[i].y);
this.ctx.drawImage(this.south, obstacle[i].x, obstacle[i].y + constant);
obstacle[i].x--;
if (obstacle[i].x == 125) {
obstacle.push({
x: 512,
y: Math.floor(Math.random() * this.north.height)
});
}
this.saveObstacle(obstacle);
}
this.ctx.drawImage(this.bg, 0, 0);
this.ctx.drawImage(this.fg, 0, this.c.height - this.fg.height);
this.ctx.drawImage(this.player, this.pX, this.pY);
this.pY += this.gravity
window.requestAnimationFrame(this.draw.bind(this));
}
moveUp(e) {
if (e == "w" || e == " " || e == "ArrowUp") {
this.pY -= 30;
console.log(this.obstacle);
}
}
}
let game = new Game(canvas);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="512" height="512">
</canvas>
我正在制作一款类似飞鸟的游戏。问题是,图像不会在 draw() 函数内的循环中加载。如果我将 drawImage() 放在循环之外(就像其他图像一样),那么它们就可以工作了。
控制台没有报错,for循环里面的两张图片没有出现,只是不明白为什么 >:/
HTML:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="512" height="512">
</canvas>
这是我在 class:
中制作的 JS 代码const canvas = document.querySelector("#canvas");
class Game {
constructor(c) {
this.c = c; //canvas
this.ctx = c.getContext("2d"); // context
this.sprites = 5;
this.loadedSprites = 0;
this.score = 0;
this.gravity = 1.5
this.player = new Image(); // define images
this.player.reference = this;
this.bg = new Image();
this.bg.reference = this;
this.fg = new Image();
this.fg.reference = this;
this.north = new Image();
this.north.reference = this;
this.south = new Image();
this.south.reference = this;
//obstacle coordinates
this.obstacle = [];
this.obstacle[0] = {
x: this.c.width,
y: 0,
// reference: this
}
this.obstacle.reference = this;
this.pX = 10; // player starting location
this.pY = 150;
// set sprite locations and load.
this.player.onload = this.draw;
this.player.src = "images/crab.png";
this.bg.onload = this.draw;
this.bg.src = "images/bg.png";
this.fg.onload = this.draw;
this.fg.src = "images/fg.png";
this.north.onload = this.draw;
this.north.src = "images/obstacle.png";
this.gap = 85;
this.constant = this.north.height + this.gap;
this.south.onload = this.draw;
this.south.src = "images/obstacle.png";
console.log(`AAA: ${this.obstacle[0].x}`);
console.log(`LAUNCH is: ${this.obstacle[0]}`);
$(document).on('keydown', (e) => { this.moveUp(e.key) });
console.log("Game constructor:", this);
}
loadObstacle() {
return this.obstacle;
}
saveObstacle(obstacle) {
this.obstacle = obstacle;
}
draw() {
let ref = this.reference;
ref.loadedSprites += 1;
if (ref.loadedSprites >= ref.sprites) {
let constant = ref.gap + ref.north.height;
let obstacle = ref.loadObstacle(); // this is actually not needed, since ref.obstacle odes the same thing. Just thought I'd try something else
for (var i = 0; i < obstacle.length; i++) {
ref.ctx.drawImage(ref.north, obstacle[i].x, obstacle[i].y);
ref.ctx.drawImage(ref.south, obstacle[i].x, obstacle[i].y + constant);
// ref.ctx.drawImage(ref.north, 250, 0); even adding these two from below, they do not show up
// ref.ctx.drawImage(ref.south, 250, 0 + constant);
obstacle[i].x--;
if (obstacle[i].x == 125) {
obstacle.push({
x: 512,
y: Math.floor(Math.random() * ref.north.height)
});
}
ref.saveObstacle(obstacle);
console.log(obstacle[0].x); // the values are right, but they do not appear?
}
ref.ctx.drawImage(ref.bg, 0, 0);
// ref.ctx.drawImage(ref.north, 250, 0); uncommenting this makes it show up
// ref.ctx.drawImage(ref.south, 250, 0 + constant);
ref.ctx.drawImage(ref.fg, 0, ref.c.height - ref.fg.height);
ref.ctx.drawImage(ref.player, ref.pX, ref.pY);
ref.pY += ref.gravity
window.requestAnimationFrame(ref.draw.bind(this));
}
}
moveUp(e) {
if (e == "w" || e == " " || e == "ArrowUp") {
this.pY -= 30;
console.log(this.obstacle);
}
}
}
let game = new Game(canvas);
How it looks like with my code
How the working code should look like
首先也是最重要的一点:你在这里混合了两种完全不同的东西。
this.player.onload = this.draw;
和
window.requestAnimationFrame(ref.draw.bind(this));
两者执行相同的功能。从技术上讲,这当然是可能的,但它让事情有点混乱。我建议为 onload 事件设置一个附加函数,这样您就可以在所有图像完成加载后立即触发 requestAnimationFrame。
this.player = new Image();
this.player.reference = this;
this.player.onload = this.loaded;
loaded() {
let ref = this.reference;
ref.loadedSprites += 1;
if (ref.loadedSprites >= ref.sprites) {
// continue
}
}
其次,需要将 this 关键字的正确 'context' 传递给 .bind() 函数。它应该始终是您的游戏 class 的对象。所以将上面的 // continue
替换为:
window.requestAnimationFrame(ref.draw.bind(ref));
现在 draw()
功能需要一些修改。由于我们为 this 关键字提供了正确的上下文,我们不再需要使用引用 - 我们现在可以简单地使用 this。
完整示例如下:
const canvas = document.querySelector("#canvas");
class Game {
constructor(c) {
this.c = c; //canvas
this.ctx = c.getContext("2d"); // context
this.sprites = 5;
this.loadedSprites = 0;
this.score = 0;
this.gravity = 1.5
this.player = new Image();
this.player.reference = this;
this.bg = new Image();
this.bg.reference = this;
this.fg = new Image();
this.fg.reference = this;
this.north = new Image();
this.north.reference = this;
this.south = new Image();
this.south.reference = this;
//obstacle coordinates
this.obstacle = [];
this.obstacle[0] = {
x: this.c.width,
y: 0,
// reference: this
}
this.obstacle.reference = this;
this.pX = 10; // player starting location
this.pY = 150;
// set sprite locations and load.
this.player.onload = this.loaded;
this.player.src = "https://picsum.photos/id/237/20/20";
this.bg.onload = this.loaded;
this.bg.src = "https://picsum.photos/id/22/20/20";
this.fg.onload = this.loaded;
this.fg.src = "https://picsum.photos/id/30/20/20";
this.north.onload = this.loaded;
this.north.src = "https://picsum.photos/id/37/20/20";
this.gap = 85;
this.constant = this.north.height + this.gap;
this.south.onload = this.loaded;
this.south.src = "https://picsum.photos/id/137/20/20";
console.log(`AAA: ${this.obstacle[0].x}`);
console.log(`LAUNCH is: ${this.obstacle[0]}`);
$(document).on('keydown', (e) => {
this.moveUp(e.key)
});
console.log("Game constructor:", this);
}
loadObstacle() {
return this.obstacle;
}
saveObstacle(obstacle) {
this.obstacle = obstacle;
}
loaded() {
let ref = this.reference;
ref.loadedSprites += 1;
if (ref.loadedSprites >= ref.sprites) {
window.requestAnimationFrame(ref.draw.bind(ref));
}
}
draw() {
let constant = this.gap + this.north.height;
let obstacle = this.loadObstacle();
for (var i = 0; i < obstacle.length; i++) {
this.ctx.drawImage(this.north, obstacle[i].x, obstacle[i].y);
this.ctx.drawImage(this.south, obstacle[i].x, obstacle[i].y + constant);
obstacle[i].x--;
if (obstacle[i].x == 125) {
obstacle.push({
x: 512,
y: Math.floor(Math.random() * this.north.height)
});
}
this.saveObstacle(obstacle);
}
this.ctx.drawImage(this.bg, 0, 0);
this.ctx.drawImage(this.fg, 0, this.c.height - this.fg.height);
this.ctx.drawImage(this.player, this.pX, this.pY);
this.pY += this.gravity
window.requestAnimationFrame(this.draw.bind(this));
}
moveUp(e) {
if (e == "w" || e == " " || e == "ArrowUp") {
this.pY -= 30;
console.log(this.obstacle);
}
}
}
let game = new Game(canvas);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="512" height="512">
</canvas>