背景需求

  • 我们的应用包含一个可在屏幕中自由拖拽的悬浮球。
  • 需求:松手后沿松手方向继续滑动,速度递减;撞到边缘需按物理直觉反弹并逐渐停下。
  • 注意点:
    • 方向与松手时方向一致
    • 速度连续递减,且可通过阻尼控制“滑行距离/停下时间”
    • 撞墙沿法向反弹

实现分析

阶段拆分

  1. 拖拽阶段:采样 (t, x, y) → 加权最小二乘回归 → 估计松手初速。
  1. 惯性阶段:线性阻尼解析更新 + 刚性边界碰撞(法向恢复+切向摩擦)+ 单帧多次碰撞分段推进。
  1. 全流程边界夹取:startDrag / dragMove / 每帧同步 时均做 clamp,避免越界闪跳。

实现步骤

  1. startDrag
      • 停止惯性;
      • 重置速度估计器;
      • 初始坐标 clamp;
      • 同步浮点位置与零速。
  1. dragMove
      • 对输入坐标先 clamp;
      • 更新 UI;
      • 记录样本(纳秒时间、被夹取的位置);
      • 同步浮点位置。
  1. dragEnd
      • 使用加权最小二乘估计释放速度(超小则直接结束);
      • 进入惯性模拟。
  1. 帧循环(Choreographer)
      • 计算步长 h;
      • 调用 stepPhysics(h);
      • 将浮点坐标转整型后 clamp 再更新 UI;
      • 若速度低于阈值结束。

速度估计器原理(VelocityEstimator)

从直觉到公式:初始速度估计

  • 两点差分:,无偏但对噪声敏感;
  • 多点平均差分:降噪但对“释放瞬间”不敏感,易滞后;
  • 最小二乘直线拟合:窗口内 ,斜率 v 即速度;
  • 加权最小二乘:使用 强调临近样本,既抗噪又敏捷,最贴近松手时刻的局部导数。
示例(一维 x,采样周期约 16ms,最新样本在 t=0ms):
  • 样本:
  • 两点差分:
  • 多点平均差分:
  • 最小二乘(OLS):在上述 4 点上拟合直线,斜率v约介于 750 与 1000 之间,
  • 加权最小二乘(WLS):对越近样本赋更大权重,结果接近 750–850 px/s,,更贴近“释放瞬间”的局部速度。

采样模型

速度定义:

加权回归公式

,权重
,权重总和
,权重 × 时间
,权重 × 时间平方
,权重 × x 坐标
,权重 × 时间 × x 坐标
,权重 × 时间 × y 坐标
,权重 × y 坐标
,X方向速度
,Y方向速度
实现细节:
  • 时间改为相对时间 降低病态;
  • 分母近零回退为最近两点差分;
  • 窗口约 200ms;
  • 最多使用12个样本,并按进行最大甩动速度裁剪。

核心代码 - 速度估计器


惯性物理模拟

线性空气阻尼

离散步: 实现参数:linearDampingPerSecond = 2.0f(可调范围 1.5–4.0 建议按手感标定)。

边界碰撞(法向恢复 + 切向摩擦)

  • 法向:
  • 切向:

单帧多次碰撞与命中时间

候选命中比例: 推进到碰撞点 → 执行反弹 → 用剩余时间继续推进;限制 maxSubStepsPerFrame 以避免极端震荡。

稳定性措施

  • maxDeltaTimePerFrameSeconds 限制步长;
  • scaledMinimumFlingVelocity 作为停机阈值;
  • 所有入口 clamp,避免越界积累。

核心代码 - 惯性模拟

核心代码 - 碰撞反弹

边界与越界处理(Clamp 策略)

  • startDrag:初始坐标 clamp 并同步;
  • dragMove:先 clamp 再记样本,样本位置与显示一致;
  • 帧同步:浮点转整后再次 clamp;
  • 作用:消除“手指出屏 → 坐标突变 → UI 闪跳”的链路风险。

参数与默认值(Tuning)

  • linearDampingPerSecond(默认 2.0):越大越“粘”,停得更快;
  • restitution(默认 0.65):越小损耗越大,反弹更弱;
  • wallFriction(默认 0.10):贴边滑动的衰减;
  • maxDeltaTimePerFrameSeconds(默认 1/60s):单步上限;
  • maxSubStepsPerFrame(默认 4):单帧最多碰撞数;
  • 估计器:
    • 窗口 200ms
    • =60ms
    • 采样数:12
    • 速度裁剪上限:平台最大甩动速度

集成与调用(API)

  • 关键类:FloatingBallPhysicsController
  • 必要输入:
    • mFloatingSafetyArea:允许范围(确保整个球可见)
    • mUpdatePosition(x,y):将计算坐标应用到 UI/WM
  • 典型接入:
  • 监听:MovementListener 可观测拖拽开始/移动/结束、模拟开始/结束

常见问题与调优指引

  • 惯性过短/过长:调 linearDampingPerSecond
  • 反弹太“硬”/太“软”:调 restitution
  • 贴边滑太久:增大 wallFriction
  • 初速过敏/过钝:
    • 减小/增大 、窗口
    • 或增/减最大样本数

符号表

  • :位置
  • :速度
  • :步长
  • :阻尼
  • :恢复系数
  • :切向摩擦
  • :权重时间常数
  • min/max:安全区边界;clamp:区间夹取;S, S_t, ...:加权回归求和量
Note重构——数据驱动Setting模块开发记录——截图耗时优化
Loading...