本节我们将完成控制小鸟穿越管道,如果碰到水管,或者碰到世界边缘,游戏结束,本节是整个游戏的重点和难点。

第一步:让管道能够不断从世界右侧向左侧移动

思路:不断修改角色的x坐标,实现向左移动,判断如果x坐标小于1也就是到达了左侧边缘,然后重置坐标到世界的最右侧,这里用到了一个随机数getRandomNumber(y坐标的高度在50到300之间),主要是让管道高低错落,否则都是一样的高度。

修改Pipe角色的程序,在act方法中加入如下代码

setLocation(getX() - 1, getY());

        if(getX() <= 1){

           setLocation(getX() + 600, Greenfoot.getRandomNumber(250)+50);

       }

这样管子的代码就完成了,比较简单,如图所示。

Greenfoot制作flappybird游戏[四]

第二步:判断小鸟是否与管子相撞。

这是关键点,我们之前介绍过如何检测两个角色碰撞,在Greenfoot中有现成的方法,只要碰到角色图片的边缘即认为碰撞发生,但是这里并不适用,因为小鸟要从管道角色的空隙中穿过,由于是png图片,背景透明,我们肉眼看到似乎是没有碰到一起,其实着已经是发生了碰撞。

那么应该怎么去判断碰到了Pipe角色的绿色管道部分呢?我们看一下这个图片:

Greenfoot制作flappybird游戏[四]

思路:要判断小鸟碰到水管有两个必备条件。

1、在x轴方向,如果小鸟的x坐标与水管x坐标之间的水平距离小于水管中心点到管道左右边缘的距离+小鸟身体宽度的一半,那么小鸟就已经越过管的左测边缘,此时还不能确定一定和水管碰撞,还要看垂直方向。

2、在y轴方向,看小鸟是否与水管上下边缘碰撞。水管的y坐标到小鸟的y坐标的垂直距离要小于间隙距离的一半再减去小鸟自己身体的高度一半。

由于实际角色中心位置存在一定偏差,所以要根据实际情况做调整。比如本例中我水管的中心点离空隙中心偏高了30像素,所以pipe.getY() + 30才是中心位置。

现在开始编写Flappybird角色代码:

1)新增变量isalive = true表示小鸟没有碰撞

private boolean isalive = true;

2)增加一个isTouchpipe()方法,判断是否与水管碰撞,这个方法就是上面我们分析思路的具体代码实现。

//碰撞检测

public boolean isTouchpipe(){

for(Pipe pipe : getWorld().getObjects(Pipe.class)){

   if(Math.abs(pipe.getX() - getX()) < 60 ){

if(Math.abs(pipe.getY() + 30 - getY()) > 37){

   isalive = false;

}

   }

}

return !isalive;

}

3)在act方法中进行实时判断,添加如下代码:

//碰到管道游戏游戏结束

if(isTouchpipe()){

   isalive = false;

}

//碰到边缘游戏结束

if(isAtEdge()){

   isalive = false;

}

4)如果isalive = false表示小鸟已经发生碰撞,我们本节先简单通过移除小鸟角色表示游戏结束,下一节我们将继续优化。继续在上面的代码下面添加:

//游戏结束

if(!isalive){

   getWorld().removeObject(this);

}

由于本节内容比较难,也是这个游戏的核心部分,因此我们先到这里,请大家根据上面的步骤进行尝试。完整的代码截图如下:

Greenfoot制作flappybird游戏[四]