50 USkeletalMeshComponent *WalkerMesh = GetMesh();
51 if (WalkerMesh ==
nullptr)
53 UE_LOG(LogCarla, Warning,
54 TEXT(
"Wheelchair: walker %s has no mesh, spawning as normal pedestrian"),
61 auto *ChairMesh = Cast<USkeletalMesh>(FSoftObjectPath(
62 TEXT(
"/Game/Carla/Static/Pedestrian/Prop_Wheelchair/Meshes_/SM_Wheelchair.SM_Wheelchair"))
64 auto *SittingAnim = Cast<UAnimSequence>(FSoftObjectPath(
65 TEXT(
"/Game/Carla/Static/Pedestrian/Animations/WheelchairUser/WheelchairSitting_Moving2.WheelchairSitting_Moving2"))
67 if (ChairMesh ==
nullptr || SittingAnim ==
nullptr)
69 UE_LOG(LogCarla, Warning,
70 TEXT(
"Wheelchair: content not available (mesh=%d anim=%d), walker %s stays a normal pedestrian"),
71 ChairMesh !=
nullptr, SittingAnim !=
nullptr, *GetName());
85 WalkerMesh, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
98 constexpr float RiderDrop = 25.0f;
99 WalkerMesh->AddLocalOffset(FVector(0.0f, 0.0f, -RiderDrop));
105 const TCHAR *ChairAnimMode = TEXT(
"none");
106 auto *ChairAnimClass = Cast<UClass>(FSoftObjectPath(
107 TEXT(
"/Game/Carla/Static/Pedestrian/Animations/Wheelchair/ABP_WheelChair_MK.ABP_WheelChair_MK_C"))
109 if (ChairAnimClass !=
nullptr && !ChairAnimClass->HasAnyClassFlags(CLASS_NewerVersionExists))
112 ChairAnimMode = TEXT(
"ABP_WheelChair_MK");
114 else if (
auto *RollingAnim = Cast<UAnimSequence>(FSoftObjectPath(
115 TEXT(
"/Game/Carla/Static/Pedestrian/Animations/Wheelchair/Wheelchair_Rolling.Wheelchair_Rolling"))
119 ChairAnimMode = TEXT(
"Wheelchair_Rolling loop");
127 WalkerMesh->PlayAnimation(SittingAnim,
true);
131 UE_LOG(LogCarla, Display,
132 TEXT(
"Wheelchair attached to walker %s (chair anim: %s, rider anim: WheelchairSitting_Moving2 loop)"),
133 *GetName(), ChairAnimMode);
156 TArray<UPrimitiveComponent *> Primitives;
157 GetComponents<UPrimitiveComponent>(Primitives,
false);
158 for (UPrimitiveComponent *Primitive : Primitives)
160 const ECollisionEnabled::Type Enabled = Primitive->GetCollisionEnabled();
161 if (Enabled == ECollisionEnabled::QueryAndPhysics)
163 Primitive->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
165 else if (Enabled == ECollisionEnabled::PhysicsOnly)
167 Primitive->SetCollisionEnabled(ECollisionEnabled::NoCollision);
175 if (Primitive->GetCollisionObjectType() == ECC_WorldDynamic)
177 Primitive->SetCollisionObjectType(ECC_Pawn);
185 TArray<UPrimitiveComponent *> Primitives;
186 GetComponents<UPrimitiveComponent>(Primitives,
false);
187 for (UPrimitiveComponent *Primitive : Primitives)
189 Primitive->SetGenerateOverlapEvents(
false);
201 GetWorldTimerManager().SetTimer(
246 const UCapsuleComponent *Capsule = GetCapsuleComponent();
247 if (Capsule ==
nullptr)
252 const float HalfHeight = Capsule->GetScaledCapsuleHalfHeight();
264 const float QueryRadius =
267 TArray<FOverlapResult> Overlaps;
268 FCollisionObjectQueryParams ObjectParams;
269 ObjectParams.AddObjectTypesToQuery(ECC_Vehicle);
270 FCollisionQueryParams Params(SCENE_QUERY_STAT(WalkerVehicleSensor),
false,
this);
271 if (!GetWorld()->OverlapMultiByObjectType(
276 FCollisionShape::MakeCapsule(QueryRadius, HalfHeight),
282 const FVector WalkerLoc = GetActorLocation();
283 for (
const FOverlapResult &Overlap : Overlaps)
286 UPrimitiveComponent *VehicleBody = Overlap.GetComponent();
287 if (
Vehicle ==
nullptr || VehicleBody ==
nullptr)
291 const FVector Velocity =
Vehicle->GetVelocity();
292 const float Speed = Velocity.Size();
300 const float DistToBody =
301 VehicleBody->GetDistanceToCollision(WalkerLoc, OnBody);
302 bool bKill = DistToBody >= 0.0f && DistToBody <= ContactRadius;
308 const FVector PathEnd = FVector(
Vehicle->GetActorLocation()) + Velocity * Dt * 1.25f;
309 const FVector Closest = FMath::ClosestPointOnSegment(
310 WalkerLoc,
Vehicle->GetActorLocation(), PathEnd);
311 bKill = FVector::Dist2D(Closest, WalkerLoc) <=
313 FMath::Abs(Closest.Z - WalkerLoc.Z) <= HalfHeight + 200.0f;
334 if (
auto *WalkerController = Cast<AWalkerController>(GetController()))
336 WalkerController->StopNavigation();
339 if (
auto *Movement = GetCharacterMovement())
341 Movement->StopMovementImmediately();
342 Movement->DisableMovement();
350 if (
auto *Capsule = GetCapsuleComponent())
352 Capsule->SetCollisionResponseToChannel(ECC_Vehicle, ECR_Ignore);
359 if (Killer !=
nullptr)
361 FHitResult FakeHit(ForceInit);
362 FakeHit.HitObjectHandle = FActorInstanceHandle(
this);
363 FakeHit.ImpactPoint = GetActorLocation();
364 FakeHit.ImpactNormal = (-ImpactVelocity).GetSafeNormal();
365 Killer->OnActorHit.Broadcast(Killer,
this,
366 ImpactVelocity * 100.0f , FakeHit);
369 USkeletalMeshComponent *BodyMesh = GetMesh();
370 bool bDeterministic =
true;
373 bDeterministic = Episode->GetSettings().bDeterministicRagdolls;
376 if (BodyMesh !=
nullptr && !bDeterministic)
383 BodyMesh->SetCollisionProfileName(TEXT(
"Ragdoll"));
384 BodyMesh->SetCollisionResponseToChannel(ECC_Vehicle, ECR_Ignore);
385 BodyMesh->SetSimulatePhysics(
true);
386 BodyMesh->SetAllPhysicsLinearVelocity(ImpactVelocity,
false);
388 else if (BodyMesh !=
nullptr)
393 const FVector LocalDir =
394 GetActorTransform().InverseTransformVectorNoScale(
395 ImpactVelocity.GetSafeNormal2D());
396 const TCHAR *AnimName;
397 if (FMath::Abs(LocalDir.X) >= FMath::Abs(LocalDir.Y))
400 AnimName = LocalDir.X >= 0.0f
401 ? TEXT(
"/Game/Carla/Animations/Death_Anim/Anim_Death_F_01.Anim_Death_F_01")
402 : TEXT(
"/Game/Carla/Animations/Death_Anim/Anim_Death_B_01.Anim_Death_B_01");
406 AnimName = LocalDir.Y >= 0.0f
407 ? TEXT(
"/Game/Carla/Animations/Death_Anim/Anim_Death_R_01.Anim_Death_R_01")
408 : TEXT(
"/Game/Carla/Animations/Death_Anim/Anim_Death_L_01.Anim_Death_L_01");
410 if (
auto *DeathAnim = Cast<UAnimSequence>(
411 StaticLoadObject(UAnimSequence::StaticClass(),
nullptr, AnimName)))
413 BodyMesh->PlayAnimation(DeathAnim,
false);
417 UE_LOG(LogCarla, Warning,
418 TEXT(
"Walker %s: death animation '%s' not found, using ragdoll"),
419 *GetName(), AnimName);
420 BodyMesh->SetCollisionProfileName(TEXT(
"Ragdoll"));
421 BodyMesh->SetCollisionResponseToChannel(ECC_Vehicle, ECR_Ignore);
422 BodyMesh->SetSimulatePhysics(
true);
423 BodyMesh->SetAllPhysicsLinearVelocity(ImpactVelocity,
false);
430 if (BodyMesh !=
nullptr && !BodyMesh->IsSimulatingPhysics())
432 BodyMesh->SetCollisionResponseToChannel(ECC_Vehicle, ECR_Ignore);
435 UE_LOG(LogCarla, Log, TEXT(
"Walker %s killed by vehicle impact (%.0f cm/s)"),
436 *GetName(), ImpactVelocity.Size());
void Kill(FVector ImpactVelocity, AActor *Killer=nullptr)
Kill the walker as if run over: stop navigation and movement, stop blocking vehicles,...