☰
甩出去还能在屏幕间弹来弹去?dsh-pet 拖拽抛掷物理引擎深度解析
2026/10/13 16:56:15 网站建设 项目流程
  • AI 插件
  • dsh-plugin
  • 交互助手
  • 桌面应用

【免费下载链接】dsh-pet

DSH 桌面宠物:一行命令装好即用的透明动画小桌宠,支持多开、大小位置随心配置;还内置 DIY 素材链,能用 AI 视频自造专属宠物

项目地址:https://gitcode.com/gh_mirrors/ds/dsh-pet
点击查看免费下载

dsh-pet 是一款住在 DeepSeek Harness 里的透明动画桌面宠物:除了待机呼吸、随机动作、右键点播之外,它最"上头"的玩法是把宠物拖起来用力甩出去——它会沿抛物线飞、撞屏边缘反弹、落地摩擦停稳,多显示器下甚至能跨屏弹跳。本文带你用通俗的方式看懂 dsh-pet 拖拽抛掷物理引擎背后的设计:弹簧跟手、初速估算、重力反弹与多屏穿行的实现思路,以及怎么在配置里调出最顺手的"弹感"。

🎯 弹簧跟手:为什么拖起来不抖、不飘、不"甩尾"

大多数桌宠拖拽是"鼠标到哪、宠物到哪",高频鼠标事件会让画面抖动。dsh-pet 的做法是给宠物挂一根虚拟弹簧:指针位置是弹簧的"目标",宠物位置是弹簧末端,每一帧朝目标加速追赶。

  • 弹簧刚度K = 200、阻尼C = 30,阻尼比 ζ ≈ 1.06 —— 属于过阻尼:跟得很紧但绝不冲过头(不 overshoot),所以拖快了宠物是"贴着"追上来,而不是荡出去再弹回来
  • 松手前,弹簧的"速度"就是宠物此时的速度,为下一阶段的抛掷无缝续上

相关常量定义在 physics.ts,浏览器端驱动循环见 pet.ts。

💡 过阻尼是"手感"的核心:既保留了一点弹性跟随的柔软感,又不会出现"甩一下,宠物原地画圈"的失控。

🚀 松手瞬间:初速估算如何"读懂"你的甩动

"温柔放下"和"大力甩出"的差别全在松手那 150 毫秒的鼠标轨迹里。dsh-pet 会持续记录指针轨迹(只保留最近 200ms 的窗口),松手时按下述策略估算初速:

  1. 方向:取窗口内首末两点的位移方向,天然抗抖动
  2. 大小:端点平均速度 × 50% + 窗口内分段峰值速度 × 50% 加权——快甩时位移集中在窗口一小段,只看端点会低估
  3. 加速度加成:如果末段还在加速(越甩越快),最多再放大 60%
  4. 软上限:速度按3600×(1-e^(-v/3600))软钳位——再大的力气也飞不出去,且力度始终单调可区分
  5. 死区判定:估算速度 < 500px/s 或松手前停顿了 150ms 以上 = "温柔放下",原地停住,不抛

核心函数estimateReleaseVelocity见 physics.ts,参数含义一目了然:

常量值作用
DEAD_ZONE_SPEED500 px/s低于此速度 = 放下,不抛
MAX_THROW_SPEED3600 px/s甩出速度软上限
RELEASE_WINDOW_MS150 ms初速估算窗口
RELEASE_STALE_MS150 ms停顿超过它 = 温柔放下

🏀 重力、反弹与落地:单屏内的完整抛体循环

一旦初速越过死区,宠物就进入逐帧积分:每帧加重力、位移,再检查四个边。默认手感由 config.jsonc 的physics段驱动:

  • 重力gravity = 1400px/s²:数值越大落得越快;0= 无重力,宠物甩出后匀速直线飘,永不回落
  • 恢复系数restitution = 0.78:每次碰墙/碰地保留约 78% 的速度,所以反弹一帧比一帧弱,几秒内自然衰减
  • 地面摩擦groundFriction = 2.5/s:落地后水平速度按秒衰减,宠物贴地"滑"一小段才停稳,而不是原地急刹
  • 顶部反弹ceilingBounce = true:关掉后宠物可以飞出屏幕顶部,再靠重力落回来

积分与边界反弹在 throwStep。落地还有一层"灵魂"——Q 弹挤压(squash & stretch):落地冲击速度越大,身体压得越扁(轻落最多压到 0.8 倍高,重砸压到 0.55 倍),再用带 4% 过冲的回弹曲线弹回原形,见 landingSquash / squashScale。

🖥️ 多屏弹来弹去:能"穿"屏幕,又不飞进黑洞

多显示器下有个经典难题:如果把整个桌面按"外接矩形"当边界,宠物会飞进不属于任何显示器的空洞(实测一例右倒 T 型双屏,外接矩形 23.7% 的面积是空洞)——用户直接看不到宠物去哪了。

dsh-pet 的解法在 displays.ts 和 throwStepRegion 里,思路分三层:

  1. 边界逐屏取:宠物用"身体中心所在屏"的 AABB 当边界,而不是整个桌面
  2. 越界先探测:撞到某条边时,先往缝外第一像素探一下——那边有屏就原样放行(跨屏飞行),没屏才反弹。于是"屏缝当墙"只发生在真空洞处
  3. 无状态判定:放行时不记录"当前在几号屏",每帧都由身体中心重新定位——避免了骑缝宠物在两屏边界间逐帧对跳的抖动

细节上还有个坑:任务栏会挖掉屏缝处的一条工作区条带,所以邻屏探测用的是完整面板(含任务栏区),而反弹/休息线仍按工作区——脚不踩任务栏,但身体能跨过去。多屏几何工具(点在屏上?最近是哪块屏?)都收敛在 displays.ts。

🖥️ 桌面模式(透明置顶小窗)与浏览器形态共用同一份纯函数物理,跨屏弹跳手感严格一致;不想要跨屏?把 config.jsonc 的confineToScreen设为true,屏缝即变墙,宠物只在本屏内弹。

🐾 进阶玩法:多宠物互撞与"点击积分"

多开宠物 + 抛掷引擎还能组合出更多物理玩法:

  • 多宠物碰撞(petCollision: true,默认关):飞行中的宠物撞到别的宠物,按动量守恒 + 恢复系数 0.995(近乎完全弹性)弹开,质量 ∝ 大小的平方——大宠物把小宠物撞飞得明显更猛,被撞方从落点以新初速继续抛。核心公式在 collidePet
  • 点击积分:飞行中的宠物被快速点中(速度 ≥ 400px/s),点击处爆粒子 + 弹积分卡——越快、宠物越小,分数越高(小目标更难命中,奖励更高)

⚙️ 手把手调参:把你的桌宠调得更"弹"

所有物理手感集中在physics段(全局默认,所有宠物共用),README 配置表 有完整说明:

参数默认调大的效果调小 / 关闭
gravity1400落得更快、砸得更狠0= 无重力漂浮
restitution0.78弹得更久(1= 完全弹性,永不衰减)接近0= 撞上即停
groundFriction2.5落地很快停稳0= 冰面,一直滑
throwPower1.0跟手更贴、甩得更猛< 1 = 松弛、更易温柔放下
ceilingBouncetrue—关掉 = 可飞出屏幕顶部
petCollisionfalse—开 = 宠物互撞弹开

两个入口任选:DSH 设置页「桌宠配置 → 物理」区图形化编辑(保存即时生效),或直接改$DSH_HOME/dsh-pet/main-config.jsonc后刷新。想魔改更细的弹簧刚度、软上限等内部常量,看 physics.ts 头部注释——每个常量都写清了取值依据。

📌 小结:一套纯函数,两种外壳,一种手感

dsh-pet 抛掷引擎的可读性来自一条纪律:物理是纯计算,不含任何 DOM / 定时器。同一份 physics.ts 被浏览器(React)和桌面(Electron 纯 DOM)两个渲染壳共用,移动几何在 motion.ts 里同样纯函数化——所以无论宠物住在网页里还是透明小窗中,甩出去的手感逐位一致。理解了"弹簧跟手 → 轨迹估速 → 逐屏积分 → 落地 Q 弹"这四段,你就掌握了整套拖拽抛掷物理引擎的骨架;剩下的,就是把restitution调到 0.95,看它在屏幕间弹满三遍 🏀

  • AI 插件
  • dsh-plugin
  • 交互助手
  • 桌面应用

【免费下载链接】dsh-pet

DSH 桌面宠物:一行命令装好即用的透明动画小桌宠,支持多开、大小位置随心配置;还内置 DIY 素材链,能用 AI 视频自造专属宠物

项目地址:https://gitcode.com/gh_mirrors/ds/dsh-pet
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询