载入中...
搜索中...
未找到
物理模块(Box2D + Box3D + 布料 + 流体)

物理模块(Box2D + Box3D + 布料 + 流体)

脚本入口: eve.Physics()

创建 World、Body、Fixture(Box2D 2D 刚体)、World3D / Body3D / Shape3D(Box3D 3D 刚体),以及可交互的 Cloth(Verlet 布料)与 Fluid(2D 粒子流体)。2D 脚本使用像素坐标并按 meter 换算;3D 使用米(Box3D 原生单位);布料/流体直接在像素空间模拟。

基本用法

刚体(Box2D,2D)

local physics = eve.Physics();
physics.setMeter(30.0);
local world = physics.newWorld(0, 980, true);
local body = world.newBody("dynamic", 100, 60);
body.newRectangleFixture(32, 32, 1.0, 0.3, 0.1);
world.update(dt);

刚体(Box3D,3D)

local physics = eve.Physics();
local world3 = physics.newWorld3D(0, -9.8, 0, true); // 米 / s²,+Y 向上
local ground = world3.newBody("static", 0, -1, 0);
ground.newBoxShape(20, 2, 20, 0.0, 0.5, 0.0); // 全尺寸宽高深(米)
local box = world3.newBody("dynamic", 0, 4, 0);
box.newBoxShape(1, 1, 1, 1.0, 0.3, 0.1);
box.newSphereShape(0.5, 1.0); // 或球体
box.newCapsuleShape(1.0, 0.25, 1.0); // 或胶囊(沿局部 Y)
world3.update(dt);
// 姿态用四元数:box.setRotation(qx, qy, qz, qw); box.getRotX/Y/Z/W()

布料

local cloth = physics.newCloth(18, 12, 14.0, 48.0, 36.0); // cols, rows, spacing, origin
cloth.setGravity(0, 980);
cloth.setBounds(0, 0, 800, 600);
cloth.setStiffness(0.9);
// 鼠标拖拽
local idx = cloth.grabAt(mx, my, 28.0);
if (idx >= 0) cloth.moveGrab(mx, my);
else cloth.releaseGrab();
cloth.update(dt);
cloth.draw(gfx);

流体

local fluid = physics.newFluid(600);
fluid.setBounds(400, 48, 360, 500);
fluid.setGravity(0, 980);
fluid.emit(520, 100, 120, 0, 40); // x, y, count, vx, vy
fluid.interactAt(mx, my, 70.0, -4200.0); // 负值排斥,正值吸引
fluid.update(dt);
fluid.draw(gfx);

示例:examples/softbody/

对象关系与调用时机

Physics 保存 2D 像素/米比例并创建 World / World3D / Cloth / Fluid。World 管理 Body;Body 管理 Fixture。World3D 管理 Body3D;Body3D 管理 Shape3D。布料与流体独立于刚体世界,可同屏并存。2D 碰撞消息为 begincontact / endcontact;3D 为 begincontact3d / endcontact3d(参数均为 body id)。查询 API(rayCastqueryAABB)结果对应**上一次查询**写入的缓存。

每帧:world.update / world3.update / cloth.update / fluid.update 各调用一次;绘制在 eve_render 中用 draw / drawDebug

目标导向指南

创建会落地的角色(2D)

  1. setMeter(30) 定义像素与米的比例。
  2. 创建向下重力的 World。
  3. 地面用 static Body,角色用 dynamic Body。
  4. 给 Body 创建矩形或圆形 Fixture,配置密度、摩擦和弹性。
  5. 每帧只调用一次 world.update(dt),渲染位置从 body.getX/Y() 读取。

创建会落地的物体(3D)

  1. newWorld3D(0, -9.8, 0):坐标与重力均以米为单位。
  2. 地面 static + newBoxShape;动态体用 box / sphere / capsule。
  3. 每帧 world3.update(dt);位置 getX/Y/Z,姿态四元数 getRotX/Y/Z/W
  4. 拾取:shape.testPoint(x,y,z)world3.rayCastworld3.queryAABB(min…, max…)

制作触发区域

把 Fixture / Shape3D 设为 sensor,监听 begincontact / endcontact(2D)或 begincontact3d / endcontact3d(3D);sensor 不产生碰撞推力,适合传送门、拾取物和区域检测。调试时调用 world.drawDebug(gfx) 核对 2D 形状。

物理体拾取与视线

  • fixture.testPoint(x, y) / shape3.testPoint(x, y, z) — 点是否在形状内
  • world.rayCast / world3.rayCast — 段上最近命中,返回 body id(未命中 -1
  • world.queryAABB(x, y, w, h) — 2D 轴对齐盒(原点+宽高)
  • world3.queryAABB(minX, minY, minZ, maxX, maxY, maxZ) — 3D AABB(角点)

可交互布料

  1. newCloth(cols, rows, spacing, originX, originY) — 默认钉住顶行。
  2. setBounds 限制摆动范围;applyForce 可作风场。
  3. grabAt / moveGrab / releaseGrab 做鼠标拖拽;pin / unpin 控制固定点。
  4. draw(gfx) 绘制约束网与质点。

可交互流体

  1. newFluid(capacity)setBounds 建容器。
  2. emit 喷射粒子;interactAt 做吸引/排斥搅拌。
  3. 可调 setSmoothingRadius / setRestDensity / setPressureStiffness / setViscosity
  4. draw(gfx) 按密度着色绘制粒子。

常见问题

  • 每帧改变 meter:会破坏 2D 单位一致性,应启动时设置一次;3D 世界不受 setMeter 影响。
  • 直接把 Body 坐标当左上角:Box2D / Box3D Body 通常表示形状中心。
  • 更新 World 多次或完全不更新:每个逻辑帧一次。
  • rayCast / queryAABB 结果会被下次同类查询覆盖;需要时立刻读出。
  • 布料/流体粒子过多会占 CPU:演示规模建议布料 ≤ 20×15、流体 ≤ 600。
  • 布料与流体**不会**自动与刚体碰撞;需要时用 bounds / 采样位置自行耦合。
  • 3D 物体尺寸建议贴近真实尺度(约 0.1–10 m);过大过小会降低求解稳定性。

API 快查

下列方法名来自当前 Squirrel 绑定;同一模块创建的辅助对象(例如 WorldBodyWorld3DBody3DClothFluid)的方法也列在这里。

  • applyAngularImpulse()applyForce()applyForceAt()applyLinearImpulse()clear()clearBounds()destroy()destroyBody()
  • draw()drawDebug()emit()getAngle()getAngularVelocity()getAngularVelocityX()getAngularVelocityY()getAngularVelocityZ()getBody()getCapacity()getCols()
  • getDamping()getDensity()getFriction()getGrabIndex()getGravityX()getGravityY()getGravityZ()getId()getIterations()
  • getLinearVelocityX()getLinearVelocityY()getLinearVelocityZ()getMeter()getName()getNearPressureStiffness()getParticleCount()getParticleSize()getParticleVx()
  • getParticleVy()getParticleX()getParticleY()getPressureStiffness()getQueryBodyId()getQueryCount()getRayHitBodyId()getRayHitFraction()
  • getRayHitNormalX()getRayHitNormalY()getRayHitNormalZ()getRayHitX()getRayHitY()getRayHitZ()getRestDensity()getRestitution()getRotW()getRotX()getRotY()getRotZ()getRows()getSmoothingRadius()
  • getSpacing()getStiffness()getType()getViscosity()getX()getY()getZ()grabAt()hasRayHit()
  • interactAt()isActive()isAwake()isBullet()isFixedRotation()isGrabbing()isPinned()isSensor()
  • moveGrab()newBody()newBoxShape()newCapsuleShape()newCircleFixture()newCloth()newFluid()newRectangleFixture()newSphereShape()newWorld()newWorld3D()pin()
  • pinTopRow()queryAABB()rayCast()releaseGrab()setActive()setAngle()setAngularVelocity()setAwake()
  • setBounds()setBullet()setColor()setDamping()setDensity()setFixedRotation()setFriction()setGravity()
  • setIterations()setLinearVelocity()setMeter()setNearPressureStiffness()setParticlePosition()setParticleSize()setPosition()setPressureStiffness()
  • setRestDensity()setRestitution()setRotation()setSensor()setSmoothingRadius()setStiffness()setType()setViscosity()testPoint()
  • unpin()update()updateFull()

使用要点

  • 模块对象和它创建的资源对象应保存在全局或实体状态中,不要在每帧重复创建。
  • update(dt) 的系统应在 eve_update 调用;绘制方法应在 eve_render 调用。
  • 参数约束、默认值和返回类型以对应模块头文件及 addFunc 绑定为准;本文 API 快查与当前源码同步生成。

源码: src/modules/physics/ 相关测试: test/box2d.cpptest/box3d.cpptest/softbody.cpp