diff --git a/AGRARIAN_DEVELOPMENT_ROADMAP.md b/AGRARIAN_DEVELOPMENT_ROADMAP.md index 00d55ec..f212348 100644 --- a/AGRARIAN_DEVELOPMENT_ROADMAP.md +++ b/AGRARIAN_DEVELOPMENT_ROADMAP.md @@ -373,7 +373,7 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe - [x] Implement movement. - [x] Implement sprinting. - [x] Define real-world baseline walking speed. Decision: baseline adult walking speed is `1.4 m/s` (`140 Unreal units/s`), with MVP tuning allowance up to about `1.6 m/s` for brisk walking. Movement speed does not scale with the `4 real hours = 1 in-game day` calendar. -- [ ] Define real-world baseline running speed. +- [x] Define real-world baseline running speed. Decision: sustainable adult running target is `3.0 m/s` (`300 Unreal units/s`); MVP sprint is a short burst at `5.5 m/s` (`550 Unreal units/s`) with stamina limits. Movement speed does not scale with the calendar. - [ ] Connect movement speed to age, condition, strength, endurance, hunger, thirst, injury, carried weight, and terrain. - [ ] Implement crouching if needed. - [x] Implement jumping if needed. @@ -1465,4 +1465,4 @@ Earliest incomplete foundation items: Immediate next item: -- [ ] Define real-world baseline running speed. +- [ ] Connect movement speed to age, condition, strength, endurance, hunger, thirst, injury, carried weight, and terrain. diff --git a/Docs/MovementAndTimeScaleBaseline.md b/Docs/MovementAndTimeScaleBaseline.md index c159fcf..051aa2c 100644 --- a/Docs/MovementAndTimeScaleBaseline.md +++ b/Docs/MovementAndTimeScaleBaseline.md @@ -43,6 +43,34 @@ MVP tuning allowance: - Terrain, injury, hunger, thirst, carried weight, weather, age, and endurance can reduce this baseline later. +## MVP Baseline Running Speed + +Baseline sustainable adult running speed: + +- `3.0 meters per second` +- `300 Unreal units per second` +- about `10.8 kilometers per hour` +- about `5.5 minutes` to run across a flat 1 km tile edge-to-edge + +Short sprint target: + +- `5.5 meters per second` +- `550 Unreal units per second` +- about `19.8 kilometers per hour` +- about `3 minutes` to sprint across a flat 1 km tile edge-to-edge, assuming + the character had enough stamina and no terrain/load penalties + +MVP implementation rule: + +- The current sprint input should represent a short burst, not sustainable + long-distance running. +- A later movement pass can add a separate sustainable jog/run state if the game + needs one. +- Sprint stamina cost should be high enough that a player cannot sprint across + a whole 1 km tile early in the game without rest or progression. +- Movement speed still does not scale with the `4 real hours = 1 in-game day` + calendar. + ## Relationship To The 4-Hour Day With a 4-hour day, one in-game hour lasts 10 real minutes. If a player walks for @@ -76,15 +104,14 @@ Use systems that make sense in the world: - Tune hunger, thirst, weather exposure, and stamina around real seconds and the 4-hour day instead of inflating movement speed. -## Open Follow-Up +## Future Movement Layers -The next roadmap item should define baseline running speed. That pass should -replace the current temporary sprint tuning with a realistic run/sprint model -that separates: +Later movement work should separate: - normal walking; - brisk walking; - sustainable jogging/running; - short sprinting; - stamina cost and recovery; -- injury/load/terrain modifiers. +- injury/load/terrain modifiers; +- skill, age, care history, and condition effects. diff --git a/Scripts/setup_movement_baseline.py b/Scripts/setup_movement_baseline.py new file mode 100644 index 0000000..4c37bed --- /dev/null +++ b/Scripts/setup_movement_baseline.py @@ -0,0 +1,31 @@ +import unreal + + +MOVEMENT_DEFAULTS = { + "WalkSpeed": 140.0, + "SprintSpeed": 550.0, + "SprintStaminaCostPerSecond": 28.0, + "MinSprintStamina": 5.0, +} + + +def load(path): + asset = unreal.EditorAssetLibrary.load_asset(path) + if not asset: + raise RuntimeError(f"Could not load {path}") + return asset + + +def main(): + character_bp = load("/Game/ThirdPerson/Blueprints/BP_ThirdPersonCharacter") + character_cdo = unreal.get_default_object(character_bp.generated_class()) + + for property_name, value in MOVEMENT_DEFAULTS.items(): + character_cdo.set_editor_property(property_name, value) + unreal.log(f"Set {property_name} to {value}") + + unreal.EditorAssetLibrary.save_loaded_asset(character_bp) + unreal.log("Agrarian movement baseline setup complete.") + + +main() diff --git a/Scripts/verify_movement_baseline.py b/Scripts/verify_movement_baseline.py new file mode 100644 index 0000000..bb7fa3d --- /dev/null +++ b/Scripts/verify_movement_baseline.py @@ -0,0 +1,36 @@ +import math +import unreal + + +MOVEMENT_DEFAULTS = { + "WalkSpeed": 140.0, + "SprintSpeed": 550.0, + "SprintStaminaCostPerSecond": 28.0, + "MinSprintStamina": 5.0, +} + + +def load(path): + asset = unreal.EditorAssetLibrary.load_asset(path) + if not asset: + raise RuntimeError(f"Could not load {path}") + return asset + + +def main(): + character_bp = load("/Game/ThirdPerson/Blueprints/BP_ThirdPersonCharacter") + character_cdo = unreal.get_default_object(character_bp.generated_class()) + + mismatches = [] + for property_name, expected in MOVEMENT_DEFAULTS.items(): + actual = float(character_cdo.get_editor_property(property_name)) + if not math.isclose(actual, expected, rel_tol=0.0, abs_tol=0.01): + mismatches.append(f"{property_name}: expected {expected}, got {actual}") + + if mismatches: + raise RuntimeError("Movement baseline verification failed: " + "; ".join(mismatches)) + + unreal.log("Agrarian movement baseline verification complete.") + + +main() diff --git a/Source/AgrarianGame/AgrarianGameCharacter.h b/Source/AgrarianGame/AgrarianGameCharacter.h index d94fe23..8a1a17f 100644 --- a/Source/AgrarianGame/AgrarianGameCharacter.h +++ b/Source/AgrarianGame/AgrarianGameCharacter.h @@ -87,15 +87,15 @@ protected: /** Baseline movement speed before sprint, skill, injury, load, and terrain modifiers. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Agrarian|Movement", meta = (ClampMin = "0")) - float WalkSpeed = 500.0f; + float WalkSpeed = 140.0f; /** Short-burst movement speed used by the first sprinting pass. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Agrarian|Movement", meta = (ClampMin = "0")) - float SprintSpeed = 750.0f; + float SprintSpeed = 550.0f; /** Stamina spent each second while sprinting and moving. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Agrarian|Movement", meta = (ClampMin = "0")) - float SprintStaminaCostPerSecond = 18.0f; + float SprintStaminaCostPerSecond = 28.0f; /** Minimum stamina required to start or continue sprinting. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Agrarian|Movement", meta = (ClampMin = "0", ClampMax = "100"))