feat(physics): a walker (Jolt CharacterVirtual with an inner body) and the verbs a boat and a guest's copy need - force, torque, angular impulse, spin, set_pose
Five new tests: stand and walk at the asked speed, a low stone is a step and a tall one a wall, a jump up and back, a crate shoved aside, a hull turned by a torque and carried by a force. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
b44b88e00e
commit
c7a18fd4f0
12 changed files with 334 additions and 2 deletions
104
packages/ludic.physics/tests/walker_test.ludic
Normal file
104
packages/ludic.physics/tests/walker_test.ludic
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# walker_test.ludic - a walker on the real Jolt: it stands, walks, steps onto a low stone, is held
|
||||
# by a tall one, jumps and lands, shoves a crate aside; and a boat-shaped body turns under a torque
|
||||
import "ludic.physics"
|
||||
import "ludic.base"
|
||||
program WalkerTest {
|
||||
numbers float
|
||||
|
||||
function flat(physics_st: mut PhysicsState) -> void {
|
||||
expect(phys_open(physics_st, 1024, 1))
|
||||
let h = floats(64 * 64)
|
||||
for i in 0 .. 64 * 64 { h[i] = 0.0 }
|
||||
phys_ground_add(physics_st, phys_heightfield(physics_st, h, 64, -32.0, -32.0, 1.0))
|
||||
}
|
||||
|
||||
function walk(physics_st: mut PhysicsState, id: int, seconds: float, vx: float, vz: float) -> void {
|
||||
for i in 0 .. int(seconds * 60.0) { phys_walker_step(physics_st, id, 1.0 / 60.0, vx, vz, 0.0) }
|
||||
}
|
||||
|
||||
test "a walker falls to the ground, stands, and walks at the speed it asks" (physics_st: mut PhysicsState) {
|
||||
flat(physics_st)
|
||||
let me = phys_walker_add(physics_st, 0.35, 1.8, 0.0, 1.0, 0.0, 50.0, 70.0)
|
||||
walk(physics_st, me, 1.0, 0.0, 0.0)
|
||||
let p = phys_walker_pose(physics_st, me)
|
||||
expect_eq(p.ground, PHYS_ON_GROUND)
|
||||
expect(Math.abs(p.y) < 0.05)
|
||||
walk(physics_st, me, 2.0, 3.0, 0.0)
|
||||
let q = phys_walker_pose(physics_st, me)
|
||||
expect(Math.abs(q.x - 6.0) < 0.2)
|
||||
expect(q.body >= 0)
|
||||
phys_close(physics_st)
|
||||
}
|
||||
|
||||
test "a low stone is a step, a tall one is a wall" (physics_st: mut PhysicsState) {
|
||||
flat(physics_st)
|
||||
let stone = phys_offset(physics_st, phys_box(physics_st, 1.0, 0.15, 3.0), 0.0, 0.15, 0.0, 0.0)
|
||||
phys_static_add(physics_st, stone, 3.0, 0.0, 0.0, 0.0)
|
||||
let wall = phys_offset(physics_st, phys_box(physics_st, 1.0, 1.5, 3.0), 0.0, 1.5, 0.0, 0.0)
|
||||
phys_static_add(physics_st, wall, 3.0, 0.0, 10.0, 0.0)
|
||||
phys_settle(physics_st)
|
||||
let a = phys_walker_add(physics_st, 0.35, 1.8, 0.0, 0.0, 0.0, 50.0, 70.0)
|
||||
phys_walker_limits(physics_st, a, 0.55, 0.5)
|
||||
walk(physics_st, a, 1.5, 2.0, 0.0)
|
||||
let pa = phys_walker_pose(physics_st, a)
|
||||
expect(pa.x > 2.5)
|
||||
expect(Math.abs(pa.y - 0.3) < 0.05)
|
||||
let b = phys_walker_add(physics_st, 0.35, 1.8, 0.0, 0.0, 10.0, 50.0, 70.0)
|
||||
walk(physics_st, b, 2.0, 2.0, 0.0)
|
||||
let pb = phys_walker_pose(physics_st, b)
|
||||
expect(pb.x < 1.7)
|
||||
expect(Math.abs(pb.y) < 0.05)
|
||||
phys_close(physics_st)
|
||||
}
|
||||
|
||||
test "a jump leaves the ground and comes back down" (physics_st: mut PhysicsState) {
|
||||
flat(physics_st)
|
||||
let me = phys_walker_add(physics_st, 0.35, 1.8, 0.0, 0.0, 0.0, 50.0, 70.0)
|
||||
walk(physics_st, me, 0.5, 0.0, 0.0)
|
||||
phys_walker_step(physics_st, me, 1.0 / 60.0, 0.0, 0.0, 5.0)
|
||||
walk(physics_st, me, 0.25, 0.0, 0.0)
|
||||
let up = phys_walker_pose(physics_st, me)
|
||||
expect_eq(up.ground, PHYS_IN_AIR)
|
||||
expect(up.y > 0.5)
|
||||
walk(physics_st, me, 1.5, 0.0, 0.0)
|
||||
let down = phys_walker_pose(physics_st, me)
|
||||
expect_eq(down.ground, PHYS_ON_GROUND)
|
||||
expect(Math.abs(down.y) < 0.05)
|
||||
phys_close(physics_st)
|
||||
}
|
||||
|
||||
test "walking into a crate shoves it, and a placed walker stands where it was put" (physics_st: mut PhysicsState) {
|
||||
flat(physics_st)
|
||||
let crate = phys_body_add(physics_st, phys_box(physics_st, 0.25, 0.25, 0.25), 2.0, 0.25, 0.0, 0.0, 4.0)
|
||||
let me = phys_walker_add(physics_st, 0.35, 1.8, 0.0, 0.0, 0.0, 50.0, 70.0)
|
||||
for i in 0 .. 150 {
|
||||
phys_walker_step(physics_st, me, 1.0 / 60.0, 2.0, 0.0, 0.0)
|
||||
phys_step(physics_st)
|
||||
}
|
||||
expect(phys_pose(physics_st, crate).x > 2.5)
|
||||
phys_walker_place(physics_st, me, -10.0, 0.0, -10.0)
|
||||
let p = phys_walker_pose(physics_st, me)
|
||||
expect(Math.abs(p.x + 10.0) < 0.01)
|
||||
phys_walker_remove(physics_st, me)
|
||||
expect(phys_walker_pose(physics_st, me) == null)
|
||||
phys_close(physics_st)
|
||||
}
|
||||
|
||||
test "a torque turns a body and a force carries it" (physics_st: mut PhysicsState) {
|
||||
expect(phys_open(physics_st, 64, 1))
|
||||
phys_gravity(physics_st, 0.0)
|
||||
let hull = phys_body_add(physics_st, phys_box(physics_st, 0.6, 0.2, 1.8), 0.0, 0.0, 0.0, 0.0, 120.0)
|
||||
for i in 0 .. 60 {
|
||||
phys_torque(physics_st, hull, 0.0, 200.0, 0.0)
|
||||
phys_force(physics_st, hull, 0.0, 0.0, 240.0)
|
||||
phys_step(physics_st)
|
||||
}
|
||||
expect(phys_spin_y(physics_st, hull) > 0.1)
|
||||
expect(phys_pose(physics_st, hull).z > 0.5)
|
||||
let p = phys_pose(physics_st, hull)
|
||||
p.x = 5.0
|
||||
phys_set_pose(physics_st, hull, p)
|
||||
expect(Math.abs(phys_pose(physics_st, hull).x - 5.0) < 0.01)
|
||||
phys_close(physics_st)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue