上次我们解决了moveDown的边界处理。这次我们可以依样画葫芦,把moveLeft,moveRight的边界处理都完成。
每次边界处理也同样是3步:1)确定新的位置。2)查看新位置是否可行。3)如果可行,把新的位置替代旧的位置。
void Element::moveLeft()
{
Box newBody[4];
for (int i=0; i<4; i++)
{
newBody[i].setX(body[i].getX()-1);
newBody[i].setY(body[i].getY());
}
if (!ifOccupied(newBody))
copyBody(newBody);
}
void Element::moveRight()
{
Box newBody[4];
for (int i=0; i<4; i++)
{
newBody[i].setX(body[i].getX()+1);
newBody[i].setY(body[i].getY());
}
if (!ifOccupied(newBody))
copyBody(newBody);
}
最后,还要进行边界判断的还有旋转。如果旋转出了边界,或者遇到了障碍块,那得阻止旋转。
和其他不同的是,左移右移,下落是每种方块行为都一致,所以在父类Element中实现。而旋转时不同形状的方块行为不同,所以旋转是在子类中实现的。现在为了加上边界处理,我们不得不在每个子类的旋转实现中都进行修改。比如在Bar的旋转我们修改如下:
void Bar::rotate()
{
//确定新的位置
Box newBody[4];
if(body[0].getX() == body[1].getX())
{
newBody[0].setX(body[0].getX() + 2);
newBody[0].setY(body[0].getY() + 2);
newBody[1].setX(body[1].getX() + 1);
newBody[1].setY(body[1].getY() + 1);
newBody[3].setX(body[3].getX() - 1);
newBody[3].setY(body[3].getY() - 1);
newBody[2]=body[2];
}
else
{
newBody[0].setX(body[0].getX() - 2);
newBody[0].setY(body[0].getY() - 2);
newBody[1].setX(body[1].getX() - 1);
newBody[1].setY(body[1].getY() - 1);
newBody[3].setX(body[3].getX() + 1);
newBody[3].setY(body[3].getY() + 1);
newBody[2]=body[2];
}
//如果新的位置可行
if (!ifOccupied(newBody))
//用新的位置代替旧的位置
copyBody(newBody);
}
鉴于篇幅,其他几种形状的旋转代码就省略了。
到现在为止,我们已经写了很多遍相同代码
if (!ifOccupied(newBody))
//用新的位置代替旧的位置
copyBody(newBody);
虽然只有两行代码,但是出现了那么多次,我们还是可以把他重构成一个单独的函数
bool Element::move(Box * newBody)
{
bool flag = ifOccupied(newBody);
if (!flag)
//用新的位置代替旧的位置
copyBody(newBody);
return !flag;
}
这样无论在父类的移动或下降函数,或者子类的旋转中,我们只需要关心移动或旋转的规则,然后调用move函数就可以了。
void Element::moveDown()
{
Box newBody[4];
for (int i=0; i<4; i++)
{
newBody[i].setX(body[i].getX());
newBody[i].setY(body[i].getY()+1);
}
move(newBody);
}
void Element::moveLeft()
{
Box newBody[4];
for (int i=0; i<4; i++)
{
newBody[i].setX(body[i].getX()-1);
newBody[i].setY(body[i].getY());
}
move(newBody);
}
void Element::moveRight()
{
Box newBody[4];
for (int i=0; i<4; i++)
{
newBody[i].setX(body[i].getX()+1);
newBody[i].setY(body[i].getY());
}
move(newBody);
}
void Bar::rotate()
{
Box newBody[4];
if(body[0].getX() == body[1].getX())
{
newBody[0].setX(body[0].getX() + 2);
newBody[0].setY(body[0].getY() + 2);
newBody[1].setX(body[1].getX() + 1);
newBody[1].setY(body[1].getY() + 1);
newBody[3].setX(body[3].getX() - 1);
newBody[3].setY(body[3].getY() - 1);
newBody[2]=body[2];
}
else
{
newBody[0].setX(body[0].getX() - 2);
newBody[0].setY(body[0].getY() - 2);
newBody[1].setX(body[1].getX() - 1);
newBody[1].setY(body[1].getY() - 1);
newBody[3].setX(body[3].getX() + 1);
newBody[3].setY(body[3].getY() + 1);
newBody[2]=body[2];
}
move(newBody);
}
这样我们的边界处理算是圆满完成了。最后还要提醒一句,为了让move函数可以被子类调用,而不被其他类使用,move函数必须声明成protected