haxis/Source/UnrealProject/Doodads/CharacterCarousel.cpp

256 lines
6.9 KiB
C++

// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "CharacterCarousel.h"
#include "CharacterBase.h"
#include "DefaultGameInstance.h"
ACharacterCarousel::ACharacterCarousel()
{
PrimaryActorTick.bCanEverTick = true;
selectedCharacterIndex = 0;
m_visualSelected = 0;
selected = false;
m_zoom = 0;
selectedCharacterOffset = FVector(30, -120, 0);
}
void ACharacterCarousel::BeginPlay()
{
check(IsValid(characterBlueprint));
Super::BeginPlay();
// Fix the rotation
FRotator rotation = GetActorRotation();
SetActorRotation(FRotator(0, rotation.Yaw, 0));
const FVector position = GetActorLocation();
const FVector forward = GetActorForwardVector();
const FVector right = GetActorRightVector();
UDefaultGameInstance* instance = Cast<UDefaultGameInstance>(GetGameInstance());
check(instance);
UCharacterSettings* settings = instance->GetCharacterSettings();
check(settings);
for (int32 i = 0; i < settings->characterSaves.Num(); i++)
{
FActorSpawnParameters spawnParams;
spawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
ACharacterBase* actor = GetWorld()->SpawnActor<ACharacterBase>(characterBlueprint, GetActorLocation(), GetActorRotation(), spawnParams);
m_characters.Add(actor);
}
}
void ACharacterCarousel::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
for (int32 i = 0; i < m_characters.Num(); i++)
{
if (IsValid(m_characters[i]))
m_characters[i]->Destroy();
}
m_characters.SetNum(0);
}
inline float MoveTowardsTarget(float current, float target, float delta, float min = 0.0005f)
{
const int32 moveDir = target > current ? 1 : -1;
float d = FMath::Abs((target - current) * delta);
if (d < 0.0005f) d = 0.0005f;
current += d * moveDir;
// Clamp
current = (moveDir == 1) ?
(current > target ? target : current) :
(current < target ? target : current);
return current;
}
void ACharacterCarousel::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (m_characters.Num() == 0)
return;
// Zoom towards the target
const float zoomTarget = selected ? 1 : 0;
m_zoom = MoveTowardsTarget(m_zoom, zoomTarget, DeltaTime * 10);
const FVector position = GetActorLocation();
const FVector forward = GetActorForwardVector();
const FVector right = GetActorRightVector();
const float carouselRadius = 1200;
const float carouselAngle = 10;
const FVector pivot = position - forward * carouselRadius;
// Clamp the selected index (may be altered from a blueprint)
selectedCharacterIndex = selectedCharacterIndex < 0 ? 0 : selectedCharacterIndex >= m_characters.Num() ? m_characters.Num() - 1 : selectedCharacterIndex;
// Animate the carousel
const float target = float(selectedCharacterIndex);
m_visualSelected = MoveTowardsTarget(m_visualSelected, target, DeltaTime * (selected ? 10 : 5));
// Spawn and set the characters
const FRotator rotation = GetActorRotation();
const FVector arm = forward * carouselRadius;
const FVector selectedOffset = rotation.RotateVector(selectedCharacterOffset) * m_zoom;
for (int32 i = 0; i < m_characters.Num(); i++)
{
const int32 distance = i - selectedCharacterIndex;
if (distance < -2 || distance > 2)
{
// Dont render characters off screen
m_characters[i]->GetRootComponent()->SetVisibility(false, true);
}
else
{
m_characters[i]->GetRootComponent()->SetVisibility(true, true);
// Set the position relative from the pivot
FRotator rotator(0, -carouselAngle * (float(i) - m_visualSelected), 0);
if (m_zoom > 0) rotator.Yaw *= (m_zoom + 1);
FVector offset = rotator.RotateVector(arm);
if (i == selectedCharacterIndex)
offset += selectedOffset;
m_characters[i]->SetActorLocation(pivot + offset);
m_characters[i]->SetActorRotation(rotator + FRotator(0, rotation.Yaw, 0));
}
}
}
void ACharacterCarousel::Reset()
{
selectedCharacterIndex = 0;
m_visualSelected = 0;
selected = false;
m_zoom = 0;
}
void ACharacterCarousel::Next()
{
if(!selected && m_characters.Num() > 0 && selectedCharacterIndex < m_characters.Num() - 1)
selectedCharacterIndex++;
}
void ACharacterCarousel::Previous()
{
if (!selected && selectedCharacterIndex > 0)
selectedCharacterIndex--;
}
void ACharacterCarousel::ToggleSelect(bool enabled)
{
selected = enabled;
}
void ACharacterCarousel::CreateNewCharacter(const FString& name)
{
UDefaultGameInstance* instance = Cast<UDefaultGameInstance>(GetGameInstance());
check(instance);
UCharacterSettings* settings = instance->GetCharacterSettings();
check(settings);
// Create a scene actor
ACharacterBase* actor = GetWorld()->SpawnActor<ACharacterBase>(characterBlueprint, GetActorLocation(), GetActorRotation());
m_characters.Add(actor);
// Select this character
selected = false;
selectedCharacterIndex = m_characters.Num() - 1;
m_zoom = 0;
// Add to save
FCharacterSave save;
save.name = name;
settings->characterSaves.Add(save);
instance->SaveSettings();
}
void ACharacterCarousel::DeleteCharacter(int32 index)
{
UDefaultGameInstance* instance = Cast<UDefaultGameInstance>(GetGameInstance());
check(instance);
UCharacterSettings* settings = instance->GetCharacterSettings();
check(settings);
if (index < 0 || index >= settings->characterSaves.Num())
{
JERROR("Invalid character index");
return;
}
// Destroy scene actor
m_characters[index]->Destroy();
m_characters.RemoveAt(index);
if (index == selectedCharacterIndex)
selectedCharacterIndex--;
// Unselect
selected = false;
m_zoom = 0;
// Remove from save
settings->characterSaves.RemoveAt(index);
instance->SaveSettings();
}
ACharacterBase* ACharacterCarousel::GetCharacterModel(int32 index)
{
if (index < 0 || index >= m_characters.Num())
{
JERROR("Invalid character index");
return nullptr;
}
return m_characters[index];
}
int32 ACharacterCarousel::GetCharacterNum()
{
return m_characters.Num();
}
void ACharacterCarousel::SaveCharacterName(const FString& name, int32 index)
{
UDefaultGameInstance* instance = Cast<UDefaultGameInstance>(GetGameInstance());
check(instance);
UCharacterSettings* settings = instance->GetCharacterSettings();
check(settings);
if (index < 0 || index >= settings->characterSaves.Num())
{
JERROR("Invalid character index");
return;
}
settings->characterSaves[index].name = name;
instance->SaveSettings();
}
FString ACharacterCarousel::GetCharacterName(int32 index)
{
UDefaultGameInstance* instance = Cast<UDefaultGameInstance>(GetGameInstance());
check(instance);
UCharacterSettings* settings = instance->GetCharacterSettings();
check(settings);
if (index < 0 || index >= settings->characterSaves.Num())
{
JERROR("Invalid character index");
return FString();
}
return settings->characterSaves[index].name;
}