You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

俯视2D弹球游戏Paddle碰撞物理优化技术问询

俯视视角2D弹球游戏Paddle碰撞逻辑问题

已实现基础墙体碰撞与缓冲器功能,但Paddle(弹板)碰撞逻辑存在问题,具体场景与可获取信息如下:

  • 球体按碰撞步移动;Paddle具备随按键长按递增的旋转加速度,每帧更新
  • Paddle由绕枢轴旋转的多对象组成,球体与任一对象碰撞即判定为Paddle碰撞
  • 碰撞时可获取以下信息:
    1. 球体速度(包含x/y坐标分量,以及长度+方向组合,单位均为单位/帧)
    2. Paddle旋转加速度(单位:°/帧)
    3. 碰撞点法线
    4. 球体碰撞位置
  • 可轻松计算碰撞点距枢轴距离等额外信息,但始终未能找到碰撞后球体速度的合适计算公式
  • 开发基于旧版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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 10:24:53