Search code examples
c++unreal-blueprintunreal-engine5

Load and Set Skeletal Mesh and Animation at runtime


I have a generic vehicle class, derived from the standard AWheeledVehiclePawn and I would like to load and change skeletal mesh and wheels animation at runtime depending on a vehicle type enum in input.

If I spawnm cars and set these assets from the editor, everything works fine, but if I try to set them programmatically from code, only the mesh is set, the animation is not working (wheels just not spinning / steering).

So the question is: how to set these two assets at runtime (or other approach, how to have a generic animation that works for all the different vehicle models and minimize the setup from code)?

Thanks!

Here some code:

UCLASS()
class MY_API ACar : public AWheeledVehiclePawn
{
    GENERATED_UCLASS_BODY()
public:
    void SetEntityType(const EntityType& type);
private:
    void SetMeshAndAnim();
...

} 


ACar::ACar(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{

    meshReferenceFolders_.Add(EntityType::Car1, L"Car1");
    ...    
    meshReferenceFolders_.Add(EntityType::CarN, L"CarN");

    for (auto& meshPath : meshReferenceFolders_)
    {

        ConstructorHelpers::FObjectFinder<USkeletalMesh> mesh(
            std::wstring(L"SkeletalMesh'" + ModelFolder + meshPath.Value + L"/" + meshPath.Value + L"." + meshPath.Value + L"'").data()
        );

        ConstructorHelpers::FObjectFinder<USkeleton> skeleton(
            std::wstring(L"Skeleton'" + ModelFolder + meshPath.Value + L"/" + meshPath.Value + L"_Skeleton." + meshPath.Value + L"_Skeleton'").data()
        );

        if (skeleton.Object) mesh.Object->SetSkeleton(skeleton.Object);


        ConstructorHelpers::FObjectFinder<UAnimBlueprint> animation(
            std::wstring(L"UAnimBlueprint'" + ModelFolder + meshPath.Value + L"/" + meshPath.Value + L"_AnimBlueprint." + meshPath.Value + L"_AnimBlueprint'").data()
        );


        meshes_.Add(meshPath.Key, mesh.Object);
        anims_.Add(meshPath.Key, animation.Object);
    }
}

void ACar::SetEntityType(const EntityType& type)
{
    carType_ = type;
    SetMeshAndAnim();
}

void ACar::SetMeshAndAnim()
{
    GetMesh()->SetSkeletalMesh(meshes_[carType_]);
    GetMesh()->SetAnimInstanceClass(anims_[carType_]->GeneratedClass);

}

caller

void UManager::UManager()
{
...
    static ConstructorHelpers::FObjectFinder<UBlueprint> asset(
        TEXT("Blueprint'/Game/Blueprints/BPCar.BPCar'")
    );
    if (asset.Object)
    {
        importedCarInstance= asset.Object->GeneratedClass;
    }
...
}

void UManager::TickComponent(
    float                        DeltaTime,
    ELevelTick                   TickType,
    FActorComponentTickFunction* ThisTickFunction
)
{
...
    if (spawn)
    {
        auto car = World->SpawnActor<ACar>(importedCarInstance, location, rotation, spawnParameters);
        car->SetEntityType(obj.type);
    }
}

Solution

  • For some unknown reasons I found that there was no controller associated to the spawned actor, and then the ChaosVehicleComponent was not able to set the throttle and steering values provided. To solve this, I just added an AIController, move all the automatic movement logic there, and associated it to my car when created