diff --git a/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.cpp b/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.cpp index ccf326da2..358f7664d 100644 --- a/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.cpp +++ b/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.cpp @@ -240,9 +240,34 @@ void ACarPawn::EndPlay(const EEndPlayReason::Type EndPlayReason) Super::EndPlay(EndPlayReason); } +void ACarPawn::FellOutOfWorld(const UDamageType& dmgType) +{ + // The engine destroys actors that drop below the level's KillZ, but AirSim keeps using its + // vehicle pawns and crashes on a destroyed one. Keep the vehicle and put it back at its start + // pose on the next tick: this is called from the physics sync, which overrides a teleport here. + if (!fell_out_of_world_) { + UE_LOG(LogTemp, Warning, TEXT("%s fell out of the world; moving it back to its start pose"), *GetName()); + UAirBlueprintLib::LogMessage(GetName(), TEXT("fell out of the world and was moved back to its start pose"), LogDebugLevel::Failure); + } + fell_out_of_world_ = true; +} + +void ACarPawn::respawnIfFellOutOfWorld() +{ + if (!fell_out_of_world_) + return; + fell_out_of_world_ = false; + for (UPrimitiveComponent* phys_comp : UAirBlueprintLib::getPhysicsComponents(this)) { + phys_comp->SetPhysicsLinearVelocity(FVector::ZeroVector); + phys_comp->SetPhysicsAngularVelocityInDegrees(FVector::ZeroVector); + } + SetActorTransform(start_transform_, false, nullptr, ETeleportType::TeleportPhysics); +} + void ACarPawn::Tick(float Delta) { Super::Tick(Delta); + respawnIfFellOutOfWorld(); // update physics material updatePhysicsMaterial(); @@ -264,6 +289,7 @@ void ACarPawn::Tick(float Delta) void ACarPawn::BeginPlay() { Super::BeginPlay(); + start_transform_ = GetActorTransform(); // Start an engine sound playing engine_sound_audio_->Play(); diff --git a/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.h b/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.h index f8637b7bc..50447b892 100644 --- a/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.h +++ b/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.h @@ -37,6 +37,7 @@ class ACarPawn : public AWheeledVehiclePawn virtual void BeginPlay() override; virtual void Tick(float Delta) override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + virtual void FellOutOfWorld(const class UDamageType& dmgType) override; virtual void NotifyHit(class UPrimitiveComponent* MyComp, class AActor* Other, class UPrimitiveComponent* OtherComp, bool bSelfMoved, FVector HitLocation, FVector HitNormal, FVector NormalImpulse, const FHitResult& Hit) override; @@ -53,6 +54,11 @@ class ACarPawn : public AWheeledVehiclePawn return keyboard_controls_; } +private: + void respawnIfFellOutOfWorld(); + FTransform start_transform_; + bool fell_out_of_world_ = false; + private: void updateHUDStrings(); void setupVehicleMovementComponent(); diff --git a/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.cpp b/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.cpp index 917a9b768..e083e22ae 100755 --- a/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.cpp +++ b/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.cpp @@ -244,9 +244,34 @@ void ASkidVehiclePawn::EndPlay(const EEndPlayReason::Type EndPlayReason) Super::EndPlay(EndPlayReason); } +void ASkidVehiclePawn::FellOutOfWorld(const UDamageType& dmgType) +{ + // The engine destroys actors that drop below the level's KillZ, but AirSim keeps using its + // vehicle pawns and crashes on a destroyed one. Keep the vehicle and put it back at its start + // pose on the next tick: this is called from the physics sync, which overrides a teleport here. + if (!fell_out_of_world_) { + UE_LOG(LogTemp, Warning, TEXT("%s fell out of the world; moving it back to its start pose"), *GetName()); + UAirBlueprintLib::LogMessage(GetName(), TEXT("fell out of the world and was moved back to its start pose"), LogDebugLevel::Failure); + } + fell_out_of_world_ = true; +} + +void ASkidVehiclePawn::respawnIfFellOutOfWorld() +{ + if (!fell_out_of_world_) + return; + fell_out_of_world_ = false; + for (UPrimitiveComponent* phys_comp : UAirBlueprintLib::getPhysicsComponents(this)) { + phys_comp->SetPhysicsLinearVelocity(FVector::ZeroVector); + phys_comp->SetPhysicsAngularVelocityInDegrees(FVector::ZeroVector); + } + SetActorTransform(start_transform_, false, nullptr, ETeleportType::TeleportPhysics); +} + void ASkidVehiclePawn::Tick(float Delta) { Super::Tick(Delta); + respawnIfFellOutOfWorld(); USkeletalMeshComponent* mesh = CastChecked(getVehicleMesh()); if (mesh->GetPhysicsAngularVelocityInDegrees().Size() > max_angular_velocity_) @@ -274,6 +299,7 @@ void ASkidVehiclePawn::Tick(float Delta) void ASkidVehiclePawn::BeginPlay() { Super::BeginPlay(); + start_transform_ = GetActorTransform(); // Start an engine sound playing engine_sound_audio_->Play(); diff --git a/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.h b/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.h index ebae31912..0ef0b2c3f 100644 --- a/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.h +++ b/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.h @@ -37,6 +37,7 @@ class ASkidVehiclePawn : public AWheeledVehiclePawn virtual void BeginPlay() override; virtual void Tick(float Delta) override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + virtual void FellOutOfWorld(const class UDamageType& dmgType) override; virtual void NotifyHit(class UPrimitiveComponent* MyComp, class AActor* Other, class UPrimitiveComponent* OtherComp, bool bSelfMoved, FVector HitLocation, FVector HitNormal, FVector NormalImpulse, const FHitResult& Hit) override; @@ -64,6 +65,11 @@ class ASkidVehiclePawn : public AWheeledVehiclePawn UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "SkidVehicle|General") bool stop_turn_ = false; +private: + void respawnIfFellOutOfWorld(); + FTransform start_transform_; + bool fell_out_of_world_ = false; + private: void updateHUDStrings(); void setupVehicleMovementComponent();