俯视2D弹球游戏Paddle碰撞物理优化技术问询
俯视视角2D弹球游戏Paddle碰撞逻辑问题
已实现基础墙体碰撞与缓冲器功能,但Paddle(弹板)碰撞逻辑存在问题,具体场景与可获取信息如下:
- 球体按碰撞步移动;Paddle具备随按键长按递增的旋转加速度,每帧更新
- Paddle由绕枢轴旋转的多对象组成,球体与任一对象碰撞即判定为Paddle碰撞
- 碰撞时可获取以下信息:
- 球体速度(包含x/y坐标分量,以及长度+方向组合,单位均为单位/帧)
- Paddle旋转加速度(单位:°/帧)
- 碰撞点法线
- 球体碰撞位置
- 可轻松计算碰撞点距枢轴距离等额外信息,但始终未能找到碰撞后球体速度的合适计算公式
- 开发基于旧版GML,需手动实现物理逻辑,无法使用引擎内置碰撞功能
球体移动更新代码
var _list = ds_list_create(); paddles = []; repeat movement_steps{ var _i = 0; var _num = instance_place_list(round(x), round(y), obj_stage_article_platform, _list, true); _i = 0; if _num repeat(_num){ var _obj = _list[|_i]; wall_bounce(_obj.normal, _obj.rebound_coeff, _obj); _i++; } ds_list_clear(_list); if abs(hspd) < 0.1 hspd = 0; if abs(vspd) < 0.1 vspd = 0; x += hspd/movement_steps; y += vspd/movement_steps; } ds_list_destroy(_list); if abs(vspd) < .1 vspd = 0;
墙体反弹及Paddle碰撞处理函数(case 2为Paddle碰撞逻辑)
#define wall_bounce(_wall_normal, _rebound, _wall) spd = point_distance(0, 0, hspd, vspd); if _wall.num == 3 _wall_normal = point_direction(_wall.x, _wall.y, x-lengthdir_x(spd, dir), y-lengthdir_y(spd, dir)); switch _wall.type{ case 0: if abs(angle_difference(dir, _wall_normal)) <= 90 return; dir = _wall_normal - angle_difference(dir, _wall_normal) + 180; hspd = lengthdir_x(spd, dir) - lengthdir_x((1-_rebound)*spd, _wall_normal); vspd = lengthdir_y(spd, dir) - lengthdir_y((1-_rebound)*spd, _wall_normal); break; case 1: if abs(angle_difference(dir, _wall_normal)) <= 90 return; var _p1 = [_wall.x, _wall.y]; var _p2 = [_wall.x + lengthdir_x(_wall.image_xscale, _wall.normal-90), _wall.y + lengthdir_y(_wall.image_xscale, _wall.normal-90)]; var _phit = point_on_line(_p1, _p2, [x, y]); var _ds_max = point_distance(_p1[0], _p1[1], _p2[0], _p2[1])/2; var _ds = point_distance(_phit[0], _phit[1], (_p1[0] + _p2[0])/2, (_p1[1] + _p2[1])/2); var _cf = max(0, dcos(90*_ds/_ds_max)) var _spd = _wall.bump_speed*_cf; hspd += lengthdir_x(_spd, _wall_normal); vspd += lengthdir_y(_spd, _wall_normal); break; case 2: var _pad = _wall.paddle; if _wall.num == "2"{ var _pad1 = _wall; var _pad2 = (_wall == _pad.parts[1][0]? _pad.parts[2][0]: _pad.parts[1][0]); var ds1 = point_on_line([_pad1.x, _pad1.y], [_pad1.x + lengthdir_x(_pad1.image_xscale, _pad1.normal-90), _pad1.y + lengthdir_y(_pad1.image_xscale, _pad1.normal-90)], [x, y]); var ds2 = point_on_line([_pad2.x, _pad2.y], [_pad2.x + lengthdir_x(_pad2.image_xscale, _pad2.normal-90), _pad2.y + lengthdir_y(_pad2.image_xscale, _pad2.normal-90)], [x, y]); if point_distance(x, y, ds1[0], ds1[1]) > point_distance(x, y, ds2[0], ds2[1]) return; } if array_find_index(paddles, _pad) return; if abs(angle_difference(dir, _wall_normal)) > 90{ dir = _wall_normal - angle_difference(dir, _wall_normal) + 180; hspd = lengthdir_x(spd, dir) - lengthdir_x((1-_rebound)*spd, _wall_normal); vspd = lengthdir_y(spd, dir) - lengthdir_y((1-_rebound)*spd, _wall_normal); } if _pad.angle_accel != 0{ var p = point_on_line([_pad.x, _pad.y], [_pad.x + lengthdir_x(_pad.padlen*_pad.dir, _pad.angle), _pad.y + lengthdir_y(_pad.padlen, _pad.angle)], [x, y]); var _spd_an = _pad.angle + 90*_pad.dir*sign(_pad.angle_accel); var _rad = clamp(point_distance(p[0], p[1], _pad.x, _pad.y)/_pad.padlen, 0, .8)*_pad.padlen; var _spd = .5*2*pi*_rad*_pad.angle_accel/360; hspd += lengthdir_x(_spd, _spd_an); vspd += lengthdir_y(_spd, _spd_an); } array_push(paddles, _pad); break; } spd = point_distance(0, 0, hspd, vspd); dir = point_direction(0, 0, hspd, vspd); while place_meeting(x, y, _wall){ x += dcos(_wall_normal); y -= dsin(_wall_normal); } x += -dcos(_wall_normal); y -= -dsin(_wall_normal); #define point_on_line(a, b, p) var ap = [p[0] - a[0], p[1] - a[1]]; var ab = [b[0] - a[0], b[1] - a[1]]; var dv = dot_product(ap[0], ap[1], ab[0], ab[1]) / dot_product(ab[0], ab[1], ab[0], ab[1]); var result = [a[0] + dv*ab[0], a[1] + dv*ab[1]]; return result
内容的提问来源于stack exchange,提问作者Dakurai
相关产品推荐
相关产品推荐

