GMS:理解碰撞基础 P1
作者:Zack bell
翻译:highway★
有问题联系我 -> zbell91@comcast.net
或者公开提问 -> http://ask.fm/ZackBellGames
碰撞基础我几乎每天都会被问到这个问题,所以我觉得应该多花点时间聊聊它。我如何实现不同角度的斜坡和更高级的碰撞特征。说实话,我认为这是很简单的碰撞检测。但是,我明白这对很多人来说并不是很直观。好在,你一旦明白是怎么回事了,那就不会再有困惑。碰撞涉及到的概念可以很容易的扩展到可跳穿的平台、移动地形等等。
1 - 首先检测坚固平坦的块状对象。基本上,玩家应该在与地面、天花板和墙壁时停下。
vx和vy变量是player的水平和垂直速度
// 垂直碰撞
repeat(abs(vy))
{
if (!place_meeting(x, y + sign(vy), oParSolid))
y += sign(vy);
else
{
vy = 0; break;
}
}
// 水平碰撞
repeat(abs(vx))
{
if (!place_meeting(x + sign(vx), y, oParSolid))
x += sign(vx);
else
{
vx = 0;
break;
}
}
上面的代码解释一下,我们就是在循环中问下面这些问题:
- 1 - 在我移动的方向(上/下)上是否有1个像素的碰撞?
- 2a - 如果没有,继续向原方向移动1个像素。
- 2b - 如果有,那重置速度(上/下),退出循环。
- 3 - 重复1。
重复这个循环,直到一个碰撞导致你跳出循环,或者你已经在循环中迭代了"vy"次。水平移动缓和跟这个一样。
2 - 接下来我们让player上下斜坡。更具体的说,斜坡就是每个step增加player的y坐标1个像素。
粗体是我们增加的代码
// 垂直碰撞
repeat(abs(vy))
{
if (!place_meeting(x, y + sign(vy), oParSolid))
y += sign(vy);
else
{
vy = 0;break;
}
}
// 水平碰撞
repeat(abs(vx))
{
// 上坡
if (place_meeting(x + sign(vx), y, oParSolid) && !place_meeting(x + sign(vx), y - 1, oParSolid))
--y;
// 下坡
if (!place_meeting(x + sign(vx), y, oParSolid) && !place_meeting(x + sign(vx), y + 1, oParSolid) && place_meeting(x + sign(vx), y + 2, oParSolid))
++y;
if (!place_meeting(x + sign(vx), y, oParSolid))
x += sign(vx);
else
{
vx = 0;break;
}
}
你会注意到,在垂直碰撞上没有任何变化。我写的初始循环会让player不会掉穿平台。但是,我对水平碰撞循环进行了两处修改,这些是为了实现上下斜坡。
// 上坡
1 - 你正在移动的方向上(左/右)是否存在碰撞 && 如果player向上移动1个像素且在该方向没有碰撞 ?
2 - 如果有碰撞,靠近斜坡并将player向上推1个像素。循环的剩余部分将搞定将player在水平方向上向斜坡移动。
// 下坡
1 - 你正在移动的方向上(左/右)是否存在碰撞 && 如果player向下移动1个像素且在该方向没有碰撞 && 如果player向下移动2个像素的话在该方向产生碰撞 ?
2 - 如果满足上面的所有条件,你就可以下坡了。
第三次检测(下移)是检测你是不是站在边缘/悬崖上。如果不是,那所有的角落都会被当作是斜坡。3 - 最后,你可能想要处理更陡的斜坡。我会展示一个斜坡示例,每个step调整player的y左边2个像素。
跟之前一样,粗体是我们增加的代码
// 垂直碰撞
repeat(abs(vy))
{
if (!place_meeting(x, y + sign(vy), oParSolid))
y += sign(vy)
;else
{
vy = 0;break;
}
}
// 水平碰撞
repeat(abs(vx))
{
//上坡
if (place_meeting(x + sign(vx), y, oParSolid) && place_meeting(x + sign(vx), y - 1, oParSolid) && !place_meeting(x + sign(vx), y - 2, oParSolid))
y -= 2;
else if (place_meeting(x + sign(vx), y, oParSolid) && !place_meeting(x + sign(vx), y - 1, oParSolid))
--y;
//下坡
if (!place_meeting(x + sign(vx), y, oParSolid) && !place_meeting(x + sign(vx), y + 1, oParSolid) && !place_meeting(x + sign(vx), y + 2, oParSolid) && place_meeting(x + sign(vx), y + 3, oParSolid))
y += 2;
else if (!place_meeting(x + sign(vx), y, oParSolid) && !place_meeting(x + sign(vx), y + 1, oParSolid) && place_meeting(x + sign(vx), y + 2, oParSolid))
++y;
if (!place_meeting(x + sign(vx), y, oParSolid))
x += sign(vx);
else
{
vx = 0;
break;
}
}
并没那么复杂,对吧~简单碰撞的关键是迭代对象的移动路径。前方是否有碰撞?如果没有,那么移动。否则,停止。
你可以试试更复杂的~ 你可能注意到了我检测2像素和1像素斜坡的方式。 你可以在内部循环中设置一个变量(比如slopeMax),并在任意陡度的斜坡上进行迭代。此外,当你上很陡的斜坡时,你可以调整player的移动速度。
thx
译注:不知道indienova这活见鬼又反人类的文字编辑工具什么时候能升级一下……代码的格式我没改,全部贴边儿,nova的编辑太麻烦了,见谅)
感谢分享,正好在寻找上下坡的方案