Hi i have written a basic code for an complex elevator. I am unsure as to why it is not working. Any help would be appreciated. The SetLiftCall() function receives input from character class about which floor the player pressed the button from(ECFloorNo) and whether the player pressed the up button(ElevatorUpCallStatus).
Elevator.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/TimelineComponent.h"
#include "Elevator.generated.h"
UCLASS()
class DARKHORSEUNREAL_API AElevator : public AActor
{
GENERATED_BODY()
UPROPERTY(VisibleDefaultsOnly, Category = "Mesh")
class UStaticMeshComponent* ElevatorMesh;
UPROPERTY(VisibleDefaultsOnly, Category = "Mesh")
class UStaticMeshComponent* Bar1Mesh;
UPROPERTY(VisibleDefaultsOnly, Category = "Mesh")
class UStaticMeshComponent* Bar2Mesh;
UPROPERTY(VisibleDefaultsOnly, Category = "Mesh")
class UStaticMeshComponent* Door1Mesh;
UPROPERTY(VisibleDefaultsOnly, Category = "Mesh")
class UStaticMeshComponent* Door2Mesh;
UPROPERTY(VisibleDefaultsOnly, Category = "Mesh")
class UStaticMeshComponent* Button1Mesh;
UPROPERTY(VisibleDefaultsOnly, Category = "Mesh")
class UStaticMeshComponent* Button2Mesh;
UPROPERTY(VisibleDefaultsOnly, Category = "Mesh")
class UStaticMeshComponent* Button3Mesh;
UPROPERTY(VisibleDefaultsOnly, Category = "Mesh")
class UStaticMeshComponent* Button4Mesh;
UPROPERTY(VisibleDefaultsOnly, Category = "Mesh")
class UStaticMeshComponent* Button5Mesh;
UPROPERTY(VisibleDefaultsOnly, Category = "Mesh")
class UStaticMeshComponent* Button6Mesh;
UPROPERTY(VisibleDefaultsOnly, Category = "Mesh")
class UStaticMeshComponent* Button7Mesh;
UPROPERTY(VisibleDefaultsOnly, Category = "Mesh")
class UStaticMeshComponent* Button8Mesh;
//Variable to store the current state the lift is in
enum ElevatorState
{
Idle,
Wait,
Transit
} EState;
//Timeline for the doors
FTimeline DoorTimeline;
//Stores the current float value of the curve
float CurveFloatValue;
//Creating a timer handle so that the door closes after certain seconds
FTimerHandle DoorTimerHandle;
//Set to true when the elevator is going up
bool EisGoingUp;
//Arrays to store the queue request for floors
TArray<int> UpQueue;
TArray<int> DownQueue;
TArray<int> CurrQueue;
//Variable to store the elevator's CurrentFloor
int ElevatorCurrentFloor;
//Variable to store the elevator's new position to go to
float PositionToGo;
//Variable to store the amount of Z position by which the elevator moves
float CurrentZPos;
//Variable to hold and store temporary value of Queue request
int TempValue;
//Variables that defines the elevator's Movement
bool IsMovingUp;
bool IsMovingDown;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Sets default values for this actor's properties
AElevator();
// Called every frame
virtual void Tick(float DeltaTime) override;
//Variable to hold the curve float
UPROPERTY(EditDefaultsOnly, Category = "Timeline")
class UCurveFloat* ElevatorDoorCurve;
//Variable to hold how much the time the doors stay opened
UPROPERTY(EditDefaultsOnly, Category = "DelayTimer")
float DelayValue;
//Function To Open and Close the lift doors
void OpenDoors();
void CloseDoors();
//Timeline Functions
UFUNCTION()
void DoorTimelineRun();
UFUNCTION()
void DoorTimelineEnd();
void SetLiftCall(bool ElevatorUpCallStatus, int ECFloorNo);
//Function to switch lift direction and states
void SetLiftMovement();
//Function to find the z position
void GetPosToGo(int FloorToGo);
void ElevatorUpMovement(float DeltaTime);
void ElevatorDownMovement(float DeltaTime);
};
Elevator.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "Elevator.h"
#include "Components/StaticMeshComponent.h"
#include "Curves/CurveFloat.h"
#include "TimerManager.h"
// Sets default values
AElevator::AElevator()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
ElevatorMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ElevatorMesh"));
RootComponent = ElevatorMesh;
ElevatorMesh->SetMobility(EComponentMobility::Movable);
Bar1Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Bar1"));
Bar1Mesh->SetupAttachment(RootComponent);
Bar1Mesh->SetWorldTransform(FTransform(FVector(101.5, -5, 102))); //Setting the mesh component transform
Bar2Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Bar2"));
Bar2Mesh->SetupAttachment(RootComponent);
Bar2Mesh->SetWorldTransform(FTransform(FVector(-101.5, -5, 102))); //Setting the mesh component transform
Bar2Mesh->SetWorldRotation(FRotator(0.0f, 180.0f, 0.0f));
Door1Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Door1"));
Door1Mesh->SetupAttachment(RootComponent);
Door1Mesh->SetWorldTransform(FTransform(FVector(0, 117, 12.7))); //Setting the mesh component transform
Door2Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Door2"));
Door2Mesh->SetupAttachment(RootComponent);
Door2Mesh->SetWorldTransform(FTransform(FVector(0, 122.08, 12.7))); //Setting the mesh component transform
Door2Mesh->SetWorldRotation(FRotator(0.0f, 180.0f, 0.0f));
Button1Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Button1")); //Setting up the buttons
Button1Mesh->SetupAttachment(RootComponent);
Button1Mesh->SetWorldTransform(FTransform(FVector(82.8, 115.8, 148.)));
Button1Mesh->SetWorldRotation(FRotator(0.0f, 0.0f, 180.0f));
Button1Mesh->SetWorldScale3D(FVector(0.8f, 0.8f, 0.8f));
Button2Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Button2"));
Button2Mesh->SetupAttachment(RootComponent);
Button2Mesh->SetWorldTransform(FTransform(FVector(75, 115.8, 148)));
Button2Mesh->SetWorldRotation(FRotator(0.0f, 0.0f, 180.0f));
Button2Mesh->SetWorldScale3D(FVector(0.8f, 0.8f, 0.8f));
Button3Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Button3"));
Button3Mesh->SetupAttachment(RootComponent);
Button3Mesh->SetWorldTransform(FTransform(FVector(82.8, 115.8, 142.5)));
Button3Mesh->SetWorldRotation(FRotator(0.0f, 0.0f, 180.0f));
Button3Mesh->SetWorldScale3D(FVector(0.8f, 0.8f, 0.8f));
Button4Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Button4"));
Button4Mesh->SetupAttachment(RootComponent);
Button4Mesh->SetWorldTransform(FTransform(FVector(75, 115.8, 142.5)));
Button4Mesh->SetWorldRotation(FRotator(0.0f, 0.0f, 180.0f));
Button4Mesh->SetWorldScale3D(FVector(0.8f, 0.8f, 0.8f));
Button5Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Button5"));
Button5Mesh->SetupAttachment(RootComponent);
Button5Mesh->SetWorldTransform(FTransform(FVector(82.8, 115.8, 137)));
Button5Mesh->SetWorldRotation(FRotator(0.0f, 0.0f, 180.0f));
Button5Mesh->SetWorldScale3D(FVector(0.8f, 0.8f, 0.8f));
Button6Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Button6"));
Button6Mesh->SetupAttachment(RootComponent);
Button6Mesh->SetWorldTransform(FTransform(FVector(75, 115.8, 137)));
Button6Mesh->SetWorldRotation(FRotator(0.0f, 0.0f, 180.0f));
Button6Mesh->SetWorldScale3D(FVector(0.8f, 0.8f, 0.8f));
Button7Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Button7"));
Button7Mesh->SetupAttachment(RootComponent);
Button7Mesh->SetWorldTransform(FTransform(FVector(82.8, 115.8, 131.5)));
Button7Mesh->SetWorldRotation(FRotator(0.0f, 0.0f, 180.0f));
Button7Mesh->SetWorldScale3D(FVector(0.8f, 0.8f, 0.8f));
Button8Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Button8"));
Button8Mesh->SetupAttachment(RootComponent);
Button8Mesh->SetWorldTransform(FTransform(FVector(75, 115.8, 131.5)));
Button8Mesh->SetWorldRotation(FRotator(0.0f, 0.0f, 180.0f));
Button8Mesh->SetWorldScale3D(FVector(0.8f, 0.8f, 0.8f));
EState = ElevatorState::Idle;
DelayValue = 5.0f; //Setting a default delay of 5s
EisGoingUp = true; //Setting default value that lift is going up
ElevatorCurrentFloor = 1; //Always assuming the lift is starting at GD floor
PositionToGo = -12.7f;
CurrentZPos = -12.7f;
TempValue = 0;
IsMovingUp = false;
IsMovingDown = false;
}
// Called when the game starts or when spawned
void AElevator::BeginPlay()
{
Super::BeginPlay();
if (ElevatorDoorCurve) //If the curve is found
{
FOnTimelineFloat TimelineCallback;
FOnTimelineEventStatic TimelineCallbackFinished;
TimelineCallback.BindUFunction(this, FName("DoorTimelineRun")); //Performing binding
TimelineCallbackFinished.BindUFunction(this, FName("DoorTimelineEnd"));
DoorTimeline.AddInterpFloat(ElevatorDoorCurve, TimelineCallback);
DoorTimeline.SetTimelineFinishedFunc(TimelineCallbackFinished);
}
}
// Called every frame
void AElevator::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
DoorTimeline.TickTimeline(DeltaTime);
SetLiftMovement();
if (IsMovingUp)
{
ElevatorUpMovement(DeltaTime);
}
else if(IsMovingDown)
{
ElevatorDownMovement(DeltaTime);
}
else
{
return;
}
}
void AElevator::DoorTimelineRun()
{
//Get the current value of the curve in time
CurveFloatValue = ElevatorDoorCurve->GetFloatValue(DoorTimeline.GetPlaybackPosition());
//Set the translation value of doors
Door1Mesh->SetRelativeLocation(FVector(CurveFloatValue, Door1Mesh->RelativeLocation.Y, Door1Mesh->RelativeLocation.Z));
Door2Mesh->SetRelativeLocation(FVector(-CurveFloatValue, Door2Mesh->RelativeLocation.Y, Door2Mesh->RelativeLocation.Z));
}
void AElevator::DoorTimelineEnd()
{
//Runs a timer handle so that when the door is open closed after s seconds automatically
if (CurveFloatValue == 53.63f)
{
GetWorldTimerManager().SetTimer(DoorTimerHandle, this, &AElevator::CloseDoors, DelayValue, false);
}
//Tells the elevator that it's ok to calculate for the next floor
if (CurveFloatValue == 0.0f)
{
EState = ElevatorState::Wait;
}
}
void AElevator::OpenDoors()
{
if (ElevatorDoorCurve)
{
//Calls to the play the timeline from start
DoorTimeline.PlayFromStart();
}
}
void AElevator::CloseDoors()
{
GetWorldTimerManager().ClearTimer(DoorTimerHandle); //Clears the timer handle
if (ElevatorDoorCurve)
{
//Plays the timeline in reverse
DoorTimeline.Reverse();
}
}
void AElevator::SetLiftCall(bool ElevatorUpCallStatus, int ECFloorNo)
{
if (EState == ElevatorState::Idle)
{
if (ElevatorCurrentFloor == ECFloorNo)
{
OpenDoors();
EState = ElevatorState::Transit;
return;
}
else if(ElevatorCurrentFloor < ECFloorNo)
{
EisGoingUp = true;
}
else
{
EisGoingUp = false;
}
CurrQueue.AddUnique(ECFloorNo);
EState = ElevatorState::Wait;
}
else
{
//When the elevator is going up
if (EisGoingUp)
{
//Player Wishes to go up
if (ElevatorUpCallStatus)
{
if (ECFloorNo > ElevatorCurrentFloor)
{
CurrQueue.AddUnique(ECFloorNo);
CurrQueue.Sort();
}
else
{
UpQueue.AddUnique(ECFloorNo);
}
}
else
{
DownQueue.AddUnique(ECFloorNo);
}
}
//When the elevator is going down
else
{
//Player Wishes to go up
if (ElevatorUpCallStatus)
{
UpQueue.AddUnique(ECFloorNo);
}
else
{
if (ElevatorCurrentFloor > ECFloorNo)
{
CurrQueue.AddUnique(ECFloorNo);
CurrQueue.Sort();
}
else
{
DownQueue.AddUnique(ECFloorNo);
}
}
}
}
}
void AElevator::SetLiftMovement()
{
if ((EState == ElevatorState::Idle)||(EState == ElevatorState::Transit))
{
return;
}
else
{
if ((CurrQueue.Num() == 0) && (UpQueue.Num() == 0) && (DownQueue.Num() == 0))
{
EState = ElevatorState::Idle;
}
else
{
EState = ElevatorState::Transit;
//Checking the Current Queue is empty
if (CurrQueue.Num() > 0)
{
if (EisGoingUp)
{
GetPosToGo(CurrQueue[0]); //Getting 1st element of the array
IsMovingUp = true;
}
else
{
GetPosToGo(CurrQueue[CurrQueue.Num() - 1]); //Getting last element of array
IsMovingDown = false;
}
}
else
{
//When the elevator is going up
if (EisGoingUp)
{
DownQueue.Sort();
TempValue = DownQueue[DownQueue.Num() - 1];
if (ElevatorCurrentFloor > TempValue)
{
CurrQueue = DownQueue;
EisGoingUp = false;
}
else
{
CurrQueue.AddUnique(TempValue);
DownQueue.Remove(TempValue);
}
}
else
{
UpQueue.Sort();
TempValue = UpQueue[0];
if (ElevatorCurrentFloor < TempValue)
{
CurrQueue = UpQueue;
EisGoingUp = true;
}
else
{
CurrQueue.AddUnique(TempValue);
UpQueue.Remove(TempValue);
}
}
EState = ElevatorState::Wait;
}
}
}
}
void AElevator::GetPosToGo(int FloorToGo)
{
switch (FloorToGo)
{
case 0: PositionToGo = -301.41f;
break;
case 1: PositionToGo = -12.7f;
break;
case 2: PositionToGo = 347.98f;
break;
case 3: PositionToGo = 695.96f;
break;
case 4: PositionToGo = 1043.94f;
break;
case 5: PositionToGo = 1391.92f;
break;
default:PositionToGo = -12.7f;
break;
}
}
void AElevator::ElevatorUpMovement(float DeltaTime)
{
if (FMath::IsNearlyEqual(ElevatorMesh->RelativeLocation.Z, PositionToGo, 10.0f))
{
ElevatorMesh->RelativeLocation.Z = PositionToGo;
CurrentZPos = PositionToGo;
IsMovingUp = false;
ElevatorCurrentFloor = CurrQueue[0];
CurrQueue.Remove(ElevatorCurrentFloor);
OpenDoors();
}
else
{
CurrentZPos = (DeltaTime * 150) + ElevatorMesh->RelativeLocation.Z;
ElevatorMesh->SetRelativeLocation(FVector(ElevatorMesh->RelativeLocation.X, ElevatorMesh->RelativeLocation.Y, CurrentZPos));
}
}
void AElevator::ElevatorDownMovement(float DeltaTime)
{
if (FMath::IsNearlyEqual(ElevatorMesh->RelativeLocation.Z, PositionToGo, 10.0f))
{
ElevatorMesh->RelativeLocation.Z = PositionToGo;
CurrentZPos = PositionToGo;
IsMovingDown = false;
ElevatorCurrentFloor = CurrQueue[CurrQueue.Num() -1];
CurrQueue.Remove(ElevatorCurrentFloor);
OpenDoors();
}
else
{
CurrentZPos = (-DeltaTime * 150) + ElevatorMesh->RelativeLocation.Z;
ElevatorMesh->SetRelativeLocation(FVector(ElevatorMesh->RelativeLocation.X, ElevatorMesh->RelativeLocation.Y, CurrentZPos));
}
}