For our AI Character class, when they die, we ragdoll them, let the ragdoll settle, then spawn a poseablemesh class I call ACorpse to provide a lightweight corpse without having to keep the Character class alive. This works great up to a point. I’ve been scratching my head on the problem I ran into for over a day and I thought I better ask if anyone else has seen something like this.
First the blueprint for the character class gets an event to turn on physics, drop the AI’s weapon, let the ragdoll settle, then calls the C++ function to spawn the corpse and poke its mesh reference in to it so the socket copy can be done for the bone rotations. The Corpse class, on BeginPlay, locates its poseablemesh, sets the bone transforms and makes the new poseable mesh visible. After a couple of seconds, the AI class destroys itself and all that is left is the corpse. Works flawlessly. That is until I wanted to add corpse looting to it.
The problem appears when I parent the corpse class to our item class. The item class is just a wrapper to provide items to any Actor in our game. The idea is that with the item class in the hierarchy, the corpse class will then have some items which the player can loot. When I parent the corpse class to our item class, the poseablemesh T stances rather than the bone copy working correctly. The item class is rather simple, and just contains a list of items that can be picked up if the player looks at its either visible or invisible static mesh. It is not related to having the static mesh there since I’ve tested with having no item class static mesh and the results are the same.
The bottom line is I can only make the poseablemesh accept the bone transforms if I keep the actor class (containing the poseablemesh component) directly parented to AActor. Anyone know what might disturb the poseablemesh component in this manner?
Character Blueprint when AI Death is signaled:
Character class Corpse Spawner:
void AAICharacter::SpawnDestroyedActor() {
UE_LOG(LogTemp,Error,TEXT("AICharacter: SpawnDestroyedActor has started"));
if(DestroyedVersion != nullptr) {
ACorpse* AICorpse;
AICorpse = Cast<ACorpse>(SpawnBPDeferred<ACorpse>(GetWorld(), DestroyedVersion, this->GetActorLocation(), this->GetActorRotation()));
AICorpse->MeshReference=MeshReference; //Poke the Mesh Ref into Corpse class to let it copy bone transforms
AICorpse->FinishSpawning(this->GetActorTransform());
} else {
UE_LOG(LogTemp,Error,TEXT("AICharacter: Failed to find DestroyedVersion"));
}
FinalizeDeath(); //Destroy this AI
}
Corpse Class BeginPlay (no other code in this class):
void ACorpse::BeginPlay()
{
UE_LOG(LogTemp,Warning,TEXT("Corpse: Beginning Corpse Bone Copy"));
TArray<UPoseableMeshComponent*> comps;
this->GetComponents<UPoseableMeshComponent>(comps);
if(comps.Num()>0) {
PoseableMeshReference=comps[0];
} else {
UE_LOG(LogTemp,Error,TEXT("Corpse: Failed to get poseable mesh component"));
}
TArray<FName> AllSockets = MeshReference->GetAllSocketNames();
for(int32 i=0;i<AllSockets.Num();i++) {
PoseableMeshReference->SetBoneTransformByName(AllSockets*, MeshReference->GetSocketTransform(AllSockets*),EBoneSpaces::WorldSpace);
UE_LOG(LogTemp,Error,TEXT("Corpse: Setting socket name %s"),*AllSockets*.ToString());
}
Super::BeginPlay();
PoseableMeshReference->SetHiddenInGame(false);
}