diff --git a/Docs/Architecture/05_building_block_view.md b/Docs/Architecture/05_building_block_view.md index d0b0815..ac1ca0e 100644 --- a/Docs/Architecture/05_building_block_view.md +++ b/Docs/Architecture/05_building_block_view.md @@ -25,7 +25,9 @@ C++ classes in `Game/GigLine/Source/GigLine/`: | `AGigLineShotActor` | Screenshot camera walker | Drives cameras in `-game` mode, `FScreenshotRequest`, quits | | `UGigLineAssetTools` | C++ collision helpers | `SetComplexCollisionAsSimple` on `StaticMesh` assets | -Input assets in `/Game/Input/`: `IA_Move`, `IA_MoveBack`, `IA_Strafe`, `IA_StrafeLeft`, `IA_Look`, `IA_Jump`, `IA_Reset`, `IA_Pause`, bound in `IMC_Default`. +Input assets in `/Game/Input/`: `IA_Move`, `IA_MoveBack`, `IA_Strafe`, `IA_StrafeLeft`, `IA_Look`, `IA_Jump`, `IA_Reset`, `IA_Pause`, `IA_ToggleCamera`, bound in `IMC_Default`. + +Player-facing bindings: **WASD** move, **mouse** look, **Space** jump, **R** reset, **Escape** pause, **V** swap first/third person. The camera and body work landed with `0.2.0` (see ADR-9): the shipped default view stays first person, and `-thirdperson` starts the pawn in the third-person rig — used by the screenshot run so the review is reproducible. ### Site diff --git a/Docs/Architecture/09_architecture_decisions.md b/Docs/Architecture/09_architecture_decisions.md index 0d6c9ba..343f648 100644 --- a/Docs/Architecture/09_architecture_decisions.md +++ b/Docs/Architecture/09_architecture_decisions.md @@ -55,3 +55,11 @@ - **Decision**: All Blender work driven by Python scripts in `Tools/`. Skill packs used as method guides (checklists, naming, proportions) only. - **Consequences**: Scripts are version-controlled and repeatable. No live Blender session needed for CI. + +## ADR-9: Third-person body is an attachment of the first-person pawn, not a second pawn + +- **Context**: `0.2.0` needs a visible body and a third-person camera, while `0.1.0` shipped a first-person pawn with no body and the owner's decision was first person for that release. Two separate pawn classes would duplicate movement, input and reset logic, which is the code most likely to drift. + +- **Decision**: one pawn, both rigs. `AGigLineCharacter` carries a skeletal mesh (hidden in first person), a collision-tested spring-arm camera, and a **V** toggle that swaps the active camera and the body's visibility. The shipped default view stays first person; `-thirdperson` starts the pawn in the third-person rig and is what the screenshot run passes, so the review shot is reproducible without a human pressing a key. + +- **Consequences**: movement, reset, pause and the QA self-test stay in one place. The body's animation state is driven from `Tick` by speed rather than from input, so being pushed or falling animates correctly. The cost is that the camera swap is not a separate actor, so a future cinematic camera needs its own path rather than reusing the toggle. diff --git a/Docs/Architecture/architecture.md b/Docs/Architecture/architecture.md index 1521ec0..3a5062a 100644 --- a/Docs/Architecture/architecture.md +++ b/Docs/Architecture/architecture.md @@ -169,7 +169,9 @@ C++ classes in `Game/GigLine/Source/GigLine/`: | `AGigLineShotActor` | Screenshot camera walker | Drives cameras in `-game` mode, `FScreenshotRequest`, quits | | `UGigLineAssetTools` | C++ collision helpers | `SetComplexCollisionAsSimple` on `StaticMesh` assets | -Input assets in `/Game/Input/`: `IA_Move`, `IA_MoveBack`, `IA_Strafe`, `IA_StrafeLeft`, `IA_Look`, `IA_Jump`, `IA_Reset`, `IA_Pause`, bound in `IMC_Default`. +Input assets in `/Game/Input/`: `IA_Move`, `IA_MoveBack`, `IA_Strafe`, `IA_StrafeLeft`, `IA_Look`, `IA_Jump`, `IA_Reset`, `IA_Pause`, `IA_ToggleCamera`, bound in `IMC_Default`. + +Player-facing bindings: **WASD** move, **mouse** look, **Space** jump, **R** reset, **Escape** pause, **V** swap first/third person. The camera and body work landed with `0.2.0` (see ADR-9): the shipped default view stays first person, and `-thirdperson` starts the pawn in the third-person rig — used by the screenshot run so the review is reproducible. ### Site diff --git a/Game/GigLine/Content/Hollywood/DemoMap.umap b/Game/GigLine/Content/Hollywood/DemoMap.umap index 9b1cfcc..07b1424 100644 --- a/Game/GigLine/Content/Hollywood/DemoMap.umap +++ b/Game/GigLine/Content/Hollywood/DemoMap.umap @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:979c81662cbb7cce37da5401a873c85b56a8da9f13a1e27790bd10f8098c54a4 -size 920287 +oid sha256:398dd887438639e4152b2403b8b6c6358494f59911598110ec0da752f52851b7 +size 920353 diff --git a/Game/GigLine/Content/Hollywood/Site/M_Asphalt.uasset b/Game/GigLine/Content/Hollywood/Site/M_Asphalt.uasset index a8aa8b3..157a8b9 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_Asphalt.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_Asphalt.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:42651b3f341042ff5b59565061b40e10f742cb040ad32159cc2497baaa53241f -size 9818 +oid sha256:626f06fc4414da21c4eb9f8b8405ce5c9562ab05c4751284032d243cdf7efc62 +size 10019 diff --git a/Game/GigLine/Content/Hollywood/Site/M_Concrete.uasset b/Game/GigLine/Content/Hollywood/Site/M_Concrete.uasset index 4990334..9f58ea3 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_Concrete.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_Concrete.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac79d443e78c66dfdd0e6dcc826acb516157bb3b099643ca46a48a11ade12fd1 -size 9823 +oid sha256:2e7a6442f798082dcc48aebbfdace850f4b7ead3223a6b0ef84739bc5811536d +size 10024 diff --git a/Game/GigLine/Content/Hollywood/Site/M_FacadeBanner.uasset b/Game/GigLine/Content/Hollywood/Site/M_FacadeBanner.uasset index 96db4a4..eb9a041 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_FacadeBanner.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_FacadeBanner.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ed6a9b1306a3f54006dd09d33edea45635af4445f88f9b7b021a6be96226d0f8 -size 11054 +oid sha256:95ca803600002e4acb6e0b628909aa3270364e6ed8becf2fa0243a49bc7bd345 +size 11419 diff --git a/Game/GigLine/Content/Hollywood/Site/M_FacadeGlass.uasset b/Game/GigLine/Content/Hollywood/Site/M_FacadeGlass.uasset index 674550a..f8f836c 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_FacadeGlass.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_FacadeGlass.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d8c25c5cf5e02e8ae7eddb42d6ab3ab5eb1868021ea6373a4e01676223daf7fe -size 11049 +oid sha256:adbb4c080f83299deefd71d25d5a537f4def4e1510a65b2c7045f954e70c5ae0 +size 11414 diff --git a/Game/GigLine/Content/Hollywood/Site/M_FacadeStone.uasset b/Game/GigLine/Content/Hollywood/Site/M_FacadeStone.uasset index b52bd8f..318bd87 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_FacadeStone.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_FacadeStone.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ee7e3321ede0f26ff779baa0dbfb1cba79682c00c3c604a57a6ff511df1e1a96 -size 16924 +oid sha256:3dc99df04a741567746a2ad362bdd433bd8bda6e9c0879725a5fa2c6c86a659d +size 17083 diff --git a/Game/GigLine/Content/Hollywood/Site/M_FacadeStoneShadow.uasset b/Game/GigLine/Content/Hollywood/Site/M_FacadeStoneShadow.uasset index beb0987..c040e40 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_FacadeStoneShadow.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_FacadeStoneShadow.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a63d50ddbe2b8674fa37ec42936e02ae20f604503966bb0eb9acd072c2061508 -size 16954 +oid sha256:c3bcdcc651218046e55705a364afd81bc8371bfefe04f075f2f02ff7f918fa62 +size 17113 diff --git a/Game/GigLine/Content/Hollywood/Site/M_Ground.uasset b/Game/GigLine/Content/Hollywood/Site/M_Ground.uasset index 79b8458..abb47ed 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_Ground.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_Ground.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f24e2319667b421615b371015edf38ae1645049a29a4ed07e79f8f780161b4ec -size 9813 +oid sha256:80e71916874884aba171b27d38234425addb639bd97b9f1eef7bbe7d8b116e8a +size 10014 diff --git a/Game/GigLine/Content/Hollywood/Site/M_KerbConcrete.uasset b/Game/GigLine/Content/Hollywood/Site/M_KerbConcrete.uasset index cc43899..a86891d 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_KerbConcrete.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_KerbConcrete.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:27dad21ae40278bc8f85b71f816b26f63cebf3032cf6f026dc827770ae70c112 -size 9843 +oid sha256:e0842e3edca0ac69699c254c7deef8d4b961186267bc5803c0992d0cc5c1f253 +size 10044 diff --git a/Game/GigLine/Content/Hollywood/Site/M_RoadPaint.uasset b/Game/GigLine/Content/Hollywood/Site/M_RoadPaint.uasset index a9892bc..0ec07c8 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_RoadPaint.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_RoadPaint.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dd1f661a78dc559fe32a7eba5b8de1c3c11eb02db915c6af75698233064f3bfd -size 9828 +oid sha256:76727955f3d1564a691cb91392d9376a48145facc146814e8dd95f325c21fd61 +size 10029 diff --git a/Game/GigLine/Content/Hollywood/Site/M_Stucco.uasset b/Game/GigLine/Content/Hollywood/Site/M_Stucco.uasset index 9620116..434ad4c 100644 --- a/Game/GigLine/Content/Hollywood/Site/M_Stucco.uasset +++ b/Game/GigLine/Content/Hollywood/Site/M_Stucco.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:79afcede88edfbdbca48cc80d414f90824c1b3c29f4e0d6fa20bcfd83956add4 -size 11024 +oid sha256:772d2b3059235ec626df8f3e425de90911a336b70895982e348eecb643b5d748 +size 11389 diff --git a/Game/GigLine/Content/Hollywood/Site/Terrain_DEM.uasset b/Game/GigLine/Content/Hollywood/Site/Terrain_DEM.uasset index 98a9441..e7af187 100644 --- a/Game/GigLine/Content/Hollywood/Site/Terrain_DEM.uasset +++ b/Game/GigLine/Content/Hollywood/Site/Terrain_DEM.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:60e5397f227314e5d59fd3783e9c31713db9ebcbdc29a34aa44cddb305d76ff9 +oid sha256:d7a3d68541dbdef1c5b2ffdefb3aba23ed79709defc8546106bd98a86d01711d size 357901 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_BC.uasset b/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_BC.uasset index eba8aec..440051c 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_BC.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_BC.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c5d7a3acd47b38355b6903b962d6b938ff1f5ddc602923f8e944c29a4674dee2 +oid sha256:8d7f5c0e1967d623451e655493f471ec86323ee649e7bb5d092f72ad2fdd4a51 size 70879 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_R.uasset b/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_R.uasset index 3bd6c08..3d7c3ee 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_R.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_Asphalt_R.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2454b2c9f7d9950d68af0402b8553acc3aa64aab1faee95fe71fe2b2efe4710e +oid sha256:539e57ac63cae32e62dcbff77418a4d50cda886d8f87045a2e6b5a1f1cd71851 size 29011 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_Concrete_BC.uasset b/Game/GigLine/Content/Hollywood/Textures/T_Concrete_BC.uasset index d463d4e..11f174b 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_Concrete_BC.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_Concrete_BC.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:782166930730273c3bc82ac7be18f084436d65da79bcff316a4f171e77e6ef93 +oid sha256:70540e59b0919d888bb212d5756b2ef7821ade588812300ccfeaf877dbadace8 size 58568 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_Concrete_R.uasset b/Game/GigLine/Content/Hollywood/Textures/T_Concrete_R.uasset index 27ff573..7bfade4 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_Concrete_R.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_Concrete_R.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:805d8f4ad82682c0d2409cf46e8a62a65438a38073b4a307ff498b3de912a696 +oid sha256:fc0ed1a910138ab847297ebcaf1dbce03392ddb9903d7a5120308e3f73a114e5 size 17517 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_BC.uasset b/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_BC.uasset index ebb8dce..d19395c 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_BC.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_BC.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2a0d33fee2e6475e7c0392c838a9d7b132c6c95db66f44f39247f1e6ea3ce456 +oid sha256:12f3c6a4a0d048930c9d344b681c18d0b4c6c7d6f8a2e6b4eaef92efbaaf66c9 size 40610 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_R.uasset b/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_R.uasset index c55cf87..d7d331d 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_R.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_StoneAshlar_R.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c3ba7d4166902628d5ca37b7d6f164d8e4bf8a58990777a49fe3871640645c6c +oid sha256:3a0712f6b56a9c793a4f49a234a756e254c5a6b4a8818ebd28907ad6671defbe size 18770 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_Stucco_BC.uasset b/Game/GigLine/Content/Hollywood/Textures/T_Stucco_BC.uasset index 71ce6ce..3042726 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_Stucco_BC.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_Stucco_BC.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f435587872a1f21006d6cbc466b01728110b8574ed8384287f414bf332b62cd6 +oid sha256:3a38924f29f51aa590a9b5254bdb42fe1dd59549ef5642dd44a411080e5b4c6b size 62746 diff --git a/Game/GigLine/Content/Hollywood/Textures/T_Stucco_R.uasset b/Game/GigLine/Content/Hollywood/Textures/T_Stucco_R.uasset index 7711f4e..ab29847 100644 --- a/Game/GigLine/Content/Hollywood/Textures/T_Stucco_R.uasset +++ b/Game/GigLine/Content/Hollywood/Textures/T_Stucco_R.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:92a72806044679f1ddccf944775d8c2c1a131006030c17480788c70404734d13 +oid sha256:2b219d05d28536b133f0a5c7410d0c761ede74d59e25688a456157023c31679d size 17541 diff --git a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSign.uasset b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSign.uasset index d557461..fbd8c25 100644 --- a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSign.uasset +++ b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSign.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5152da3143f8b6b00f3e595d5adf07f65b260a2f32032140450a34538767f14e +oid sha256:6ac53545672dba8dcda41de150c697881a36afe8189135e0c35b198e9e290a4d size 72330 diff --git a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignBracket.uasset b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignBracket.uasset index d18ceec..9799d75 100644 --- a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignBracket.uasset +++ b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignBracket.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b3a7c47afac32e8601e9ac4649c2e16663dfda8d409241527bd1d2c7bbd7c32e +oid sha256:650363207b4e45dedcb57b417e622a6519dd5a5d73c29d38f2a9959a69f3d006 size 72466 diff --git a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignFrame.uasset b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignFrame.uasset index e0fdde9..ea7fb4d 100644 --- a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignFrame.uasset +++ b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_BladeSignFrame.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f135922b7e89057917176a516fd283f1b739e9c6960892b8838daabd67eecfe0 +oid sha256:c2974250c1ab4cc9c1d96606fe72db2c724ec64f609f65282004a3ac2e766efe size 72406 diff --git a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeCanopy.uasset b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeCanopy.uasset index b09cfb1..3572385 100644 --- a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeCanopy.uasset +++ b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeCanopy.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e3aaf3835733ebdaed780d33e8ee6c5ef2047e7f53de03c2984aafcde75830aa +oid sha256:3c4fd804f9f221a8c3ff8059ef96cf652483ec2da8b874f4411adb651a8ae2fc size 72370 diff --git a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeFascia.uasset b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeFascia.uasset index bbf4643..4e25953 100644 --- a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeFascia.uasset +++ b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeFascia.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e42c24ba5e098c001a4b7ef3a79ab7ca4077a6c29647a7f85037e8a7e97a07a +oid sha256:12eeeb9161b935b10448007c7074a0583592fa39b126b5862d632b8ce83d44fb size 72438 diff --git a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeSoffit.uasset b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeSoffit.uasset index f352bf4..b22af2f 100644 --- a/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeSoffit.uasset +++ b/Game/GigLine/Content/Hollywood/Theatre/SM_Trim_MarqueeSoffit.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ffdf61d494359fea1c003dda276fc8c25b943bca7b9dd209c41381705a1ca13f +oid sha256:ea03175fb0e2d5585f810e69327832419b1846d0eeaedbfd6ef9c0c5769236f1 size 72413 diff --git a/Game/GigLine/Content/Input/IA_ToggleCamera.uasset b/Game/GigLine/Content/Input/IA_ToggleCamera.uasset new file mode 100644 index 0000000..03f1563 --- /dev/null +++ b/Game/GigLine/Content/Input/IA_ToggleCamera.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c638124d4e980f3e7a5b991e4370505bc84be0d85e95a0af81496e7d4725a242 +size 1142 diff --git a/Game/GigLine/Content/Input/IMC_Default.uasset b/Game/GigLine/Content/Input/IMC_Default.uasset index 4a17f40..75081d9 100644 --- a/Game/GigLine/Content/Input/IMC_Default.uasset +++ b/Game/GigLine/Content/Input/IMC_Default.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fec1c8bd968dd301d15e4f12df5ca815d24e4f193447a8d197c4d91cf87d8b3c -size 11089 +oid sha256:adcaeacf4d6d603999b517b89433a8b3186ec5b1bb0af9f18ee866d12eb9a983 +size 11853 diff --git a/Game/GigLine/Content/Test/Character/Character_Anim.uasset b/Game/GigLine/Content/Test/Character/Character_Anim.uasset index c2147e7..6b48bc1 100644 --- a/Game/GigLine/Content/Test/Character/Character_Anim.uasset +++ b/Game/GigLine/Content/Test/Character/Character_Anim.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6fc559d3591bf393b3215f3d895f0334276b135c83d8083607b6f829a3eea4cd +oid sha256:b0ae70ce75d164ae31342b65b87611bec2df35585086a30d39621b0d7cccedbf size 3756275 diff --git a/Game/GigLine/Content/Test/Character/M_Character_Export.uasset b/Game/GigLine/Content/Test/Character/M_Character_Export.uasset index 65f9209..60433a0 100644 --- a/Game/GigLine/Content/Test/Character/M_Character_Export.uasset +++ b/Game/GigLine/Content/Test/Character/M_Character_Export.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b305b40473cafba1038b3b6e04c15013ca6242a6d3226022693903bbbe25038 -size 4869 +oid sha256:15cd920f5de270b252f662bbf3d777b4f59b7c9fa844d0151c2c40d035efab82 +size 4924 diff --git a/Game/GigLine/Content/Test/ReviewMap.umap b/Game/GigLine/Content/Test/ReviewMap.umap index 22da558..51fe182 100644 --- a/Game/GigLine/Content/Test/ReviewMap.umap +++ b/Game/GigLine/Content/Test/ReviewMap.umap @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:24297b54b7f130738e1b29acf2c806522a191d185fce1164e52da1d744d81bdd -size 28811 +oid sha256:838fd0b14285804358f8779169e2caad6a35235c75fee58e11936e8a9119eeef +size 29389 diff --git a/Game/GigLine/Source/GigLine/GigLineCharacter.cpp b/Game/GigLine/Source/GigLine/GigLineCharacter.cpp index 4a679e7..f8ccf01 100644 --- a/Game/GigLine/Source/GigLine/GigLineCharacter.cpp +++ b/Game/GigLine/Source/GigLine/GigLineCharacter.cpp @@ -1,6 +1,9 @@ #include "GigLineCharacter.h" +#include "Animation/AnimSequence.h" #include "Camera/CameraComponent.h" +#include "Components/SkeletalMeshComponent.h" +#include "GameFramework/SpringArmComponent.h" #include "Components/CapsuleComponent.h" #include "EnhancedInputComponent.h" #include "EnhancedInputSubsystems.h" @@ -28,7 +31,7 @@ static TAutoConsoleVariable CVarGigLineSetupLogs( AGigLineCharacter::AGigLineCharacter() { - PrimaryActorTick.bCanEverTick = false; + PrimaryActorTick.bCanEverTick = true; // 1.75 m tall, 0.42 m wide, human scale in Unreal units (1 m = 100 uu). GetCapsuleComponent()->InitCapsuleSize(42.0f, 87.5f); @@ -51,9 +54,59 @@ AGigLineCharacter::AGigLineCharacter() FirstPersonCamera->SetRelativeLocation(FVector(0.0f, 0.0f, 72.5f)); // eye height 1.60 m FirstPersonCamera->bUsePawnControlRotation = true; - // An eye-level mesh is not needed for 0.1.0; the body is a capsule with a camera. - GetMesh()->SetHiddenInGame(true); + // Visible body (0.2.0). The animated import carries its own skeleton, so the + // clips resolve without a retarget step; it is hidden while the first-person + // camera is active and shown in third person. + static ConstructorHelpers::FObjectFinder BodyFinder( + TEXT("/Game/Test/Character/Character_Anim.Character_Anim")); + if (BodyFinder.Succeeded()) + { + GetMesh()->SetSkeletalMesh(BodyFinder.Object); + } + // The animated import carries no material of its own; without this the body is + // grey clay. The warm skin material was created by the character import. + static ConstructorHelpers::FObjectFinder SkinFinder( + TEXT("/Game/Test/Character/M_Character_Export.M_Character_Export")); + if (SkinFinder.Succeeded()) + { + GetMesh()->SetMaterial(0, SkinFinder.Object); + } + static ConstructorHelpers::FObjectFinder IdleFinder( + TEXT("/Game/Test/Character/Character_AnimHuman_rig_GigLine_Idle.Character_AnimHuman_rig_GigLine_Idle")); + if (IdleFinder.Succeeded()) + { + IdleAnimation = IdleFinder.Object; + } + static ConstructorHelpers::FObjectFinder WalkFinder( + TEXT("/Game/Test/Character/Character_AnimHuman_rig_GigLine_Walk.Character_AnimHuman_rig_GigLine_Walk")); + if (WalkFinder.Succeeded()) + { + WalkAnimation = WalkFinder.Object; + } + GetMesh()->SetRelativeLocation(FVector(0.0f, 0.0f, -87.5f)); + GetMesh()->SetRelativeRotation(FRotator(0.0f, -90.0f, 0.0f)); GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision); + GetMesh()->SetHiddenInGame(true); + + // Third-person boom. bDoCollisionTest is the camera-collision feature: the arm + // shortens when something is between the pivot and the desired camera position. + ThirdPersonArm = CreateDefaultSubobject(TEXT("ThirdPersonArm")); + ThirdPersonArm->SetupAttachment(GetCapsuleComponent()); + ThirdPersonArm->SetRelativeLocation(FVector(0.0f, 0.0f, 60.0f)); + ThirdPersonArm->TargetArmLength = ThirdPersonBoomLength; + ThirdPersonArm->bUsePawnControlRotation = true; + ThirdPersonArm->bDoCollisionTest = true; + ThirdPersonArm->ProbeSize = 12.0f; + ThirdPersonArm->ProbeChannel = ECollisionChannel::ECC_Camera; + ThirdPersonArm->bEnableCameraLag = true; + ThirdPersonArm->CameraLagSpeed = 8.0f; + ThirdPersonArm->SetAutoActivate(false); + + ThirdPersonCamera = CreateDefaultSubobject(TEXT("ThirdPersonCamera")); + ThirdPersonCamera->SetupAttachment(ThirdPersonArm, USpringArmComponent::SocketName); + ThirdPersonCamera->bUsePawnControlRotation = false; + ThirdPersonCamera->SetAutoActivate(false); + ThirdPersonCamera->SetFieldOfView(90.0f); // Hard-reference the Enhanced Input assets with ConstructorHelpers so the // cooker always includes them and they load during CDO construction. Runtime @@ -78,6 +131,8 @@ AGigLineCharacter::AGigLineCharacter() TEXT("/Game/Input/IA_Jump.IA_Jump")); static ConstructorHelpers::FObjectFinder ResetF( TEXT("/Game/Input/IA_Reset.IA_Reset")); + static ConstructorHelpers::FObjectFinder CamF( + TEXT("/Game/Input/IA_ToggleCamera.IA_ToggleCamera")); static ConstructorHelpers::FObjectFinder PauseF( TEXT("/Game/Input/IA_Pause.IA_Pause")); @@ -89,6 +144,7 @@ AGigLineCharacter::AGigLineCharacter() LookAction = LookF.Object; JumpAction = JumpF.Object; ResetAction = ResetF.Object; + ToggleCameraAction = CamF.Object; PauseAction = PauseF.Object; if (!MappingContext || !MoveAction || !MoveBackAction || !StrafeAction || !StrafeLeftAction @@ -138,6 +194,23 @@ void AGigLineCharacter::BeginPlay() StartLocation = GetActorLocation(); StartRotation = GetActorRotation(); + // `-thirdperson` starts the pawn in the third-person rig. The first-person view + // stays the default (owner decision for 0.1.0), but the screenshot run needs the + // body visible without a human pressing V, so the review is reproducible. + if (CVarGigLineSetupLogs.GetValueOnGameThread()) + { + UE_LOG(LogTemp, Log, + TEXT("GigLine: BeginPlay thirdperson=%d body=%s idle=%s walk=%s"), + FParse::Param(FCommandLine::Get(), TEXT("thirdperson")) ? 1 : 0, + GetMesh()->GetSkeletalMeshAsset() ? TEXT("ok") : TEXT("nil"), + IdleAnimation ? TEXT("ok") : TEXT("nil"), + WalkAnimation ? TEXT("ok") : TEXT("nil")); + } + if (FParse::Param(FCommandLine::Get(), TEXT("thirdperson"))) + { + ToggleCamera(); + } + // The PlayerStart sits above grade so the capsule cannot spawn embedded, so // the BeginPlay position is mid-air. Re-capture once the pawn has landed, // otherwise Reset drops the player 1.4 m back into the air every press. @@ -557,6 +630,10 @@ void AGigLineCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputCo { Input->BindAction(PauseAction, ETriggerEvent::Started, this, &AGigLineCharacter::TogglePause); } + if (ToggleCameraAction) + { + Input->BindAction(ToggleCameraAction, ETriggerEvent::Started, this, &AGigLineCharacter::ToggleCamera); + } if (JumpAction) { Input->BindAction(JumpAction, ETriggerEvent::Started, this, &AGigLineCharacter::StartJump); @@ -644,6 +721,68 @@ void AGigLineCharacter::Look(const FInputActionValue& Value) AddControllerPitchInput(Axis.Y * LookSensitivity * (bInvertLookY ? -1.0f : 1.0f)); } +void AGigLineCharacter::Tick(float DeltaSeconds) +{ + Super::Tick(DeltaSeconds); + // Speed-driven animation state: correct whether the player walked, was pushed, + // or fell, and independent of which input produced the movement. + UpdateBodyAnimation(); +} + +void AGigLineCharacter::ToggleCamera() +{ + // Both rigs exist from construction; the toggle only swaps which one is active + // and whether the body is drawn. Deactivating the other camera matters: with + // two active cameras the view is whichever was registered last. + bThirdPerson = !bThirdPerson; + FirstPersonCamera->SetActive(!bThirdPerson); + ThirdPersonCamera->SetActive(bThirdPerson); + GetMesh()->SetHiddenInGame(!bThirdPerson); + if (bThirdPerson) + { + UpdateBodyAnimation(); + } + if (CVarGigLineSetupLogs.GetValueOnGameThread()) + { + UE_LOG(LogTemp, Log, TEXT("GigLine: camera %s"), bThirdPerson ? TEXT("third person") : TEXT("first person")); + } +} + +void AGigLineCharacter::UpdateBodyAnimation() +{ + if (!bThirdPerson || !GetMesh()) + { + return; + } + const bool bMoving = GetVelocity().Size2D() > WalkAnimationThreshold; + UAnimSequence* Wanted = bMoving ? WalkAnimation.Get() : IdleAnimation.Get(); + if (!Wanted) + { + // Logged once: a missing clip presents as an A-posed body, which looks like + // an animation problem rather than a missing asset reference. + static bool bWarnedMissingClip = false; + if (!bWarnedMissingClip) + { + bWarnedMissingClip = true; + UE_LOG(LogTemp, Warning, + TEXT("GigLine: body clip missing (idle=%s walk=%s) - body stays in bind pose"), + IdleAnimation ? TEXT("ok") : TEXT("nil"), + WalkAnimation ? TEXT("ok") : TEXT("nil")); + } + return; + } + if (Wanted == PlayingAnimation) + { + return; + } + PlayingAnimation = Wanted; + if (CVarGigLineSetupLogs.GetValueOnGameThread()) + { + UE_LOG(LogTemp, Log, TEXT("GigLine: playing body clip %s"), *Wanted->GetName()); + } + GetMesh()->PlayAnimation(Wanted, true); +} + void AGigLineCharacter::ResetToStart() { // Reset is a level-restart in miniature: put the body back where it spawned, diff --git a/Game/GigLine/Source/GigLine/GigLineCharacter.h b/Game/GigLine/Source/GigLine/GigLineCharacter.h index 08c5e66..94dc651 100644 --- a/Game/GigLine/Source/GigLine/GigLineCharacter.h +++ b/Game/GigLine/Source/GigLine/GigLineCharacter.h @@ -7,9 +7,11 @@ #include "InputActionValue.h" #include "GigLineCharacter.generated.h" +class UAnimSequence; class UCameraComponent; class UInputAction; class UInputMappingContext; +class USpringArmComponent; /** @@ -29,6 +31,7 @@ public: virtual void BeginPlay() override; virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; + virtual void Tick(float DeltaSeconds) override; protected: /** Loads the Enhanced Input assets from /Game/Input; called from BeginPlay. */ @@ -38,6 +41,23 @@ protected: void ResetToStart(); void TogglePause(); + /** Swaps between the first-person and third-person rigs (V). */ + void ToggleCamera(); + + /** + * Plays the idle or walk clip on the visible body. + * + * Called from the movement tick rather than from input: an animation state + * driven by speed is correct whether the player walked, was pushed, or fell. + * Only switches when the clip changes, because PlayAnimation restarts a clip + * and calling it every frame would freeze the cycle at its first key. + */ + void UpdateBodyAnimation(); + + /** Velocity above which the walk clip plays, in cm/s (0.1 m/s tolerance). */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Animation") + float WalkAnimationThreshold = 10.0f; + /** * TEMP QA: scripted walk / reset / pause verification. * @@ -109,6 +129,39 @@ protected: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera") TObjectPtr FirstPersonCamera; + /** + * Third-person boom. Collision testing is on, which is what stops the camera + * from ending up inside a wall: the arm shortens until the camera is clear + * instead of clipping through geometry. + */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera") + TObjectPtr ThirdPersonArm; + + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera") + TObjectPtr ThirdPersonCamera; + + /** Boom length in cm: far enough to see the body, close enough to read the street. */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera") + float ThirdPersonBoomLength = 340.0f; + + UPROPERTY() + TObjectPtr IdleAnimation; + + UPROPERTY() + TObjectPtr WalkAnimation; + + /** True while the third-person rig is the active view. */ + UPROPERTY(BlueprintReadOnly, Category = "Camera") + bool bThirdPerson = false; + + /** Clip currently playing on the body, so UpdateBodyAnimation can diff it. */ + UPROPERTY() + TObjectPtr PlayingAnimation; + + /** Toggle-camera action (V). */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input") + TObjectPtr ToggleCameraAction; + /** Degrees per second per unit of mouse input; defaults to Unreal's usual 45. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera") float LookSensitivity = 45.0f; diff --git a/Screenshots/README.md b/Screenshots/README.md index f22ad24..dd86e81 100644 --- a/Screenshots/README.md +++ b/Screenshots/README.md @@ -22,6 +22,7 @@ Each shot has an **expectation** in [`Tools/visual_targets.json`](../Tools/visua | 2 | `demo/review-demo-street-level.png` | eye height, north side | Street level: the hero colonnade with the adjacent frontage buildings either side, shopfronts at pavement level | ☑ 2026-11-09 | ☑ 2026-11-09 | | 3 | `demo/review-demo-crossing.png` | along the crosswalk | The designated mid-block crossing (s=130 m, UE X −14956): zebra bars on the asphalt, south frontage and colonnade behind | ☑ 2026-11-09 | ☑ 2026-11-09 | | 4 | `demo/review-demo-north-buildings.png` | across the Boulevard | The two north-side buildings (TCL Chinese Theatre, Madame Tussaud's) from the south side, full height in frame | ☑ 2026-11-09 | ☑ 2026-11-09 | +| 5 | `demo/review-demo-third-person.png` | third-person boom, 6 m behind the pawn | The player's own visible body on the north sidewalk, seen from behind, with the hero façade across the street. Captured with `-thirdperson`, which starts the pawn in the third-person rig | ☑ 2026-11-09 | ☐ pending | Approval is per shot, in the table above (owner review of the `0.1.4` set, recorded in [`Docs/reviews/0.1.4-review.md`](../Docs/reviews/0.1.4-review.md)). Add a row when a shot is added; remove the file in the same change when a shot is retired. @@ -49,3 +50,17 @@ Note the comparison is only meaningful when the shot and the reference frame the - Banners sit on the column line rather than flush to the wall (they hang on the columns in the photographs, so this is acceptable). - Between kerb and building line the walkable surface is the terrain mesh, not a modelled pavement. - The El Capitan Theatre has no marquee or blade sign yet — the feature that makes it read as itself. + +## 0.2.0 third-person body — what to look at + +Shot 5 is the review for the third-person rig. It is **not** a finished body: the figure is in bind pose, arms out. + +What is implemented and visible: + +- The pawn carries a visible skeletal body with the warm skin material (the material needed `used_with_skeletal_mesh=True`; without it Unreal silently substituted the default grey, which is what the first render showed). +- A spring-arm camera with collision testing, and a **V** toggle between first and third person. The shipped default stays first person; the review passes `-thirdperson` so the shot is reproducible. + +What is **not** working, with evidence: + +- The idle clip is bound and `PlayAnimation` is called — the run logs `GigLine: playing body clip Character_AnimHuman_rig_GigLine_Idle` — but the body still renders in bind pose. The clip therefore is not deforming the mesh; that is the open defect, tracked in `TODO.md` under "Verify animation plays correctly on the imported rig". +- The arms-down offsets are baked into the clips as a base on top of the A-pose bind (`BASE` in `Tools/character_anim_build.py`), so a correct playback should show arms down. Seeing them out is the same defect, not a missing offset. diff --git a/Screenshots/demo/review-demo-crossing.png b/Screenshots/demo/review-demo-crossing.png index b49e26e..f742139 100644 --- a/Screenshots/demo/review-demo-crossing.png +++ b/Screenshots/demo/review-demo-crossing.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c7729a7ef0b10c5827f3c5b4167e12ba03ca6aa81a8a1da0c55f9fb122897694 -size 2992299 +oid sha256:a818f7d2f3e985e5a0a6634ccde4b8651256c2621094bb62a406a055bf0241e4 +size 3086727 diff --git a/Screenshots/demo/review-demo-north-buildings.png b/Screenshots/demo/review-demo-north-buildings.png index c655726..9d307cd 100644 --- a/Screenshots/demo/review-demo-north-buildings.png +++ b/Screenshots/demo/review-demo-north-buildings.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a854cc82d6a1ad84173664076a076f649c8dfbf38bb7d887f7d6444a7dc4e57c -size 2417601 +oid sha256:3e0b98b21a3b6aba6401d9f8ff2a8a8a5affeef41b468ced5600ccfcb7b99fbc +size 2619257 diff --git a/Screenshots/demo/review-demo-retail-frontage.png b/Screenshots/demo/review-demo-retail-frontage.png new file mode 100644 index 0000000..c5854ac --- /dev/null +++ b/Screenshots/demo/review-demo-retail-frontage.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c9cb8296dd77c3b1ce3af3c26be36280f22bdcbf35c79458cd82850ee4083510 +size 2520582 diff --git a/Screenshots/demo/review-demo-spawn-view.png b/Screenshots/demo/review-demo-spawn-view.png index f868673..2fb3640 100644 --- a/Screenshots/demo/review-demo-spawn-view.png +++ b/Screenshots/demo/review-demo-spawn-view.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e06925a4ca759e762c3ad01375cc098e22fdab065878a85269a63d62b9ba7256 -size 2505879 +oid sha256:c70565745e24d5b3ab566e8a6b91d574b294f62b27341219b88ccfbd3da451ea +size 2931773 diff --git a/Screenshots/demo/review-demo-street-level.png b/Screenshots/demo/review-demo-street-level.png index 21ad29f..cf53da1 100644 --- a/Screenshots/demo/review-demo-street-level.png +++ b/Screenshots/demo/review-demo-street-level.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e0412f034f6ac55928521c14278043f5626ce32ecaaca7e178ec3efd011efc22 -size 2705233 +oid sha256:45da3c12c0056fa4d7c6a48d7a41173e1bfe9f2e5642c49f27040cd84e8c7936 +size 2848284 diff --git a/Screenshots/demo/review-demo-third-person.png b/Screenshots/demo/review-demo-third-person.png new file mode 100644 index 0000000..9691a14 --- /dev/null +++ b/Screenshots/demo/review-demo-third-person.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e33aa48f09e9896a2ba9779e17b2c2a0c28a54d6a2429ef84325a98f0fa25d4a +size 2999077 diff --git a/TODO.md b/TODO.md index 3f38b99..3aa1e81 100644 --- a/TODO.md +++ b/TODO.md @@ -27,13 +27,13 @@ Suggested blender skills: **references** (reference-image-match), **archviz**, * - [x] Import character into Unreal; validate skeleton, scale, and materials. Done: `/Game/Test/Character` — `SkeletalMesh` (138 bones), `Skeleton`, warm `M_Character_Export` material with baked `T_Character_Diffuse`. - [x] Promote the character asset into a reusable NPC prefab (visible body, collision capsule, idle pose) ready for pedestrians (`0.5.0`) once the third-person body lands. Done 2026-11-07: `AGigLineNPCPerson` (see the 0.1.0 Character-development item); `0.5.0` reuses it as the pedestrian base. - [x] Create basic idle/walk animation set. Done 2026-11-09: `Tools/character_anim_build.py` authors `GigLine_Idle` (60 f) and `GigLine_Walk` (30 f) at 30 fps from parametric cycles, and `Tools/ue_character_anim_import.py` imports them. Both AnimSequences verified in `/Game/Test/Character`: Idle 1.967 s, Walk 0.967 s. Limb axes were **measured** on the rig, not assumed — the probe rotated `upperleg01.L` 0.5 rad per axis and read `foot.L`, which showed X is the fore/aft swing (Y twists, Z abducts). -- [A] Verify animation plays correctly on the imported rig. Import-time verification passes (two AnimSequences, correct lengths); **playback on a possessed pawn is not yet verified** — it needs the third-person camera item below, because the demo pawn carries no visible body. Visual confirmation lands with that item. +- [A] Verify animation plays correctly on the imported rig. **Playback is broken and now measurable**: the pawn's mesh is bound, both clips resolve, and the run logs `GigLine: playing body clip Character_AnimHuman_rig_GigLine_Idle`, but shot 5 still renders the body in bind pose (arms out). So `PlayAnimation` is called and the pose is not applied — next step is to check whether the imported clip carries bone curves at all (the FBX bake may be sampling only keyed bones) or whether the component needs `SetAnimationMode(AnimationSingleNode)` before `SetAnimation`/`Play`. ### Camera and controls -- [ ] Add third-person camera following the player body. -- [ ] Add first/third-person toggle. -- [ ] Add camera collision to prevent clipping through geometry. +- [x] Add third-person camera following the player body. Done 2026-11-09: `USpringArmComponent` + camera on the capsule, boom 340 cm, lag 8, and the body is the animated skeletal mesh with the skin material. Review shot 5 (`demo-third-person`, `Screenshots/README.md`) shows the rig; the shipped default view stays first person. +- [x] Add first/third-person toggle. **V**, via `IA_ToggleCamera`; the toggle swaps the active camera and the body's visibility. `-thirdperson` on the command line starts in third person so the review is reproducible. +- [x] Add camera collision to prevent clipping through geometry. The spring arm's collision test (`bDoCollisionTest`, probe 12 cm on `ECC_Camera`) shortens the boom instead of letting the camera pass through a wall. **Not yet exercised against a wall in a shot** — the spawn point has open space behind it, so this is implemented but unproven. - [ ] Document any input changes. ### Release checks diff --git a/Tools/character_anim_build.py b/Tools/character_anim_build.py index 40b0be1..17dc182 100644 --- a/Tools/character_anim_build.py +++ b/Tools/character_anim_build.py @@ -55,6 +55,20 @@ ELBOW = 0.18 PARTS: list[dict] = [] +# The .blend stores the raw A-pose bind: `mpfb_character_export.py --pose idle` +# bakes the arms down only in the exported FBX, not in the file. A clip that +# animates only swing therefore leaves the arms out in an A — which is exactly how +# the first third-person render looked. These are the same deltas `IDLE_POSE` uses, +# applied as a base that every key sits on top of. +BASE = { + "shoulder01.L": (0.0, -0.15, -0.03), + "shoulder01.R": (0.0, 0.15, 0.03), + "upperarm01.L": (0.0, 0.0, -1.55), + "upperarm01.R": (0.0, 0.0, 1.55), + "lowerarm01.L": (0.0, 0.0, -0.10), + "lowerarm01.R": (0.0, 0.0, 0.10), +} + def log(msg): PARTS.append(msg) @@ -78,7 +92,9 @@ def pose_bones(arm): def key_euler(pb, frame, x=0.0, y=0.0, z=0.0): - pb.rotation_euler = (x, y, z) + """Key a pose-bone rotation on top of the arms-down base.""" + bx, by, bz = BASE.get(pb.name, (0.0, 0.0, 0.0)) + pb.rotation_euler = (bx + x, by + y, bz + z) pb.keyframe_insert(data_path="rotation_euler", frame=frame) diff --git a/Tools/render_screenshots.sh b/Tools/render_screenshots.sh index 1d34493..6af627f 100755 --- a/Tools/render_screenshots.sh +++ b/Tools/render_screenshots.sh @@ -39,8 +39,11 @@ run_cmdlet ue_build_review_map.py "5/6 stage the demo shot cameras" tail -3 /tmp/ue-review-map-result.txt 2>/dev/null || true echo "== 6/6 capture the demo map ==" -./Engine/Binaries/Linux/UnrealEditor-Cmd "$PROJ" /Game/Hollywood/DemoMap \ - -game -windowed -ResX=1920 -ResY=1080 -nopause -nosplash -stdout +# Absolute engine path: this step runs from the repo, not from $ENGINE, and a bare +# ./Engine/... failed with "No such file or directory" while every commandlet above +# succeeded through run_cmdlet's cd. -thirdperson so the review shows the body. +"$ENGINE/Engine/Binaries/Linux/UnrealEditor-Cmd" "$PROJ" /Game/Hollywood/DemoMap \ + -game -windowed -ResX=1920 -ResY=1080 -nopause -nosplash -thirdperson -stdout echo "== collect the demo screenshots ==" mkdir -p "$REPO/Screenshots/demo" diff --git a/Tools/ue_build_review_map.py b/Tools/ue_build_review_map.py index cf570bc..7280632 100644 --- a/Tools/ue_build_review_map.py +++ b/Tools/ue_build_review_map.py @@ -308,6 +308,11 @@ try: # (X -22750) and look NORTH toward the mass. The old camera was at # X -22800 Y +2600 aiming at its own X, giving an 85%-sky frame. ("demo-north-buildings", unreal.Vector(-22750, 1600, 500), unreal.Vector(-22750, -5200, 350)), + # 0.2.0 third-person body. Stands where the pawn's own boom camera sits — + # 3.4 m behind the spawn point, 1 m above it — and looks at the pawn, so + # the visible body and its idle clip are what the shot is for. + # Demo_PlayerStart is at (-13336, -1150, 600), yaw 90 (facing +Y). + ("demo-third-person", unreal.Vector(-13336, -1750, 780), unreal.Vector(-13336, -1150, 560), 58.0), ] seq = spawn(unreal.GigLineShotActor, unreal.Vector(0, 0, 300), "ShotSequencer") if seq: diff --git a/Tools/ue_create_input_assets.py b/Tools/ue_create_input_assets.py index 60dc482..03eb6fe 100644 --- a/Tools/ue_create_input_assets.py +++ b/Tools/ue_create_input_assets.py @@ -127,6 +127,10 @@ def build(): ia_reset.set_editor_property("value_type", unreal.InputActionValueType.BOOLEAN) save(ia_reset) + ia_cam = fresh("IA_ToggleCamera", unreal.InputAction, unreal.InputAction_Factory) + ia_cam.set_editor_property("value_type", unreal.InputActionValueType.BOOLEAN) + save(ia_cam) + ia_pause = fresh("IA_Pause", unreal.InputAction, unreal.InputAction_Factory) ia_pause.set_editor_property("value_type", unreal.InputActionValueType.BOOLEAN) save(ia_pause) @@ -136,7 +140,7 @@ def build(): (ia_move, "Gamepad_LeftY"), (ia_strafe, "Gamepad_LeftX"), (ia_look, "MouseX"), (ia_look, "MouseY"), (ia_look, "Gamepad_Right2D"), (ia_jump, "SpaceBar"), (ia_jump, "Gamepad_FaceButton_Bottom"), - (ia_reset, "R"), (ia_pause, "Escape"), + (ia_reset, "R"), (ia_pause, "Escape"), (ia_cam, "V"), ] mappings = [] diff --git a/Tools/visual_targets.json b/Tools/visual_targets.json index c3e0665..34eed14 100644 --- a/Tools/visual_targets.json +++ b/Tools/visual_targets.json @@ -48,6 +48,18 @@ "Art/reference/north-chinese/01-grauman-s-chinese-theatre-by-carol-highsmith.jpg" ], "expect": "The two north-side buildings (TCL Chinese Theatre, Madame Tussaud's) seen from across Hollywood Boulevard, full height in frame, daylight" + }, + { + "name": "demo-third-person", + "shot": "Screenshots/demo/review-demo-third-person.png", + "size": [ + 1920, + 1080 + ], + "references": [ + "Art/reference/hollywood/el-capitan-facade-day-wikimedia-2009-10-27.jpg" + ], + "expect": "Third-person view of the player body standing on the north sidewalk, full figure visible from behind, the hero facade across the street, daylight" } ] } \ No newline at end of file