canvas drawImage循环问题

时间:2017-01-04 11:54:26

标签: javascript canvas

我正在尝试通过将fillRect替换为图像来修改this画布游戏。

在第529行更改 spaceinvaders.js 中的船舶代码时没有问题:

ship = new Image();
ship.src = "images/ship.svg";

ctx.drawImage(ship, this.ship.x - (this.ship.width / 2), this.ship.y - (this.ship.height / 2), this.ship.width, this.ship.height);

但遇到入侵者循环问题:

for(var i=0; i<this.invaders.length; i++) {

    var invader = this.invaders[i] = new Image();
    this.invaders[i].src = "images/space_invader.png";

    //ctx.fillRect(invader.x - invader.width/2, invader.y - invader.height/2, invader.width, invader.height);

    this.invaders[i].onload = function(){

        var thisX = invader.x * 18;
        var thisY = invader.y * 14;

        return function() {
            ctx.drawImage(invader,invader.x - invader.width/2, invader.y - invader.height/2, invader.width, invader.height);
            //ctx.drawImage(this, thisX, thisY, invader.width, invader.height);
        };

    };
}

当我最终显示入侵者图像时,它将它们全部叠加在一起。 - 即使使用thisX和thisY变量。

编辑:

img = new Image();

img.onload = function(){

    for(var i=0; i<this.invaders.length; i++) {
        for(var j=0; j<this.invaders.length; j++) {
            var invader = this.invaders[i];
            ctx.drawImage(img,j*18, i*14, invader.width, invader.height);
        }
    }
}

img.src = "images/space_invader.png";

给出:无法读取未定义的属性“长度”。

编辑2:

img = new Image();

img.onload = function(){

    for(var i=0; i<5; i++) {
        for(var j=0; j<10; j++) {
            ctx.drawImage(img,j*22, i*16, 18, 14);
        }
    }
}

img.src = "images/space_invader.png";

这样我至少可以看到入侵者,但它们是静态的:enter image description here

编辑3:

var invaders=[{x:0,y:0},{x:20,y:0},{x:40,y:0},{x:60,y:0},{x:80,y:0},{x:100,y:0},{x:120,y:0},{x:140,y:0},{x:160,y:0},{x:180,y:0},{x:0,y:16},{x:20,y:16},{x:40,y:16},{x:60,y:16},{x:80,y:16},{x:100,y:16},{x:120,y:16},{x:140,y:16},{x:160,y:16},{x:180,y:16},{x:200,y:16},{x:0,y:32},{x:20,y:32},{x:40,y:32},{x:60,y:32},{x:80,y:32},{x:100,y:32},{x:120,y:32},{x:140,y:32},{x:160,y:32},{x:180,y:32},{x:200,y:32},{x:0,y:48},{x:20,y:48},{x:40,y:48},{x:60,y:48},{x:80,y:48},{x:100,y:48},{x:120,y:48},{x:140,y:48},{x:160,y:48},{x:180,y:48},{x:200,y:48},{x:0,y:64},{x:20,y:64},{x:40,y:64},{x:60,y:64},{x:80,y:64},{x:100,y:64},{x:120,y:64},{x:140,y:64},{x:160,y:64},{x:180,y:64},{x:200,y:64}];

for (var i=0; i<this.invaders.length; i++) {

    invaders[i] = new Image();

    invaders[i].onload = function() {
        ctx.drawImage(this, x, y);         
    };

    invaders[i].src = "images/space_invader.png";
}

未定义x。

编辑4:

function createImage(i){   

var image = new Image();  
    image.src = "images/space_invader.png";
    image.onload = function(){  
        ctx.drawImage(image,imagePos[i][0],imagePos[i][1], 20, 16);
    } 
}

var imagePos=[[0,0],[20,0],[40,0],[60,0],[80,0],[100,0],[120,0],[140,0],[160,0],[180,0],[0,16],[20,16],[40,16],[60,16],[80,16],[100,16],[120,16],[140,16],[160,16],[180,16],[0,32],[20,32],[40,32],[60,32],[80,32],[100,32],[120,32],[140,32],[160,32],[180,32],[0,48],[20,48],[40,48],[60,48],[80,48],[100,48],[120,48],[140,48],[160,48],[180,48],[0,64],[20,64],[40,64],[60,64],[80,64],[100,64],[120,64],[140,64],[160,64],[180,64]];

for(var i = 0; i <this.invaders.length; i += 1){
    createImage(i); 
}
return

显示入侵者,但他们一直闪烁。 (主要游戏循环?)

3 个答案:

答案 0 :(得分:3)

一个变量只能包含一个值。

有一条简单的规则可以帮助您避免这样的问题。永远不要在循环中声明函数。

<强>为什么?

让我们看一个循环

[Wed Jan 04 21:23:09 2017] [error] [client ::1] Traceback (most recent call last):
[Wed Jan 04 21:23:09 2017] [error] [client ::1]   File "/home/blakeh/test.py", line 7, in <module>
[Wed Jan 04 21:23:09 2017] [error] [client ::1]     client.foo()
[Wed Jan 04 21:23:09 2017] [error] [client ::1]   File "/usr/local/lib/python3.5/xmlrpc/client.py", line 1092, in __call__
[Wed Jan 04 21:23:09 2017] [error] [client ::1]     return self.__send(self.__name, args)
[Wed Jan 04 21:23:09 2017] [error] [client ::1]   File "/usr/local/lib/python3.5/xmlrpc/client.py", line 1432, in __request
[Wed Jan 04 21:23:09 2017] [error] [client ::1]     verbose=self.__verbose
[Wed Jan 04 21:23:09 2017] [error] [client ::1]   File "/usr/local/lib/python3.5/xmlrpc/client.py", line 1134, in request
[Wed Jan 04 21:23:09 2017] [error] [client ::1]     return self.single_request(host, handler, request_body, verbose)
[Wed Jan 04 21:23:09 2017] [error] [client ::1]   File "/usr/local/lib/python3.5/xmlrpc/client.py", line 1146, in single_request
[Wed Jan 04 21:23:09 2017] [error] [client ::1]     http_conn = self.send_request(host, handler, request_body, verbose)
[Wed Jan 04 21:23:09 2017] [error] [client ::1]   File "/usr/local/lib/python3.5/xmlrpc/client.py", line 1259, in send_request
[Wed Jan 04 21:23:09 2017] [error] [client ::1]     self.send_content(connection, request_body)
[Wed Jan 04 21:23:09 2017] [error] [client ::1]   File "/usr/local/lib/python3.5/xmlrpc/client.py", line 1289, in send_content
[Wed Jan 04 21:23:09 2017] [error] [client ::1]     connection.endheaders(request_body)
[Wed Jan 04 21:23:09 2017] [error] [client ::1]   File "/usr/local/lib/python3.5/http/client.py", line 1102, in endheaders
[Wed Jan 04 21:23:09 2017] [error] [client ::1]     self._send_output(message_body)
[Wed Jan 04 21:23:09 2017] [error] [client ::1]   File "/usr/local/lib/python3.5/http/client.py", line 934, in _send_output
[Wed Jan 04 21:23:09 2017] [error] [client ::1]     self.send(msg)
[Wed Jan 04 21:23:09 2017] [error] [client ::1]   File "/usr/local/lib/python3.5/http/client.py", line 877, in send
[Wed Jan 04 21:23:09 2017] [error] [client ::1]     self.connect()
[Wed Jan 04 21:23:09 2017] [error] [client ::1]   File "/usr/local/lib/python3.5/http/client.py", line 849, in connect
[Wed Jan 04 21:23:09 2017] [error] [client ::1]     (self.host,self.port), self.timeout, self.source_address)
[Wed Jan 04 21:23:09 2017] [error] [client ::1]   File "/usr/local/lib/python3.5/socket.py", line 711, in create_connection
[Wed Jan 04 21:23:09 2017] [error] [client ::1]     raise err
[Wed Jan 04 21:23:09 2017] [error] [client ::1]   File "/usr/local/lib/python3.5/socket.py", line 702, in create_connection
[Wed Jan 04 21:23:09 2017] [error] [client ::1]     sock.connect(sa)
[Wed Jan 04 21:23:09 2017] [error] [client ::1] PermissionError: [Errno 13] Permission denied

您希望开始加载10张图片,当每张图片都已加载时,您希望它们在正确的位置绘制。但这永远不会发生。

在for循环完成并返回执行之前,var imagePos = [[10,10],[10,20],[10,30],[10,40],[10,50],[20,10],[20,20],[20,30],[20,40],[20,50]]; for(var i = 0; i < 10; i += 1){ var image = new Image(); image.src = "imagename"; image.onload = function(){ ctx.drawImage(image,imagePos[i][0],imagePos[i][1]); } } // end return 函数不会触发。在第一个onload事件触发onload时,您有2个变量iimage,并且每个onload都会保持这种变量。您在onload函数中提供的图像也只是一个变量,不能容纳多个图像。即使每个i = 10都正确绑定到图像,onload变量也将指向循环中创建的最后一个图像。

您希望imagei分别拥有10个单独的值,并知道什么时候需要什么值。

正确的方法如下

image

您也可以使用循环内的函数完成它,但您需要使用函数绑定对象来存储您想要的值。

function createImage(i){   // load an image function 
                           // creates a new i each time it is called
    var image = new Image();  // create a new image variable 
    image.src = "imagename";
    image.onload = function(){  // now the onload will have the correct variables 
         ctx.drawImage(image,imagePos[i][0],imagePos[i][1]);
    } 
 }
var imagePos = [[10,10],[10,20],[10,30],[10,40],[10,50],[20,10],[20,20],[20,30],[20,40],[20,50]];
for(var i = 0; i < 10; i += 1){
    createImage(i); // call the function so it can create unique variables for each image
}
// end
return

除了你发现的陷阱之外,这样做是没有错的。这就是为什么一般规则是,如果你不熟悉javascript,不要在循环中声明函数。

答案 1 :(得分:1)

您可能不应该使用Image对象的x和y属性。首先它是只读的,第二个可能没有设置,因为你正在创建一个新的Image实例,所以总是为0。

请参阅https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image以及https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement

答案 2 :(得分:0)

大!现在你所需要的只是某种游戏循环来让它们移动。我会将x和y位置(从你当前的for循环)移动到单个对象中,这样你就可以修改每个(更新)循环的每个入侵者。

var invaders = [ {x: 100, y: 100, speed: 10}, {x: 140, y: 100, speed: 10}, {x: 180, y: 100, speed: 10}, // and so on ];

尝试阅读有关游戏循环及其工作方式的更多信息:https://www.isaacsukin.com/news/2015/01/detailed-explanation-javascript-game-loops-and-timing

编辑:像这样......

for(var i = 0; i < invaders.length; i++) {

    var invader = new Image();

    invader.onload = function() {
        ctx.drawImage(this, invaders[i].x, invaders[i].y);         
    };

    invaders[i].src = "images/space_invader.png";
}