movement: smooth animated moves (move duration, observable intermediate positions) + proactive cruise (glide while the LLM thinks, collision-safe, reported back); verified mission with gpt-5.6-luna

This commit is contained in:
opencode
2026-08-08 21:36:32 +03:00
parent 1cb3bdc46e
commit 315762363e
6 changed files with 201 additions and 11 deletions
+38 -3
View File
@@ -85,6 +85,7 @@ class MoveOutput(BaseModel):
collision_normal: Vec3 | None
position: Vec3
tick: int
duration: float = 0.0
class TurnOutput(BaseModel):
@@ -165,6 +166,31 @@ class RoomBridge(Bridge):
def _tick(self) -> int:
return self.world.advance_tick()
async def _animate_move(
self, forward: float, duration: float
) -> tuple[float, Any | None]:
"""Smoothly displace the capsule over ``duration`` seconds.
The position advances in small timed steps, so concurrent clients
(e.g. the live viewer) observe genuine gliding motion instead of a
teleport. Collision resolution is unchanged.
"""
world = self.world
n = max(1, min(int(duration / 0.1), 200))
step = forward / n
dt = duration / n
total = 0.0
hit: Any | None = None
for i in range(n):
moved, h = world.move_forward(step)
total += moved
if h is not None or moved < step * 0.01:
hit = h
break
if i < n - 1:
await asyncio.sleep(dt)
return total, hit
def _vec3(self, x: float, y: float, z: float) -> Vec3:
return Vec3(x=round(x, 3), y=round(y, 3), z=round(z, 3))
@@ -263,13 +289,21 @@ class RoomBridge(Bridge):
@self.tool(
cls=ToolClass.ACTUATOR,
description="Move the capsule forward along its heading by the given distance in meters.",
description=(
"Move the capsule forward along its heading by the given distance in meters. "
"duration (seconds) animates the motion smoothly instead of teleporting."
),
)
async def move(forward: float = 1.0) -> MoveOutput:
async def move(forward: float = 1.0, duration: float = 0.0) -> MoveOutput:
tick = self._tick()
if forward < 0.0 or forward > 5.0:
raise ValueError(f"forward must be in [0, 5] m, got {forward}")
moved, hit = world.move_forward(forward)
if duration < 0.0 or duration > 10.0:
raise ValueError(f"duration must be in [0, 10] s, got {duration}")
if duration > 0.0:
moved, hit = await self._animate_move(forward, duration)
else:
moved, hit = world.move_forward(forward)
c = world.capsule
normal = None
if hit is not None:
@@ -294,6 +328,7 @@ class RoomBridge(Bridge):
collision_normal=normal,
position=self._vec3(c.x, 0.0, c.z),
tick=tick,
duration=round(duration, 3),
).model_dump()
@self.tool(