反弹的墙壁
本篇是 Gamedev Canvas tutorial 10 节教程中的第三节。如果你完成了本篇教程之后,你可以从 Gamedev-Canvas-workshop/lesson3.html 看到源码。
看到我们的球动起来很惊讶吧,但是它很快就从屏幕上消失了,当然我们是可以控制它的。我们会实现一些非常简单的碰撞检测 (详细后面解释),使球在画布的四周反弹回来。
简单的碰撞
我们将检查球体是否与边缘接触,如果有接触我们将相应的改变它的运动方向。
为了运算方便我们定义一个名为 ballRadius 的变量,来存储球的半径。向代码中添加一下内容:
var ballRadius = 10;
现在更新绘制球的 drawBall() 函数:
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
从顶部和底部弹起
有四面墙壁可以让它反弹回来,我们先来看上面的那面墙。我们需要判断球运动的每一帧,球体是否与画布的顶部边缘接触。如果有接触,我们将会改变球体的运动方向,使它向相反的方向移动,并保证它在画布的可见范围之内。记住坐标系统的左上角,让我们开始并加以下代码:
if (y + dy < 0) {
dy = -dy;
}
如果球的纵坐标(y 轴)值小于零,我们将在球体原有的运动方向上逆转。如果球体向上移动的速度是 2 像素/帧,现在就是向上移动速度是 -2 像素。这相当于此时向下移动的速度是 2 像素/帧。
上面的代码将处理球与画布顶部边缘的反射,现在让我们思考一下底部边缘如何处理:
if (y + dy > canvas.height) {
dy = -dy;
}
如果球的 y 位置大于canvas
的高度(记住,我们从左上角计算 y 值,所以顶部边缘从 0 开始,底部边缘在 480 像素),然后通过像以前那样反转 y 轴运动而离开底部边缘。
我们可以将这两句冗长的代码合二为一:
if (y + dy > canvas.height || y + dy < 0) {
dy = -dy;
}
如果其中一个判断为 true
, 则反转球的运动。
从左边和右边反弹
我们有顶部和底部的边缘,所以我们来考虑一下左边和右边的边缘。实际上非常相似,你所要做的就是颠倒x
而不是y
:
if (x + dx > canvas.width || x + dx < 0) {
dx = -dx;
}
if (y + dy > canvas.height || y + dy < 0) {
dy = -dy;
}
你应该把上面的代码块插入到 draw()函数中,就在大括号之前。
球部分消失在墙上!
测试你的代码,你会看到我们的球碰到任一边缘都会反弹!然而,我们还发现了一个问题,当球碰撞到边缘,反弹之前:
这是因为我们正在计算墙和球的中心碰撞点,而我们应该围绕它的周长来做。如果碰到墙壁,球应该会弹起来,而不是陷入墙壁一半时,所以让我们来调整一下我们的判断条件。更新你之前添加的代码:
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if (y + dy > canvas.height - ballRadius || y + dy < ballRadius) {
dy = -dy;
}
当球的中心到墙的边缘之间的距离与球的半径完全相同时,它将改变运动的方向。
比较你的代码
让我们再次检查这个部分的代码与你之间有何差异:
备注:尝试修改你的代码,在每次碰到墙壁时都要把球的颜色改成随机的颜色。
下一步
现在我们已经到了我们的球正在移动和留在游戏板上的阶段。在第四章中,我们将看看如何实现一个可控制的 paddle - 参见paddle 和键盘控制。