I am trying to use a Timeline to animate a button being pressed. Below is the code for the button class
BasicButton.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameFramework/Actor.h"
#include "BasicButton.generated.h"
/**
*
*/
UCLASS()
class SPACEPUZZLE_API ABasicButton : public AActor
{
GENERATED_BODY()
ABasicButton(const class FObjectInitializer& ObjectInitializer);
virtual void BeginPlay() override;
virtual void ReceiveHit
(
UPrimitiveComponent* MyComponent,
AActor* OtherActor,
UPrimitiveComponent* OtherComponent,
bool bSelfMoved, FVector HitLocation,
FVector HitNormal, FVector NormalImpulse,
const FHitResult& Hit
) override; //Overide the RecieveHit function from AActor to define custom behaviour
float DELTATIME;
UFUNCTION()
void Anim_UpdateProgress(FVector Vec); // Function that will update the buttons position
UFUNCTION()
void Anim_TickTimeline();
UFUNCTION()
void Anim_AnimateButton();
protected:
public:
//PROPERTY
UPROPERTY(BlueprintReadWrite, Category = Components)
UPrimitiveComponent* ButtonMesh; //Pointer to the Buttons MeshComponent (To be set in Blueprints)
UPROPERTY(BlueprintReadWrite, Category = Components)
UCurveVector* Anim_VectorCurve; //Pointer to the Vector Curve used in the Animation Timeline
UPROPERTY()
float Anim_DeltaTime; //Stepsize for the timer that will tick the timeline;
UPROPERTY()
FTimeline Anim_Timeline; //Timeline that will animate the button
//FUNCTION
};
BasicButton.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "SpacePuzzle.h"
#include "BasicButton.h"
ABasicButton::ABasicButton(const class FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
const ConstructorHelpers::FObjectFinder<UCurveVector> Curve(TEXT("CurveVector'/Game/Blueprints/Functionals/Anim_ButtonCurve.Anim_ButtonCurve'"));
DELTATIME = 1.f;
FOnTimelineVector ProgressDelegate{}; //Setup a Delegate to pass the Timeline. Tis will be bound to Anim_UpdateProgress()
ProgressDelegate.BindUFunction(this, "Anim_UpdateProgress"); // Bind the delegate to our update function
Anim_Timeline.AddInterpVector(Anim_VectorCurve, ProgressDelegate);
}
void ABasicButton::BeginPlay()
{
Super::BeginPlay();
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Using Basic Button"));
}
}
void ABasicButton::ReceiveHit(UPrimitiveComponent* MyComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, bool bSelfMoved, FVector HitLocation, FVector HitNormal, FVector NormalImpulse, const FHitResult& Hit)
{
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("HIT"));
}
if (!Anim_Timeline.IsPlaying())
{
Anim_AnimateButton();
}
}
void ABasicButton::Anim_TickTimeline()
{
if (Anim_Timeline.IsPlaying())
{
Anim_Timeline.TickTimeline(DELTATIME);
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("TRYING TO Tick Timeline!"));
}
else
{
UWorld* World = GetWorld();
if (World)
{
GetWorldTimerManager().ClearTimer(this, &ABasicButton::Anim_TickTimeline);
}
}
}
void ABasicButton::Anim_UpdateProgress(FVector Vec)
{
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("TRYING TO PLAY"));
}
//This function is called when the timline ticks and should move the button
if (ButtonMesh != NULL)
{
FVector MoveLocation = ButtonMesh->GetComponentLocation() + Vec;
ButtonMesh->MoveComponent(Vec, ButtonMesh->GetComponentRotation(), false);
}
}
void ABasicButton::Anim_AnimateButton()
{
//This Function should begin playback of the animation timeline
//Begin a clock that will tick with the timeline
UWorld* World = GetWorld();
if (World)
{
Anim_Timeline.PlayFromStart();
FTimerHandle TimerHandle;
GetWorldTimerManager().SetTimer(TimerHandle, this, &ABasicButton::Anim_TickTimeline, DELTATIME, true, 0.0f);
}
}
When the Button object receives a Hit the game crashes and gives the following error
Access violation - code c0000005 (first/second chance not available)
UE4Editor_Engine + 2542179 bytes
UE4Editor_Engine + 8907614 bytes
UE4Editor_Engine + 8945910 bytes
UE4Editor_Engine + 9050082 bytes
UE4Editor_SpacePuzzle!ABasicButton::Anim_TickTimeline() + 65 bytes [d:\ut4project\spacepuzzle\source\spacepuzzle\basicbutton.cpp:49]
UE4Editor_Engine + 8866299 bytes
UE4Editor_Engine + 9047929 bytes
UE4Editor_Engine + 5623214 bytes
UE4Editor_UnrealEd + 1803906 bytes
UE4Editor_UnrealEd + 6686342 bytes
UE4Editor!FEngineLoop::Tick() + 3876 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.6\engine\source\runtime\launch\private\launchengineloop.cpp:2214]
UE4Editor!GuardedMain() + 479 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.6\engine\source\runtime\launch\private\launch.cpp:131]
UE4Editor!GuardedMainWrapper() + 26 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.6\engine\source\runtime\launch\private\windows\launchwindows.cpp:126]
UE4Editor!WinMain() + 249 bytes [d:\buildfarm\buildmachine_++depot+ue4-releases+4.6\engine\source\runtime\launch\private\windows\launchwindows.cpp:202]
UE4Editor!__tmainCRTStartup() + 329 bytes [f:\dd\vctools\crt\crtw32\dllstuff\crtexe.c:618]
Through a process of elimination I have been able to narrow this crash down to the Anim_TickTimeLine() function, specifically the line:
Anim_Timeline.TickTimeline(DELTATIME);
If I comment this line out I see the debug message “Trying to Tick Timeline!” periodically be printed to the screen, until after 5 seconds have passed (The length of the curve) at which point the messages stop.
Can anyone see why the timeline is not ticking? Perhaps there is some initialization required before the timeline is ready to be ticked?