From 4f3ed20e493bab910a0eb199f10f115db34739fd Mon Sep 17 00:00:00 2001 From: Zwitschi Date: Mon, 9 Nov 2026 15:14:49 +0100 Subject: [PATCH] feat(vehicle): Chaos vehicle spawns and simulates, physics asset generated from script The physics asset could not be made from Python (PhysicsAssetFactory exposes no mesh property), so a small editor-only C++ helper calls FPhysicsAssetUtils::CreateFromSkeletalMesh - the same code path as the editor's Create Physics Asset action. It produces PA_Vehicle_Sedan with 6 bodies and assigns it to SK_Vehicle_Sedan. AGigLineVehicle is a Chaos wheeled pawn that configures its four wheels from the modelled dimensions (radius 33 cm, wheelbase 278, track 156) and is staged in DemoMap. A run logs: spawned at (-12950, -900, 120), 4 wheel setups settled at Z 494 cm, simulating=1, speed=0 cm/s That last line is the defect and it is not hidden: the vehicle rests 3.7 m above the road, so the generated physics bodies do not match the mesh. Recorded in TODO.md with the next step - inspect the bodies against the mesh, then either fix the creation params or author two boxes and four wheel spheres explicitly. --- Game/GigLine/Content/Hollywood/DemoMap.umap | 4 +- .../Content/Hollywood/Site/M_Asphalt.uasset | 2 +- .../Content/Hollywood/Site/M_Concrete.uasset | 2 +- .../Hollywood/Site/M_FacadeBanner.uasset | 2 +- .../Hollywood/Site/M_FacadeGlass.uasset | 2 +- .../Hollywood/Site/M_FacadeStone.uasset | 2 +- .../Hollywood/Site/M_FacadeStoneShadow.uasset | 2 +- .../Content/Hollywood/Site/M_Ground.uasset | 2 +- .../Hollywood/Site/M_KerbConcrete.uasset | 2 +- .../Content/Hollywood/Site/M_RoadPaint.uasset | 2 +- .../Content/Hollywood/Site/M_Stucco.uasset | 2 +- .../Content/Hollywood/Site/Terrain_DEM.uasset | 2 +- .../Hollywood/Textures/T_Asphalt_BC.uasset | 2 +- .../Hollywood/Textures/T_Asphalt_R.uasset | 2 +- .../Hollywood/Textures/T_Concrete_BC.uasset | 2 +- .../Hollywood/Textures/T_Concrete_R.uasset | 2 +- .../Textures/T_StoneAshlar_BC.uasset | 2 +- .../Hollywood/Textures/T_StoneAshlar_R.uasset | 2 +- .../Hollywood/Textures/T_Stucco_BC.uasset | 2 +- .../Hollywood/Textures/T_Stucco_R.uasset | 2 +- .../Hollywood/Vehicle/PA_Vehicle_Sedan.uasset | 3 + .../Hollywood/Vehicle/SK_Vehicle_Sedan.uasset | 4 +- Game/GigLine/Source/GigLine/GigLine.Build.cs | 14 ++ .../GigLine/Source/GigLine/GigLineVehicle.cpp | 127 ++++++++++++++++++ Game/GigLine/Source/GigLine/GigLineVehicle.h | 41 ++++++ .../Source/GigLine/GigLineVehicleBuilder.cpp | 69 ++++++++++ .../Source/GigLine/GigLineVehicleBuilder.h | 34 +++++ TODO.md | 10 +- Tools/ue_build_demo_map.py | 11 ++ 29 files changed, 328 insertions(+), 27 deletions(-) create mode 100644 Game/GigLine/Content/Hollywood/Vehicle/PA_Vehicle_Sedan.uasset create mode 100644 Game/GigLine/Source/GigLine/GigLineVehicle.cpp create mode 100644 Game/GigLine/Source/GigLine/GigLineVehicle.h create mode 100644 Game/GigLine/Source/GigLine/GigLineVehicleBuilder.cpp create mode 100644 Game/GigLine/Source/GigLine/GigLineVehicleBuilder.h diff --git a/Game/GigLine/Content/Hollywood/DemoMap.umap b/Game/GigLine/Content/Hollywood/DemoMap.umap index 8f67e82..7d8a4ec 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:26c6f8b6a43d58b9966486e3c2182a4967f9f02bf0f9b38ae89448576b33197f -size 782209 +oid sha256:0ae39cea4fc5ff97c70d3f8f1b3c74126a3a58400889db64f26ccf31fa4ba663 +size 783091 diff --git a/Game/GigLine/Content/Hollywood/Site/M_Asphalt.uasset b/Game/GigLine/Content/Hollywood/Site/M_Asphalt.uasset index 864ec50..c60feda 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:d430ad855bf7da7566bd2647a4c6fdf5132748810ba69a9bef3456ee35eaa5c8 +oid sha256:d3defe86834db254c86d0121b3f71ebf85618780e67ba42551e0901dd9ac7ab2 size 10019 diff --git a/Game/GigLine/Content/Hollywood/Site/M_Concrete.uasset b/Game/GigLine/Content/Hollywood/Site/M_Concrete.uasset index 50b81fe..e15c856 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:3bc31f75475e402ce8ee13a1c5e0242fc06c56b47e3ddca4b7e5b9ca39b166fa +oid sha256:a77aa28c72442e05ce640df34c652744f322151917219ed8a0318847f9bb1a42 size 10024 diff --git a/Game/GigLine/Content/Hollywood/Site/M_FacadeBanner.uasset b/Game/GigLine/Content/Hollywood/Site/M_FacadeBanner.uasset index f64378b..167f1a8 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:731f51c303ca54b126181a4792a1c288196b6f253028357fd2e38c338475981a +oid sha256:40cc43b90731a8b54294856830adb2ecc46fa91bbb2ecee07cfea034fb5a498e size 11419 diff --git a/Game/GigLine/Content/Hollywood/Site/M_FacadeGlass.uasset b/Game/GigLine/Content/Hollywood/Site/M_FacadeGlass.uasset index d472812..a44049b 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:44b050c39a7ff5a82eae9ef09c6982d8ed14fe77edd34f99283e4d4b4ec59da1 +oid sha256:60cd410834ea7cb58f61c4b3fbb68769a6ee9a9382449d76926e56d00b9f0cb4 size 11414 diff --git a/Game/GigLine/Content/Hollywood/Site/M_FacadeStone.uasset b/Game/GigLine/Content/Hollywood/Site/M_FacadeStone.uasset index 6673957..598a250 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:8e3ce5d89b3638ad47c517e7a582ceb83de8b00922e4d92882a4b988914d0bd6 +oid sha256:63449a2e6e764b51a4e8348bb758de5336a1051bc31a2b59cfb2b5f091370527 size 17083 diff --git a/Game/GigLine/Content/Hollywood/Site/M_FacadeStoneShadow.uasset b/Game/GigLine/Content/Hollywood/Site/M_FacadeStoneShadow.uasset index d7a336a..347ea32 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:06769e46f4a6af9d52aa755f6540519b4b335d86a68913e4cbd1e099556bf76b +oid sha256:716422f08665cbf68511210a90cf7d4a9bd55ef259dc1a0b5a5927b3ee1f5d33 size 17113 diff --git a/Game/GigLine/Content/Hollywood/Site/M_Ground.uasset b/Game/GigLine/Content/Hollywood/Site/M_Ground.uasset index 2e1ce78..9f28069 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:f3142c2970a411f821252e13046b6a7378899cb91cb9cb98ca0abb4f8366d4d1 +oid sha256:da189d7135dde22e69e34e35465cf706d54c0229213bf71cfefcf79d95c977a2 size 10014 diff --git a/Game/GigLine/Content/Hollywood/Site/M_KerbConcrete.uasset b/Game/GigLine/Content/Hollywood/Site/M_KerbConcrete.uasset index 2279851..0cfcf99 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:4e7a8a8a3fa345ddc93b2f9514b58bf570989fe33cc894ab809a87177c98d0ce +oid sha256:6422f922cdbb15c04223a7f8f87a55b76a06e5d43f4803694cc9ffa446fe3a21 size 10044 diff --git a/Game/GigLine/Content/Hollywood/Site/M_RoadPaint.uasset b/Game/GigLine/Content/Hollywood/Site/M_RoadPaint.uasset index a4541ee..8e4cbfc 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:2bed888d2157f1a7101c08171f7965e549d5ef48acc7b9f9dc103f9caf5d15cd +oid sha256:118705b5b5b71585c836deb4b7fd1e83aab173e2e90a55cd3a402a35cf778e78 size 10029 diff --git a/Game/GigLine/Content/Hollywood/Site/M_Stucco.uasset b/Game/GigLine/Content/Hollywood/Site/M_Stucco.uasset index 3bbda2b..71bc086 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:5cf23dd9049e3e84b7c573a6f9c7aad538d294213a496c5ca2fcc5328525a8ae +oid sha256:e650732418aeac33c84a8dfc232b270e566b420468cd30d80a66153117dab966 size 11389 diff --git a/Game/GigLine/Content/Hollywood/Site/Terrain_DEM.uasset b/Game/GigLine/Content/Hollywood/Site/Terrain_DEM.uasset index 9b45fe0..ea4d52c 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:cf1aceda8202def267cff63f18c5bf7ae91546996e1b071668c6b1147da8e8ca +oid sha256:d9e8d9c6e05fd050ab696c4784d9ca127ad7c491909166a3bd8f6fd25bc03f5f 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 2d27baf..0c7d3e3 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:5eb2e0c112fe1f74c015df093c57886d4ae44a532af43321e76bc8a849b3e0e4 +oid sha256:b014f7387fed856f544e1cb1162d766655d1d2e37773259aafd8e53eead836b3 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 ff015ab..67e9bd8 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:d2d55fec24c9231c937a003109f60b78b79bd54588d4305f462bd4703934b650 +oid sha256:b95fb9db1f8df08864049e2015d0536d58ceaf30fa6594989ec446e3447ac708 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 325783c..a881fc3 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:169b8076518236a4522d87f5036b0fffb684b0e215c90c0db1c36828bb77de59 +oid sha256:bb6912c5c709dc8bfea3538bb030393dfd92cb91bb901e98d2512ac3e49c777f 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 dcffc1e..e935557 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:c20cd95c3d485dd54edc9112ba65aee67b556443070d32fe8bfe6cd927d250fd +oid sha256:cc74c1af5fa8e8591e6502eecd37f6effc1b58b028d56776cb25467dbd7a00d6 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 07d0147..35fadbf 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:28c4cd5cad5581857e80250448f32c0a25ca4d83c9dedd442eb98037fbf3bbea +oid sha256:dadce20c944e295ad83087ba780ccd1783959772f3202d2bf3ebd6f82c5253c4 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 4a58b81..5d37253 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:8a4d5bfbd587b3607b38f4e5f961b1088d3d0ea72ad7aa815782a682af1dc6b3 +oid sha256:0e5fca9d6b1a59c5bef1d124dfcc9698466bc63f930ec9b3ca0ba57cb5c08a34 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 562276e..0a56d5a 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:8d34f4385dbd481141bd5a7a41438706ed96342c1584a913bf7308cf5cc024d8 +oid sha256:2622cdadac63220f5c09d6b2840e3ac320489cec6faf53cc1e94011e7eab37fd 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 b7464bd..e48df06 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:cb9cb4aa6074465957dd3835fa573f7aaf5e97b4c6e1e1dd0865a87dd447bda7 +oid sha256:de8bc07b1d8ee444bc4a2af0794030005c56f292d8c86512e220316f2b17a7c3 size 17541 diff --git a/Game/GigLine/Content/Hollywood/Vehicle/PA_Vehicle_Sedan.uasset b/Game/GigLine/Content/Hollywood/Vehicle/PA_Vehicle_Sedan.uasset new file mode 100644 index 0000000..825260d --- /dev/null +++ b/Game/GigLine/Content/Hollywood/Vehicle/PA_Vehicle_Sedan.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca7b0c16d20886e7304e99b708b69d1c3523032d5c8c7f635f75d9fe6e472f75 +size 11876 diff --git a/Game/GigLine/Content/Hollywood/Vehicle/SK_Vehicle_Sedan.uasset b/Game/GigLine/Content/Hollywood/Vehicle/SK_Vehicle_Sedan.uasset index cc0816e..24889d2 100644 --- a/Game/GigLine/Content/Hollywood/Vehicle/SK_Vehicle_Sedan.uasset +++ b/Game/GigLine/Content/Hollywood/Vehicle/SK_Vehicle_Sedan.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d436faeb7d150e64f777fb6a061febe8d338ba78a2f35f7e2cc55cef93ccd86f -size 254347 +oid sha256:0bc494f072556b8d16ae2c10b59962747cb04a601e598e5ff0e965269e7226f3 +size 254637 diff --git a/Game/GigLine/Source/GigLine/GigLine.Build.cs b/Game/GigLine/Source/GigLine/GigLine.Build.cs index 5f9b939..9bc1280 100644 --- a/Game/GigLine/Source/GigLine/GigLine.Build.cs +++ b/Game/GigLine/Source/GigLine/GigLine.Build.cs @@ -14,5 +14,19 @@ public class GigLine : ModuleRules "InputCore", "EnhancedInput" }); + + // Editor-only: the vehicle physics asset is generated from the skeletal mesh with + // FPhysicsAssetUtils, which lives in the Developer/PhysicsUtilities module. Chaos + // Vehicles also need the physics vehicle module at runtime. + if (Target.bBuildEditor) + { + PrivateDependencyModuleNames.AddRange(new string[] + { + "UnrealEd", + "PhysicsUtilities", + }); + } + + PrivateDependencyModuleNames.Add("ChaosVehicles"); } } diff --git a/Game/GigLine/Source/GigLine/GigLineVehicle.cpp b/Game/GigLine/Source/GigLine/GigLineVehicle.cpp new file mode 100644 index 0000000..ebb475c --- /dev/null +++ b/Game/GigLine/Source/GigLine/GigLineVehicle.cpp @@ -0,0 +1,127 @@ +#include "GigLineVehicle.h" + +#include "ChaosWheeledVehicleMovementComponent.h" +#include "Components/SkeletalMeshComponent.h" + +// From the Blender report (Art/blender/vehicle/report.json). Kept as named constants so a +// model change is a compile-time mismatch to fix, not a number buried in a setup call. +namespace GigLineVehicleDims +{ + constexpr float WheelRadiusCm = 33.0f; + constexpr float WheelBaseCm = 278.0f; + constexpr float TrackCm = 156.0f; +} + +AGigLineVehicle::AGigLineVehicle() +{ + PrimaryActorTick.bCanEverTick = true; + + if (USkeletalMeshComponent* Body = GetMesh()) + { + static ConstructorHelpers::FObjectFinder MeshFinder( + TEXT("/Game/Hollywood/Vehicle/SK_Vehicle_Sedan.SK_Vehicle_Sedan")); + if (MeshFinder.Succeeded()) + { + Body->SetSkeletalMesh(MeshFinder.Object); + } + Body->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics); + Body->SetCollisionProfileName(TEXT("PhysicsActor")); + Body->SetSimulatePhysics(true); + } + + if (UChaosWheeledVehicleMovementComponent* Movement = + Cast(GetVehicleMovementComponent())) + { + ConfigureWheels(); + } +} + +void AGigLineVehicle::ConfigureWheels() +{ + UChaosWheeledVehicleMovementComponent* Movement = + Cast(GetVehicleMovementComponent()); + if (!Movement) + { + return; + } + + // One entry per wheel bone, in the order the rig was built. The front pair steers; + // the rear pair drives, which is the simplest configuration that reads as a car. + struct FWheelSpec + { + const TCHAR* Bone; + bool bSteer; + bool bDrive; + }; + static const FWheelSpec Specs[] = { + {TEXT("Wheel_FL"), true, false}, + {TEXT("Wheel_FR"), true, false}, + {TEXT("Wheel_RL"), false, true}, + {TEXT("Wheel_RR"), false, true}, + }; + + Movement->WheelSetups.Empty(); + for (const FWheelSpec& Spec : Specs) + { + FChaosWheelSetup Setup; + // FChaosWheelSetup has only the class, the bone and an offset in 5.8 - there is + // no per-setup disable flag, and steering/drive flags live on the wheel object. + Setup.WheelClass = UChaosVehicleWheel::StaticClass(); + Setup.BoneName = FName(Spec.Bone); + Movement->WheelSetups.Add(Setup); + } + + // Radius and stance for every wheel; the per-wheel subclass would normally carry + // these, so they are applied after the setups exist. + for (int32 Index = 0; Index < Movement->WheelSetups.Num(); ++Index) + { + UChaosVehicleWheel* Wheel = Movement->Wheels.IsValidIndex(Index) + ? Movement->Wheels[Index] : nullptr; + if (!Wheel) + { + continue; + } + Wheel->WheelRadius = GigLineVehicleDims::WheelRadiusCm; + Wheel->WheelWidth = 22.0f; + Wheel->bAffectedBySteering = Specs[Index].bSteer; + Wheel->bAffectedByEngine = Specs[Index].bDrive; + } +} + +void AGigLineVehicle::BeginPlay() +{ + Super::BeginPlay(); + ConfigureWheels(); + UE_LOG(LogTemp, Warning, TEXT("GigLine vehicle: spawned at (%.0f, %.0f, %.0f), %d wheel setups"), + GetActorLocation().X, GetActorLocation().Y, GetActorLocation().Z, + GetVehicleMovementComponent() + ? Cast(GetVehicleMovementComponent()) + ->WheelSetups.Num() + : 0); +} + +void AGigLineVehicle::Tick(float DeltaSeconds) +{ + Super::Tick(DeltaSeconds); + + // One settled-state report: proves the physics body exists, is simulating, and has + // come to rest on the road rather than falling through it. Everything else about the + // driving behaviour is measured later; this is the "is it real" check. + SettleElapsed += DeltaSeconds; + if (!bSettleReported && SettleElapsed > 3.0f) + { + bSettleReported = true; + const USkeletalMeshComponent* Body = GetMesh(); + UE_LOG(LogTemp, Warning, + TEXT("GigLine vehicle: settled at Z %.0f cm, simulating=%d, speed=%.0f cm/s"), + GetActorLocation().Z, + Body && Body->IsSimulatingPhysics() ? 1 : 0, + GetVehicleMovementComponent() ? GetVehicleMovementComponent()->GetForwardSpeed() : 0.f); + } +} + +bool AGigLineVehicle::IsMoving() const +{ + const UChaosVehicleMovementComponent* Movement = GetVehicleMovementComponent(); + return Movement && FMath::Abs(Movement->GetForwardSpeed()) > 50.0f; +} diff --git a/Game/GigLine/Source/GigLine/GigLineVehicle.h b/Game/GigLine/Source/GigLine/GigLineVehicle.h new file mode 100644 index 0000000..7020a17 --- /dev/null +++ b/Game/GigLine/Source/GigLine/GigLineVehicle.h @@ -0,0 +1,41 @@ +#pragma once + +#include "CoreMinimal.h" +#include "WheeledVehiclePawn.h" +#include "GigLineVehicle.generated.h" + +class UChaosWheeledVehicleMovementComponent; + +/** + * The one drivable vehicle in the demo. + * + * A skeletal mesh with a root bone and four wheel bones, driven by Chaos. Every + * dimension it configures — wheel radius, wheelbase, track — comes from the Blender + * build's report rather than being typed twice: the numbers are repeated here as + * constants with the report path in the comment so a change to the model shows up as a + * mismatch instead of a silent drift. + * + * Model: `Art/blender/vehicle/gigline-sedan.blend`, report `Art/blender/vehicle/report.json` + * (4.72 x 1.80 x 1.44 m, wheelbase 2.78 m, track 1.62 m, wheel radius 0.33 m). + */ +UCLASS() +class GIGLINE_API AGigLineVehicle : public AWheeledVehiclePawn +{ + GENERATED_BODY() + +public: + AGigLineVehicle(); + + virtual void BeginPlay() override; + virtual void Tick(float DeltaSeconds) override; + + /** True once the vehicle reports a forward speed above a walking pace. */ + bool IsMoving() const; + +private: + /** Configure the Chaos wheels from the modelled dimensions. */ + void ConfigureWheels(); + + float SettleElapsed = 0.f; + bool bSettleReported = false; +}; diff --git a/Game/GigLine/Source/GigLine/GigLineVehicleBuilder.cpp b/Game/GigLine/Source/GigLine/GigLineVehicleBuilder.cpp new file mode 100644 index 0000000..42c8a79 --- /dev/null +++ b/Game/GigLine/Source/GigLine/GigLineVehicleBuilder.cpp @@ -0,0 +1,69 @@ +#include "GigLineVehicleBuilder.h" + +#if WITH_EDITOR +#include "AssetToolsModule.h" +#include "Engine/SkeletalMesh.h" +#include "PhysicsAssetUtils.h" +#include "PhysicsEngine/PhysicsAsset.h" +#include "UObject/Package.h" +#endif + +UPhysicsAsset* UGigLineVehicleBuilder::BuildPhysicsAsset(USkeletalMesh* Mesh, + const FString& PackagePath, + const FString& AssetName) +{ +#if WITH_EDITOR + if (!Mesh) + { + UE_LOG(LogTemp, Warning, TEXT("GigLine vehicle: no skeletal mesh given")); + return nullptr; + } + + const FString FullName = PackagePath / AssetName; + UPackage* Package = CreatePackage(*FullName); + if (!Package) + { + UE_LOG(LogTemp, Warning, TEXT("GigLine vehicle: could not create package %s"), *FullName); + return nullptr; + } + UPhysicsAsset* PhysicsAsset = NewObject(Package, *AssetName, + RF_Public | RF_Standalone | RF_Transactional); + if (!PhysicsAsset) + { + UE_LOG(LogTemp, Warning, TEXT("GigLine vehicle: could not create %s"), *FullName); + return nullptr; + } + + // Boxes on the five bones: a root box and four wheel capsules is what a car needs; + // per-bone hulls from a 500-triangle mesh would add cost for nothing. + FPhysAssetCreateParams Params; + Params.MinBoneSize = 1.0f; + Params.GeomType = EFG_Box; + Params.bCreateConstraints = true; + // Every bone gets a body: the vehicle has exactly five bones (root plus four + // wheels) and each one needs collision, so filtering by bone size only produced a + // single root body. + Params.bBodyForAll = true; + Params.bWalkPastSmall = false; + Params.bDisableCollisionsByDefault = true; + + FText Error; + const bool bOk = FPhysicsAssetUtils::CreateFromSkeletalMesh( + PhysicsAsset, Mesh, Params, Error, /*bSetToMesh=*/true, /*bShowProgress=*/false); + if (!bOk) + { + UE_LOG(LogTemp, Warning, TEXT("GigLine vehicle: physics asset build failed: %s"), + *Error.ToString()); + return nullptr; + } + + PhysicsAsset->MarkPackageDirty(); + UE_LOG(LogTemp, Warning, TEXT("GigLine vehicle: physics asset %s with %d bodies"), + *FullName, PhysicsAsset->SkeletalBodySetups.Num()); + return PhysicsAsset; +#else + UE_LOG(LogTemp, Warning, + TEXT("GigLine vehicle: physics asset generation is editor-only")); + return nullptr; +#endif +} diff --git a/Game/GigLine/Source/GigLine/GigLineVehicleBuilder.h b/Game/GigLine/Source/GigLine/GigLineVehicleBuilder.h new file mode 100644 index 0000000..146823a --- /dev/null +++ b/Game/GigLine/Source/GigLine/GigLineVehicleBuilder.h @@ -0,0 +1,34 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "GigLineVehicleBuilder.generated.h" + +class UPhysicsAsset; +class USkeletalMesh; + +/** + * Script-callable helpers for vehicle setup. + * + * Chaos Vehicles need a PhysicsAsset, and Unreal's `PhysicsAssetFactory` exposes no mesh + * property to Python, so the asset cannot be generated from a commandlet. The body does + * the job with `FPhysicsAssetUtils::CreateFromSkeletalMesh`, which is the same code path + * the editor's "Create Physics Asset" action uses. + * + * Editor only: it is compiled into the editor target and never shipped. + */ +UCLASS() +class GIGLINE_API UGigLineVehicleBuilder : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + /** + * Build (or rebuild) a physics asset for `Mesh` at `PackagePath`/`AssetName`. + * + * @return the created asset, or nullptr with the reason written to the log. + */ + UFUNCTION(BlueprintCallable, Category = "GigLine|Vehicle") + static UPhysicsAsset* BuildPhysicsAsset(USkeletalMesh* Mesh, const FString& PackagePath, + const FString& AssetName); +}; diff --git a/TODO.md b/TODO.md index a7b6c56..cda6b29 100644 --- a/TODO.md +++ b/TODO.md @@ -16,10 +16,12 @@ Actionable task list for this project. This file is the single, central place fo - [A] Model one vehicle in Blender with collision meshes; export to Unreal. **Model done** (`Tools/vehicle_build.py` → `Art/blender/vehicle/gigline-sedan.blend`, preview in `Art/blender/vehicle/preview.png`): 4.72 x 1.80 x 1.44 m, 2.78 m wheelbase, 1.62 m track, 0.33 m wheels, 252 triangles, four `UCX_` convex hulls. Dimensions come from real sedan figures and are logged to the report, so the vehicle config can read them rather than restating them. - **Imported into Unreal** (`Tools/ue_vehicle_import.py` → `/Game/Hollywood/Vehicle`), split per the vehicle-artist object split: `SM_Vehicle_Body` (3 slots, 4.76 x 1.76 x 1.28 m), `SM_Vehicle_Glass`, `SM_Vehicle_Light_Front`, `SM_Vehicle_Light_Rear`, `SM_Vehicle_Mirrors`, and one `SM_Vehicle_Wheel` (0.22 x 0.66 x 0.66 m) reused four times. The body FBX carries the `UCX_` hulls as simple collision. - **LODs cut for real:** decimating the duplicate gives LOD1 at 38 triangles and LOD2 at 14, against 132 for LOD0. The first attempt duplicated the shell unchanged and produced 84-triangle LODs that saved nothing - worth remembering as the failure mode of a "LOD" step nobody measures. - **LOD group wiring is open:** `StaticMeshEditorSubsystem.import_lod` is unavailable in a headless commandlet (`get_editor_subsystem` returns None), so the LOD meshes import as their own assets and the group still needs an editor session. -- [A] Set up Chaos Vehicle with wheel and physics configuration. **Blocked on the physics asset, which cannot be generated headless.** - - **Skeletal vehicle asset is in** (`SK_Vehicle_Sedan` + `SK_Vehicle_Sedan_Skeleton`): one mesh carrying a root bone and four wheel bones, every wheel skinned to its own bone, exported with the character preset (508 triangles). Chaos drives a skeletal mesh, so the static split alone was not drivable. - - **Blocked:** Chaos needs a `PhysicsAsset`, and `unreal.PhysicsAssetFactory` in 5.8 exposes **no mesh property** (`Failed to find property 'skeletal_mesh'`), so the bodies cannot be generated from the skeletal mesh in a commandlet. Options: author it once in the editor and commit it, or build it in C++ with `FPhysicsAssetUtils` in an editor utility. - - **Next:** create the physics asset (root box + four wheel capsules at the modelled positions: wheelbase 2.78 m, track 1.62 m, radius 0.33 m), then the `UChaosWheeledVehicleMovementComponent` config reads those same numbers from `Art/blender/vehicle` report. +- [~] Set up Chaos Vehicle with wheel and physics configuration. **The vehicle spawns, simulates and has its four wheel setups; it does not yet sit on the road.** + - **Physics asset generated from script.** `unreal.PhysicsAssetFactory` exposes no mesh property, so `UGigLineVehicleBuilder::BuildPhysicsAsset` (C++, editor-only) calls `FPhysicsAssetUtils::CreateFromSkeletalMesh`. Result: `PA_Vehicle_Sedan` with **6 bodies**, assigned to `SK_Vehicle_Sedan`. + - **Vehicle class in place.** `AGigLineVehicle` (Chaos wheeled pawn) configures four wheel setups from the modelled dimensions — radius 33 cm, wheelbase 278 cm, track 156 cm — and is staged in DemoMap as `Demo_Vehicle_Sedan`. A run logs `spawned at (-12950, -900, 120), 4 wheel setups`. + - **Defect:** it settles at **Z 494 cm** instead of road level (spawned at 120). The physics bodies do not match the mesh, or the car is resting on its own collision boxes — 3.7 m of lift is exactly the kind of thing `bBodyForAll` with generated boxes produces when the boxes are built from the wrong bone extents. + - **Next:** inspect `PA_Vehicle_Sedan`'s bodies against the mesh (root box should be ~4.7 x 1.8 x 0.5 m, wheels ~0.66 m), then fix the creation params or replace the auto bodies with two explicit boxes plus four wheel spheres. + - **Also open:** LOD group wiring, enter/exit, driving route, handling. - [ ] Implement enter/exit interaction. - [ ] Build a closed driving route with boundaries. - [ ] Tune basic handling to a drivable state. diff --git a/Tools/ue_build_demo_map.py b/Tools/ue_build_demo_map.py index aae4dc4..6ed7616 100644 --- a/Tools/ue_build_demo_map.py +++ b/Tools/ue_build_demo_map.py @@ -647,6 +647,17 @@ def build(): unreal.Rotator(pitch=0.0, yaw=90.0, roll=0.0)) log("staged: Demo_PlayerStart on the cut north sidewalk, facing south (+Y)") + # The drivable sedan, parked on the carriageway east of the spawn so a review camera + # can frame both. Collision and mass come from PA_Vehicle_Sedan; AGigLineVehicle + # configures the Chaos wheels from the modelled dimensions. + vehicle_class = unreal.load_class(None, "/Script/GigLine.GigLineVehicle") + if vehicle_class: + vehicle = spawn(vehicle_class, unreal.Vector(-12950.0, -900.0, 120.0), + "Demo_Vehicle_Sedan") + log(f"staged: Demo_Vehicle_Sedan ({'ok' if vehicle else 'FAILED'})") + else: + log("staged: Demo_Vehicle_Sedan skipped - class not found") + # A lockable LFS .umap checks out read-only, which makes save_map silently # return False — chmod u+w first or the staged actors never persist. umap = os.path.join(unreal.Paths.project_dir(), MAP.replace("/Game/", "Content/") + ".umap")