mcpField
P
physics

physics

github.com/drawcall-ai开发160 次安装
代码仓库

关于 physics

基于 BVH 的物理技能,面向使用 @pmndrs/viverse 构建交互场景的开发者。它提供静态与运动学几何体、角色控制器及传感器,并将游戏规则留给项目自行实现。

主要功能

  1. 01创建 BVH 物理世界
  2. 02添加静态和运动学刚体
  3. 03控制角色速度与冲量
  4. 04查询角色接地状态
  5. 05检测传感器进入与离开

适用场景

  1. 01为场景几何体添加碰撞
  2. 02实现角色移动与跳跃基础
  3. 03响应角色进入或离开区域

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/drawcall-ai/skills --skill physics

安装后在 Claude Code 中输入/physics确认已加载。

详细介绍

物理

使用 BVH(包围体层次结构)处理静态/运动学几何体。目前,动态刚体之间无法相互作用。

物理世界

创建物理世界

import { BvhPhysicsWorld } from '@pmndrs/viverse'

const world = new BvhPhysicsWorld()

addBody(object, kinematic) — 第二个参数表示刚体是否为运动学刚体(由脚本移动,例如平台或火车),而不是表示它是否静态。对于静态世界几何体(地面、墙壁),传入 false;对于由你自行移动的物体,传入 true。

world.addBody(ground, false) // static
world.addBody(train, true)   // kinematic (you move it each frame)

注意这两个参数的含义正好相反:addBody 的标志是 kinematic,而下面 addSensor 的第二个标志是 isStatic。

角色控制器

BvhCharacterPhysics 是角色控制器——它移动角色刚体并处理碰撞。它不会为角色制作动画,也不是摄像机。要实现完整的可操控人形角色,请将它与 CharacterCameraBehavior(摄像机)和 Acta 组合使用,由 Acta 负责所有动画及动画产生的运动(参见 acta 技能)。不要使用 SimpleCharacter——它包含自己的动画,会与 Acta 冲突。

创建角色控制器

import { BvhCharacterPhysics, type BvhCharacterPhysicsOptions } from '@pmndrs/viverse'

const characterPhysics = new BvhCharacterPhysics(world)

控制器假定角色对象的原点位于脚部(胶囊体底部)。如果模型的原点位于中心或头部,角色就会悬浮或下沉——请将它包在一个原点位于脚部的 Group 中。可通过可选的 BvhCharacterPhysicsOptions(update 的第三个参数)进行调整:capsuleRadius、capsuleHeight、gravity、maxGroundSlope、updatesPerSecond、linearDamping。

驱动角色

characterPhysics.inputVelocity.copy(velocity) // continuous (walking) — set each frame
characterPhysics.applyVelocity(jumpImpulse) // one-off impulse (e.g. jumping)

对于 Acta 角色,信息流是输入 → Acta → 物理:向 Acta 传入移动意图(相机相对的 moveDirection,长度为 0..1),Acta 会将当前动画转换为期望速度,并在其 motion 回调中将该速度传给你,然后你在回调中将该速度赋给 inputVelocity 并更新控制器。不要根据原始输入设置 inputVelocity,也不要在其他位置移动角色。参见 acta 技能。

更新控制器

设置速度后,每帧调用:

characterPhysics.update(character, delta) // pass a BvhCharacterPhysicsOptions third arg to tune
接地状态
characterPhysics.isGrounded // true when character is on the ground
控制器不会做的事——请自行实现

控制器只提供两个基本操作——inputVelocity(连续作用)和 applyVelocity(冲量)——以及 isGrounded。具体游戏叠加的规则需要由你编写:

  • **多段跳 / 二段跳、土狼时间、跳跃缓冲:**控制器没有跳跃计数器——只有在 isGrounded 为真时才允许首次调用 applyVelocity,自行记录空中跳跃次数,并在接地时重置。
  • 蹬墙跳 / 滑墙:isGrounded 只报告是否接地,不检测墙壁。使用胶囊体发出水平的 world.raycast(ray, far) 来检测墙壁——返回的交点包含命中距离和表面法线——然后调用 applyVelocity,施加远离墙壁并向上的速度。
  • **随移动平台移动:**站在运动学平台上不会让角色随之移动。角色站在平台上时,需要自行将平台每帧的位移增量加到角色身上。
  • **掉出世界 / 越界:**只有当胶囊体向下进行形状投射并命中碰撞几何体时,isGrounded 才为真——越过有限地面网格的边缘后就没有东西可命中,因此角色会无限下落,并卡在空中/下落姿势(通常看起来像意外的“飞行”或滑翔状态)。控制器不会阻止这种情况。请自行让玩家留在坚实地面上:将位置限制在可碰撞区域内,添加越界地板平面或触发重生的死亡屏障,而不要假定世界是无限的。应将玩家限制在物理网格范围内,该网格可能超出可见游戏区域。

这些属于游戏玩法规则,并非缺失的功能——控制器刻意保持精简,让每款游戏都能自行调整手感。

传感器

传感器会检测角色进入或离开某个区域。

添加传感器

world.addSensor(object, isStatic, (intersected) => {
  if (intersected) {
    // character entered the sensor
  } else {
    // character exited the sensor
  }
})

移除传感器

world.removeSensor(object)

如果你更希望使用单个回调来获取角色进入的传感器对象,请按以下方式操作

function onEnter(object: Object3D) {}

world.addSensor(obj1, isStatic, (intersected) => intersected && onEnter(obj1))
world.addSensor(obj2, isStatic, (intersected) => intersected && onEnter(obj2))

评论

支持 Markdown