我正在研究俄罗斯方块的实现,自学javascript,我遇到了一个问题。首先,背景:我有一个类用于每种类型的tetris块,它继承自基本块模板,使用移动和返回坐标等方法。例如,
function BlockTemplate(w, h, c){
var height = h;
var width = w;
var x = 0;
var y = 0;
var color = c;
this.getHeight = function(){return height;};
this.getWidth = function(){return width;};
this.getX = function(){return x;};
this.getY = function(){return y;};
this.getColor = function(){return color;};
this.moveTo = function(newX, newY){
x = newX;
y = newY;
};
this.translate = function(dx, dy){
x += dx;
y += dy;
};
}
function StraightBlock(){
this.draw = function(){
ctx.fillStyle = this.getColor();
ctx.fillRect(this.getX(), this.getY(), 20, 100);
};
}
StraightBlock.prototype = new BlockTemplate(20, 100, "#00FFE5");
当前屏幕上的所有块都存储在数组blockArr
中,但当前正在下降的块除外,该块存储在curBlock
中。
我使用一个名为createRandomBlock()
的函数创建一个块并将其放在curBlock中:
var blockTypeArr = [LBlock, SquareBlock, StraightBlock, SquigBlock];
var createRandomBlock = function(){
var block = blockTypeArr[Math.floor(Math.random()*blockTypeArr.length)];
var randomBlock = new block();
return randomBlock;
};
curBlock = createRandomBlock();
一旦完成,我将它放入数组并创建一个新块:
blockArr[blockArr.length] = curBlock;
curBlock = createRandomBlock();
如果新创建的块尚未出现在屏幕上,则没有问题。但是,使用新实例的moveTo
和translate
方法会影响该类的所有实例(我添加了一个id属性以确保它们实际上是不同的实例)。
例如,使用JavaScript控制台
>curBlock
SquigBlock
>blockArr
[SquareBlock, SquigBlock, SquigBlock]
正如你所看到的,到目前为止,3个SquigBlocks已经下降(blockArr
中有2个,目前正在下降1个)。然而,我看到的唯一一个是当前正在下降的那个(curBlock
),并且检查参数,curBlock.getY()
,blockArr[1].getY()
和blockArr[2].getY()
都返回相同的值。换句话说,它们都被绘制在同一个位置。
如何更改它以使旧块(无论是什么类)停留在屏幕底部,而新创建的块从顶部落下而不会导致该类的所有其他块随之移动?< / p>
谢谢!
答案 0 :(得分:1)
StraightBlock.prototype = new BlockTemplate(20, 100, "#00FFE5");
嗯, 只有一个BlockTemplate
与StraightBlock
个实例共享。您可以看到new StraightBlock().moveTo == new StraightBlock().moveTo
,即两个实例具有影响相同x
变量的相同方法。 Do not use new
for creating the prototype,但Correct javascript inheritance:
function StraightBlock(){
BlockTemplate.call(this, 20, 100, "#00FFE5");
this.draw = function(){
ctx.fillStyle = this.getColor();
ctx.fillRect(this.getX(), this.getY(), 20, 100);
};
}
StraightBlock.prototype = Object.create(BlockTemplate.prototype);
答案 1 :(得分:1)
StraightBlock.prototype = new BlockTemplate(20, 100, "#00FFE5");
由于调用了一次,因此在var x
的所有实例之间共享的单个getHeight
会关闭一个StraightBlock
。
您应该进行两项更改:
this
function BlockTemplate(w, h, c){
this.height = h;
...
}
BlockTemplate.prototype.getHeight = function(){return this.height;};
...
让StraightBlock
调用其超类构造函数,为每个创建的实例添加新版本的方法。
function StraightBlock(){
BlockTemplate.apply(this, arguments);
...
}
您也可以只进行构造函数链接,但这意味着您要为每个实例创建每个方法的新副本。如果您有很多短期的“类”实例,这可能会很昂贵。
在this
上存储字段的缺点是它们可能被天真的代码无意中变异。除了通过封闭的局部变量之外,JavaScript没有强大的信息隐藏功能,因此如果您希望通过其他语言的private
字段获得稳健性,那么通过局部变量进行的当前设计可能是最佳的。