256 lines
6.9 KiB
C++
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;
|
|
} |