I have been testing this further, I rewrote all blueprint parts into code, and the problem remained.
I now have only 2 blueprints remaining in my game now, these are the AnimationBlueprint(with basic setup and named slot) and the HUD blueprint.
Once I switched to using my c++ gamemode class instead of blueprinted one for my world settings,
I avoided problems with spawning blueprints I had in the Question link - posted above,
and then I also changed my character to be a C++ class, not a blueprint so that problem is now avoided twice.
Anyway to get back to the topic, I tested 3 ways of playing animation from the Character class:
1.PlayAnimMontage (didn’t work)
2.PlayAnimation (works)
3.MontagePlay (works, but you need to cast your AnimInstance to Character class)
and again I can confirm PlayAnimMontage() returns 0.0 duration right off, like it wouldn’t be able to find the UAnimMontage or the skeletalMesh. Then I looked at the code again, and discovered the problem, when I called PlayAnimMontage, I called it in my character class, and character.h parent class has a variable “Mesh” so you can use that to plug in your skeletal mesh , in other words when you call PlayAnimMontage() it will automatically want to play the animation on the “Mesh” , in my case I created FrogSkelMesh Subobject so that’s why it didn’t work,
once I plugged in my skeletalMesh to the “Mesh” instead, then it played fine.
Here’s the code:
First the Constructor part:
AJumpyFrogCharacter::AJumpyFrogCharacter()
{
struct FConstructorStatics
{
ConstructorHelpers::FObjectFinderOptional<USkeletalMesh> skelMesh;
ConstructorHelpers::FObjectFinderOptional<UMaterial> BlueMaterial;
ConstructorHelpers::FObjectFinderOptional<UMaterial> OrangeMaterial;
FConstructorStatics()
: skelMesh(TEXT("/Game/Characters/FrogChar/SkelMesh/FrogSkelMesh"))
, BlueMaterial(TEXT("Material'/Game/Characters/FrogChar/Materials/BlueDartFrog_mat.BlueDartFrog_Mat'"))
, OrangeMaterial(TEXT("/Game/Characters/FrogChar/Materials/OrangeFrog_Diffuse_Mat"))
{
}
};
static FConstructorStatics ConstructorStatics;
// Create dummy root scene component
DummyRoot = CreateDefaultSubobject<USceneComponent>(TEXT("Dummy0"));
RootComponent = DummyRoot;
// Create skeletal mesh component
FrogSkelMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Frog0"));
FrogSkelMesh->SetSkeletalMesh(ConstructorStatics.skelMesh.Get());
FrogSkelMesh->SetRelativeScale3D(FVector(1.f, 1.f, 0.25f));
FrogSkelMesh->SetRelativeLocation(FVector(0.f, 0.f, 0.6f));
FrogSkelMesh->SetMaterial(0, ConstructorStatics.OrangeMaterial.Get());
FrogSkelMesh->AttachTo(DummyRoot);
FrogSkelMesh->OnClicked.AddDynamic(this, &AJumpyFrogCharacter::FrogClicked);
FrogSkelMesh->OnInputTouchBegin.AddDynamic(this, &AJumpyFrogCharacter::OnFingerPressedFrog);
FrogSkelMesh->SetCollisionProfileName("BlockAll");
const ConstructorHelpers::FObjectFinder<UAnimBlueprint> AnimObj(TEXT("/Game/Characters/FrogChar/Blueprints/FrogAnimBP"));
FrogSkelMesh->SetAnimInstanceClass(AnimObj.Object->GeneratedClass);
Obviously I shouldn’t have created FrogSkelMesh but assign those things to the “Mesh” instead, so once I assigned my skeletal Mesh to the “Mesh” variable, then PlayAnimMontage worked:
GetMesh()->SetSkeletalMesh(ConstructorStatics.skelMesh.Get());
GetMesh()->SetAnimInstanceClass(AnimObj.Object->GeneratedClass);
1.PlayAnimMontage():
this->PlayAnimMontage(JumpRightMontage, 1);
2.PlayAnimation():
this->FrogSkelMesh->PlayAnimation(JumpRightMontage, 1);
3.MontagePlay():
UJumpyFrogsAnimInstance* AnInstnc = Cast<UJumpyFrogsAnimInstance>(FrogSkelMesh->GetAnimInstance());
if (AnInstnc)
{
AnInstnc->Montage_Play(JumpRightMontage, 1);
}
To wrap this up, it was basically a very little sloppy mistake, all I would need to do is assign my skeletal mesh to the “Mesh” inherited variable in the CharacterBlueprint, and for some reason when I was rebuilding this project I added a SkeletalMesh component instead of just using the “Mesh” variable, I’m including a screenshot.