vehicles: a boat nobody rows is moored where it was called or left - its hull put back on the mooring (home_x, home_z, home_yaw) whenever it strays, and no wind on it; the wind drifts only a rowed boat
A called boat and one got out of drifted across the lake on the wind (the user's play of the bundle). The tests hold a boat at its berth in a full wind for eight seconds, and one dropped out on the lake where it was left. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
b2a45c2fda
commit
66da424b90
6 changed files with 64 additions and 13 deletions
|
|
@ -26,8 +26,9 @@ through the game).
|
||||||
- **A boat is a body in the game's physics** (`VehicleHull`, phase 16; a buoyant Jolt hull in Maroon
|
- **A boat is a body in the game's physics** (`VehicleHull`, phase 16; a buoyant Jolt hull in Maroon
|
||||||
Lake). The package rows it - the stick forward and back is a stroke along the bow, left and right
|
Lake). The package rows it - the stick forward and back is a stroke along the bow, left and right
|
||||||
the oars pulled against each other - and reads back where the hull is and how fast it goes. The
|
the oars pulled against each other - and reads back where the hull is and how fast it goes. The
|
||||||
water floats it, the wind (`VehicleWorld.wind`) drifts every boat, ridden or not, and the lake bed
|
water floats it, the wind (`VehicleWorld.wind`) drifts a rowed boat, and the lake bed stops it at
|
||||||
stops it at the shore; the swell at the sail limit takes the outward share of a stroke.
|
the shore. A boat nobody rows is moored where it was called or left (`home_x`, `home_z`,
|
||||||
|
`home_yaw`): its hull is put back there whenever it strays, so it never crosses the lake alone; the swell at the sail limit takes the outward share of a stroke.
|
||||||
- **A horse walks on legs in the game's physics** (`VehicleLegs`; a Jolt walker in Maroon Lake). The
|
- **A horse walks on legs in the game's physics** (`VehicleLegs`; a Jolt walker in Maroon Lake). The
|
||||||
package decides its pace - a walk, a canter on stamina, hay for every metre - and never steps it
|
package decides its pace - a walk, a canter on stamina, hay for every metre - and never steps it
|
||||||
into water; the legs meet the ground, its steps and slopes, and whatever stands in its way. What
|
into water; the legs meet the ground, its steps and slopes, and whatever stands in its way. What
|
||||||
|
|
@ -74,7 +75,7 @@ export port VehicleRider {
|
||||||
| `vehicle_mount(v) -> bool`, `vehicle_dismount() -> bool`, `vehicle_drop()` | on and off |
|
| `vehicle_mount(v) -> bool`, `vehicle_dismount() -> bool`, `vehicle_drop()` | on and off |
|
||||||
| `vehicle_update(ix, iz, run, dt)` | a frame of riding from the rider's stick (bind it where the body hands its stick over) |
|
| `vehicle_update(ix, iz, run, dt)` | a frame of riding from the rider's stick (bind it where the body hands its stick over) |
|
||||||
| `vehicle_own(v)`, `vehicle_feed(v, hay)`, `vehicle_follow(v, x, y, z, yaw)`, `vehicles_release(pid)`, `vehicle_restore(kind, owned, food)` | hiring, hay, a tied horse's wandering, a player leaving, a saved word |
|
| `vehicle_own(v)`, `vehicle_feed(v, hay)`, `vehicle_follow(v, x, y, z, yaw)`, `vehicles_release(pid)`, `vehicle_restore(kind, owned, food)` | hiring, hay, a tied horse's wandering, a player leaving, a saved word |
|
||||||
| `vehicles_tick(dt)` | every boat's hull read back and pushed by the wind (the game calls it where the world is run) |
|
| `vehicles_tick(dt)` | every boat's hull read back: a rowed one pushed by the wind, one nobody rows held at its mooring (the game calls it where the world is run) |
|
||||||
| `vehicle_facts() -> Queue<VehicleFact>` | `{ what, nid, kind, owner, x, z, v }`: `VEHICLE_MOUNTED`, `_DISMOUNTED`, `_NO_LANDING`, `_MOVED` (v: metres), `_SWELL` (every 14 s), `_HUNGRY`, `_FED` |
|
| `vehicle_facts() -> Queue<VehicleFact>` | `{ what, nid, kind, owner, x, z, v }`: `VEHICLE_MOUNTED`, `_DISMOUNTED`, `_NO_LANDING`, `_MOVED` (v: metres), `_SWELL` (every 14 s), `_HUNGRY`, `_FED` |
|
||||||
| `vehicles_reset()`, `vehicles_system() -> System` | `"vehicles"`: this player's own saved by kind (hired, hay) - where they lie is not saved |
|
| `vehicles_reset()`, `vehicles_system() -> System` | `"vehicles"`: this player's own saved by kind (hired, hay) - where they lie is not saved |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,14 @@ function ve_put(v: Vehicle, x: float, z: float) -> void {
|
||||||
v.z = z
|
v.z = z
|
||||||
v.speed = 0.0
|
v.speed = 0.0
|
||||||
if v.kind == VEHICLE_BOAT { v.y = VehicleWorld.water(x, z) + 0.02 } else { v.y = VehicleWorld.ground(x, z) }
|
if v.kind == VEHICLE_BOAT { v.y = VehicleWorld.water(x, z) + 0.02 } else { v.y = VehicleWorld.ground(x, z) }
|
||||||
v.home_x = x
|
ve_moor(v)
|
||||||
v.home_z = z
|
}
|
||||||
|
|
||||||
|
# a boat nobody rows holds here (vehicles_tick); a horse is tied here
|
||||||
|
function ve_moor(v: Vehicle) -> void {
|
||||||
|
v.home_x = v.x
|
||||||
|
v.home_z = v.z
|
||||||
|
v.home_yaw = v.yaw
|
||||||
}
|
}
|
||||||
|
|
||||||
# Bring player pid's boat or horse to place k. False when the place is somebody else's, or it is
|
# Bring player pid's boat or horse to place k. False when the place is somebody else's, or it is
|
||||||
|
|
@ -59,8 +65,8 @@ export function vehicle_call_for(vehicles_st: VehiclesState, pid: int, kind: int
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if v.rider >= 0 { return false }
|
if v.rider >= 0 { return false }
|
||||||
ve_put(v, vehicle_place_x(vehicles_st, kind, k), vehicle_place_z(vehicles_st, kind, k))
|
|
||||||
v.yaw = yaw
|
v.yaw = yaw
|
||||||
|
ve_put(v, vehicle_place_x(vehicles_st, kind, k), vehicle_place_z(vehicles_st, kind, k))
|
||||||
ve_settle(v)
|
ve_settle(v)
|
||||||
VehicleWorld.placed(v)
|
VehicleWorld.placed(v)
|
||||||
return true
|
return true
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,9 @@ export property Vehicle {
|
||||||
owned: bool = false # hired or rented for the trip
|
owned: bool = false # hired or rented for the trip
|
||||||
owner: int = 0 # the player it belongs to (0: this machine's)
|
owner: int = 0 # the player it belongs to (0: this machine's)
|
||||||
rider: int = -1 # the player on it, -1 nobody
|
rider: int = -1 # the player on it, -1 nobody
|
||||||
home_x: float = 0.0 # a horse is tied where its home is
|
home_x: float = 0.0 # a horse is tied where its home is; a boat nobody rows is moored there
|
||||||
home_z: float = 0.0
|
home_z: float = 0.0
|
||||||
|
home_yaw: float = 0.0 # and a moored boat faces as it was left
|
||||||
ent: int = -1 # its handle in the table
|
ent: int = -1 # its handle in the table
|
||||||
tab: Table<Vehicle> = null
|
tab: Table<Vehicle> = null
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ export function vehicle_dismount(vehicles_st: mut VehiclesState) -> bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
VehicleRider.step_off(VehicleRider.safe_x(), VehicleRider.safe_z())
|
VehicleRider.step_off(VehicleRider.safe_x(), VehicleRider.safe_z())
|
||||||
|
ve_moor(v)
|
||||||
} else {
|
} else {
|
||||||
let wx = v.x + Math.cos(v.yaw) * 1.2
|
let wx = v.x + Math.cos(v.yaw) * 1.2
|
||||||
let wz = v.z - Math.sin(v.yaw) * 1.2
|
let wz = v.z - Math.sin(v.yaw) * 1.2
|
||||||
|
|
@ -49,6 +50,7 @@ export function vehicle_drop(vehicles_st: mut VehiclesState) -> void {
|
||||||
if vehicles_st.ve_cur != null {
|
if vehicles_st.ve_cur != null {
|
||||||
vehicles_st.ve_cur.rider = -1
|
vehicles_st.ve_cur.rider = -1
|
||||||
vehicles_st.ve_cur.speed = 0.0
|
vehicles_st.ve_cur.speed = 0.0
|
||||||
|
if vehicles_st.ve_cur.kind == VEHICLE_BOAT { ve_moor(vehicles_st.ve_cur) }
|
||||||
}
|
}
|
||||||
vehicles_st.ve_cur = null
|
vehicles_st.ve_cur = null
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,19 +51,35 @@ function ve_swell(vehicles_st: mut VehiclesState, v: Vehicle, iz: float, dt: flo
|
||||||
return take
|
return take
|
||||||
}
|
}
|
||||||
|
|
||||||
# every boat: its hull read back, and the wind pushing it across the lake, ridden or not
|
# every boat: a rowed one pushed by the wind across the lake; one nobody rows moored where it was
|
||||||
|
# called or left, its hull read back and held there
|
||||||
export function vehicles_tick(vehicles_st: VehiclesState, dt: float) -> void {
|
export function vehicles_tick(vehicles_st: VehiclesState, dt: float) -> void {
|
||||||
let l = ve_all(vehicles_st)
|
let l = ve_all(vehicles_st)
|
||||||
let w = VehicleWorld.wind() * VE_WIND
|
let w = VehicleWorld.wind() * VE_WIND
|
||||||
let wy = VehicleWorld.wind_yaw()
|
let wy = VehicleWorld.wind_yaw()
|
||||||
for i in 0 .. len(l) {
|
for i in 0 .. len(l) {
|
||||||
let v = l[i]
|
let v = l[i]
|
||||||
if v.kind == VEHICLE_BOAT {
|
if v.kind != VEHICLE_BOAT { continue }
|
||||||
|
if v.rider >= 0 {
|
||||||
if w > 0.0 { VehicleHull.drift(v.nid, -Math.sin(wy) * w, -Math.cos(wy) * w) }
|
if w > 0.0 { VehicleHull.drift(v.nid, -Math.sin(wy) * w, -Math.cos(wy) * w) }
|
||||||
if v.rider < 0 {
|
continue
|
||||||
ve_hull_read(v)
|
|
||||||
VehicleWorld.placed(v)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
ve_hull_read(v)
|
||||||
|
ve_hold(v)
|
||||||
|
VehicleWorld.placed(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# a moored hull that has moved off its mooring (a knock, the swell) is put back on it, at rest
|
||||||
|
function ve_hold(v: Vehicle) -> void {
|
||||||
|
let dx = v.x - v.home_x
|
||||||
|
let dz = v.z - v.home_z
|
||||||
|
let dyaw = Math.abs(Math.atan2(Math.sin(v.yaw - v.home_yaw), Math.cos(v.yaw - v.home_yaw)))
|
||||||
|
if dx * dx + dz * dz < 0.0004 and dyaw < 0.01 and Math.abs(v.speed) < 0.01 { return }
|
||||||
|
v.x = v.home_x
|
||||||
|
v.z = v.home_z
|
||||||
|
v.yaw = v.home_yaw
|
||||||
|
v.y = VehicleWorld.water(v.x, v.z) + 0.02
|
||||||
|
v.speed = 0.0
|
||||||
|
VehicleHull.put(v.nid, v.x, v.y, v.z, v.yaw)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -309,6 +309,31 @@ program VehiclesTest {
|
||||||
expect(b.z < z0 - 0.2)
|
expect(b.z < z0 - 0.2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "a boat nobody rows holds its berth in a wind, and one left out on the lake holds where it was left" (physics_st: mut PhysicsState, vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
|
||||||
|
fresh(vehicles_st, vehicles_test_st)
|
||||||
|
vehicle_call_for(vehicles_st, 0, VEHICLE_BOAT, 0)
|
||||||
|
let b = vehicle_find(vehicles_st, VEHICLE_BOAT)
|
||||||
|
let bx = b.x
|
||||||
|
let bz = b.z
|
||||||
|
vehicles_test_st.wind = 1.0
|
||||||
|
ride(physics_st, vehicles_st, 0.0, 0.0, false, 8.0)
|
||||||
|
expect_near(b.x, bx, 0.2)
|
||||||
|
expect_near(b.z, bz, 0.2)
|
||||||
|
expect(vehicle_in_place(vehicles_st, VEHICLE_BOAT, 0) != null)
|
||||||
|
vehicles_test_st.wind = 0.0
|
||||||
|
vehicle_mount(vehicles_st, b)
|
||||||
|
ride(physics_st, vehicles_st, 0.0, 1.0, false, 4.0)
|
||||||
|
vehicle_drop(vehicles_st)
|
||||||
|
let lx = b.x
|
||||||
|
let lz = b.z
|
||||||
|
expect(lx > bx + 4.0)
|
||||||
|
vehicles_test_st.wind = 1.0
|
||||||
|
ride(physics_st, vehicles_st, 0.0, 0.0, false, 8.0)
|
||||||
|
expect_near(b.x, lx, 0.2)
|
||||||
|
expect_near(b.z, lz, 0.2)
|
||||||
|
expect(Math.abs(b.speed) < 0.05)
|
||||||
|
}
|
||||||
|
|
||||||
function char_turn(a: float) -> float {
|
function char_turn(a: float) -> float {
|
||||||
var d = a
|
var d = a
|
||||||
while d > 3.14159265 { d -= 6.2831853 }
|
while d > 3.14159265 { d -= 6.2831853 }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue