1 Commits

Author SHA1 Message Date
ayresma e1ceb2f7fc cube
cuuuube
2025-05-21 17:41:43 -04:00
27 changed files with 82 additions and 199 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,18 +3,18 @@
#include "LumiCharacter.h" #include "LumiCharacter.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Engine/LocalPlayer.h" #include "Engine/LocalPlayer.h"
#include "Engine/UserInterfaceSettings.h" #include "Engine/UserInterfaceSettings.h"
#include "GameFramework/CharacterMovementComponent.h" #include "Camera/CameraComponent.h"
#include "GameFramework/Controller.h" #include "Components/CapsuleComponent.h"
#include "GameFramework/SpringArmComponent.h" #include "GameFramework/SpringArmComponent.h"
#include "GameFramework/Controller.h"
#include "InputActionValue.h" #include "InputActionValue.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "WizardingCentral/Utils/OneDollar/UniStrokeDataTable.h" #include "WizardingCentral/Utils/OneDollar/UniStrokeDataTable.h"
#include "WizardingCentral/Utils/OneDollar/UniStrokeResult.h" #include "WizardingCentral/Utils/OneDollar/UniStrokeResult.h"
static const FString SpellTemplatesTablePath = TEXT("/Game/DataTables/SpellTemplates.SpellTemplates"); DEFINE_LOG_CATEGORY(LogLumiCharacter);
// Sets default values // Sets default values
ALumiCharacter::ALumiCharacter() ALumiCharacter::ALumiCharacter()
@@ -49,17 +49,8 @@ ALumiCharacter::ALumiCharacter()
// Spell System // Spell System
bIsDrawing = false; bIsDrawing = false;
SpellRecognizer = new FUniStrokeRecognizer(); SpellRecognizer = new FUniStrokeRecognizer();
if (SpellTemplatesTable == nullptr) if (SpellTemplatesTable)
{ LoadSpellTemplates();
SpellTemplatesTable = Cast<UDataTable>(
StaticLoadObject(
UDataTable::StaticClass(),
nullptr,
*SpellTemplatesTablePath
)
);
}
LoadSpellTemplates();
} }
ELumiStance ALumiCharacter::GetCurrentStance() const ELumiStance ALumiCharacter::GetCurrentStance() const
@@ -76,7 +67,7 @@ void ALumiCharacter::BeginPlay()
if (!GetPlayerController(LumiController)) if (!GetPlayerController(LumiController))
{ {
UE_LOG(LogTemp, Error, TEXT("ALumiCharacter::BeginPlay() Failed to get LumiController!")); UE_LOG(LogLumiCharacter, Error, TEXT("ALumiCharacter::BeginPlay() Failed to get LumiController!"));
return; return;
} }
@@ -120,21 +111,19 @@ bool ALumiCharacter::IsLastJump() const
void ALumiCharacter::OnGrabActionTriggered(const FInputActionValue& Value) void ALumiCharacter::OnGrabActionTriggered(const FInputActionValue& Value)
{ {
UE_LOG(LogTemp, Log, TEXT("Grab Triggered")); UE_LOG(LogLumiCharacter, Log, TEXT("Grab Triggered"));
} }
void ALumiCharacter::OnJumpActionStarted(const FInputActionValue& Value) void ALumiCharacter::OnJumpActionStarted(const FInputActionValue& Value)
{ {
// Broadcast that the jump has started // Broadcast that the jump has started
OnJumpStarted.Broadcast(); OnJumpStarted.Broadcast();
UE_LOG(LogTemp, Log, TEXT("Jump Started")); UE_LOG(LogLumiCharacter, Log, TEXT("Jump Started"));
Jump(); Jump();
} }
void ALumiCharacter::OnJumpActionOngoing(const FInputActionValue& Value) void ALumiCharacter::OnJumpActionOngoing(const FInputActionValue& Value) {}
{
}
void ALumiCharacter::OnJumpActionCompleted(const FInputActionValue& Value) void ALumiCharacter::OnJumpActionCompleted(const FInputActionValue& Value)
{ {
@@ -182,12 +171,12 @@ void ALumiCharacter::OnLookActionTriggered(const FInputActionValue& Value)
void ALumiCharacter::OnDefaultStance_Implementation() void ALumiCharacter::OnDefaultStance_Implementation()
{ {
UE_LOG(LogTemp, Log, TEXT("OnDefaultStance_Implementation()")); UE_LOG(LogLumiCharacter, Log, TEXT("OnDefaultStance_Implementation()"));
} }
void ALumiCharacter::OnMagicStance_Implementation() void ALumiCharacter::OnMagicStance_Implementation()
{ {
UE_LOG(LogTemp, Log, TEXT("OnMagicStance_Implementation()")); UE_LOG(LogLumiCharacter, Log, TEXT("OnMagicStance_Implementation()"));
} }
void ALumiCharacter::OnSpellActionStarted() void ALumiCharacter::OnSpellActionStarted()
@@ -201,7 +190,7 @@ void ALumiCharacter::OnSpellActionCompleted()
if (SpellSystemState == Casting) if (SpellSystemState == Casting)
SpellSystemState = bIsTraining ? Training : Recognizing; SpellSystemState = bIsTraining ? Training : Recognizing;
UE_LOG(LogTemp, Log, TEXT("OnSpellActionCompleted() Current State: %d"), SpellSystemState); UE_LOG(LogLumiCharacter, Log, TEXT("OnSpellActionCompleted() Current State: %d"), SpellSystemState);
switch (SpellSystemState) switch (SpellSystemState)
{ {
@@ -287,16 +276,6 @@ void ALumiCharacter::AddSpellTemplateToTable(const FString& Name)
HideTrainWidget(); HideTrainWidget();
} }
void ALumiCharacter::OnSpellCast_Implementation(const FString& SpellName)
{
UE_LOG(
LogTemp,
Log,
TEXT("ALumiCharacter::OnSpellCast_Implementation() Spell: %s"),
*SpellName
);
}
bool ALumiCharacter::GetPlayerController(APlayerController*& LumiController) const bool ALumiCharacter::GetPlayerController(APlayerController*& LumiController) const
{ {
LumiController = Cast<APlayerController>(this->Controller); LumiController = Cast<APlayerController>(this->Controller);
@@ -321,19 +300,17 @@ void ALumiCharacter::LoadSpellTemplates() const
void ALumiCharacter::CastSpell() void ALumiCharacter::CastSpell()
{ {
const TArray<FVector2D>* CurrentPoints = SpellOverlay->GetSpellPoints(); const TArray<FVector2D>* CurrentPoints = SpellOverlay->GetSpellPoints();
const FUniStrokeResult Result = SpellRecognizer->Recognize(*CurrentPoints); const FUniStrokeResult Result = SpellRecognizer->Recognize(*CurrentPoints, false);
bool bHasMatch = false; bool bHasMatch = false;
if (Result.Score < 0.8f) if (Result.Score < 0.8f)
{ {
UE_LOG(LogTemp, Log, TEXT("ALumiCharacter::CastSpell() No match found!")); UE_LOG(LogLumiCharacter, Log, TEXT("ALumiCharacter::CastSpell() No match found!"));
} }
else else
{ {
bHasMatch = true; bHasMatch = true;
UE_LOG(LogTemp, Log, TEXT("ALumiCharacter::CastSpell() Spell: %s"), *Result.Name); UE_LOG(LogLumiCharacter, Log, TEXT("ALumiCharacter::CastSpell() Spell: %s"), *Result.Name);
OnSpellCast(Result.Name);
} }
// TODO: Handle Spell Casting // TODO: Handle Spell Casting
@@ -15,6 +15,8 @@ class USpringArmComponent;
class UCameraComponent; class UCameraComponent;
struct FInputActionValue; struct FInputActionValue;
DECLARE_LOG_CATEGORY_EXTERN(LogLumiCharacter, Log, All);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FJumpDelegate); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FJumpDelegate);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FStanceChangedDelegate, DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FStanceChangedDelegate,
@@ -143,24 +145,13 @@ public:
OnSpellActionCompleted(); OnSpellActionCompleted();
void void
OnSpellPositionActionTriggered(const FInputActionValue& Value); OnSpellPositionActionTriggered(const FInputActionValue& Value);
void
OnSpellTrainSwitchActionCompleted();
UFUNCTION(BlueprintCallable, Category = "Spell") void OnSpellTrainSwitchActionCompleted();
void
SetIsTraining(const bool bTraining);
UFUNCTION(BlueprintCallable, Category = "Spell") void SetIsTraining(const bool bTraining);
void void HideTrainWidget();
HideTrainWidget(); void ShowTrainWidget();
void AddSpellTemplateToTable(const FString& Name);
UFUNCTION(BlueprintCallable, Category = "Spell")
void
ShowTrainWidget();
UFUNCTION(BlueprintCallable, Category = "Spell")
void
AddSpellTemplateToTable(const FString& Name);
protected: protected:
/** /**
@@ -201,10 +192,6 @@ protected:
virtual void virtual void
BeginPlay() override; BeginPlay() override;
UFUNCTION(BlueprintNativeEvent, Category = "Spell")
void
OnSpellCast(const FString& SpellName);
private: private:
bool bool
GetPlayerController(APlayerController*& LumiController) const; GetPlayerController(APlayerController*& LumiController) const;
@@ -30,11 +30,6 @@ void ALumiController::GetLumiCharacter(ALumiCharacter*& OutLumiCharacter) const
OutLumiCharacter = LumiCharacter; OutLumiCharacter = LumiCharacter;
} }
ALumiCharacter* ALumiController::GetLumiCharacter() const
{
return LumiCharacter;
}
void ALumiController::OnPossess(APawn* InPawn) void ALumiController::OnPossess(APawn* InPawn)
{ {
Super::OnPossess(InPawn); Super::OnPossess(InPawn);
@@ -104,8 +99,8 @@ void ALumiController::OnPossess(APawn* InPawn)
{ {
EnhancedInputComponent->BindAction(SpellAction, EnhancedInputComponent->BindAction(SpellAction,
ETriggerEvent::Started, ETriggerEvent::Started,
this, LumiCharacter,
&ALumiController::OnSpellActionStarted); &ALumiCharacter::OnSpellActionStarted);
EnhancedInputComponent->BindAction(SpellAction, EnhancedInputComponent->BindAction(SpellAction,
ETriggerEvent::Completed, ETriggerEvent::Completed,
this, this,
@@ -133,12 +128,12 @@ void ALumiController::OnUnPossess()
void ALumiController::OnSpellActionStarted() void ALumiController::OnSpellActionStarted()
{ {
// ShowMouseCursor(); ShowMouseCursor();
LumiCharacter->OnSpellActionStarted(); LumiCharacter->OnSpellActionStarted();
} }
void ALumiController::OnSpellActionCompleted() void ALumiController::OnSpellActionCompleted()
{ {
LumiCharacter->OnSpellActionCompleted(); LumiCharacter->OnSpellActionCompleted();
// HideMouseCursor(); HideMouseCursor();
} }
@@ -60,10 +60,6 @@ public:
void void
GetLumiCharacter(ALumiCharacter*& OutLumiCharacter) const; GetLumiCharacter(ALumiCharacter*& OutLumiCharacter) const;
UFUNCTION(BlueprintCallable, Category = "LumiController")
ALumiCharacter*
GetLumiCharacter() const;
protected: protected:
virtual void virtual void
OnPossess(APawn* InPawn) override; OnPossess(APawn* InPawn) override;
@@ -1,27 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "SpellInteractable.generated.h"
UINTERFACE(MinimalAPI, Blueprintable)
class USpellInteractable : public UInterface
{
GENERATED_BODY()
};
/**
* Interface for objects that can be interacted with by spells.
*/
class WIZARDINGCENTRAL_API ISpellInteractable
{
GENERATED_BODY()
public:
/**
* Called when the spell is cast on the object.
* @param SpellName The name of the spell that was cast.
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Spell")
void OnSpellCast(const FString& SpellName);
};
@@ -1,24 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "SpellInteractableActor.h"
// Sets default values
ASpellInteractableActor::ASpellInteractableActor()
{
// 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;
}
// Called when the game starts or when spawned
void ASpellInteractableActor::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ASpellInteractableActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
@@ -1,27 +0,0 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "SpellInteractable.h"
#include "GameFramework/Actor.h"
#include "SpellInteractableActor.generated.h"
UCLASS()
class WIZARDINGCENTRAL_API ASpellInteractableActor : public AActor,
public ISpellInteractable
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ASpellInteractableActor();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
};
@@ -1,5 +1,7 @@
#include "UniStrokePoint.h" #include "UniStrokePoint.h"
#include "ScreenPass.h"
FUniStrokePoint::FUniStrokePoint() FUniStrokePoint::FUniStrokePoint()
{ {
this->X = 0.0f; this->X = 0.0f;
@@ -47,7 +49,9 @@ FUniStrokePoint::BoundingBox(const TArray<FUniStrokePoint>& Points)
{ {
// Edge case // Edge case
if (Points.Num() == 0) if (Points.Num() == 0)
{
return FUniStrokeRectangle(); return FUniStrokeRectangle();
}
float MinX = Points[0].X; float MinX = Points[0].X;
float MinY = Points[0].Y; float MinY = Points[0].Y;
@@ -82,16 +86,14 @@ FUniStrokePoint::Vectorize(const TArray<FUniStrokePoint>& Points)
const float Magnitude = FMath::Sqrt(Sum); const float Magnitude = FMath::Sqrt(Sum);
for (float& V : Vector) for (float& V : Vector)
{
V /= Magnitude; V /= Magnitude;
}
return Vector; return Vector;
} }
FString FUniStrokePoint::ToString() const // TODO: Proofread this function
{
return FString::Printf(TEXT("X=%.3f Y=%.3f"), X, Y);
}
float float
FUniStrokePoint::OptimalCosineDistance(const TArray<float>& VectorA, FUniStrokePoint::OptimalCosineDistance(const TArray<float>& VectorA,
const TArray<float>& VectorB) const TArray<float>& VectorB)
@@ -171,7 +173,9 @@ FUniStrokePoint::Resample(TArray<FUniStrokePoint>& Points,
// Edge case // Edge case
if (Points.Num() == Num - 1) if (Points.Num() == Num - 1)
{
Points.Add(OldPoints.Last()); Points.Add(OldPoints.Last());
}
} }
float float
@@ -381,7 +385,9 @@ FUniStrokePoint::PathDistance(const TArray<FUniStrokePoint>& PathA,
{ {
// Edge case: Different number of points // Edge case: Different number of points
if (PathA.Num() != PathB.Num()) if (PathA.Num() != PathB.Num())
{
return TNumericLimits<float>::Max(); return TNumericLimits<float>::Max();
}
// d <- 0 // d <- 0
float d = 0; float d = 0;
@@ -84,9 +84,6 @@ struct WIZARDINGCENTRAL_API FUniStrokePoint
static TArray<float> static TArray<float>
Vectorize(const TArray<FUniStrokePoint>& Points); Vectorize(const TArray<FUniStrokePoint>& Points);
FString
ToString() const;
private: private:
float X; float X;
float Y; float Y;
@@ -12,13 +12,16 @@ FUniStrokeRecognizer::~FUniStrokeRecognizer()
// TODO: Review this function // TODO: Review this function
FUniStrokeResult FUniStrokeResult
FUniStrokeRecognizer::Recognize(const TArray<FVector2D>& VectorPoints) FUniStrokeRecognizer::Recognize(const TArray<FVector2D>& VectorPoints,
const bool& UseProtractor)
{ {
TArray<FUniStrokePoint> Points = FUniStrokePoint::From(VectorPoints); TArray<FUniStrokePoint> Points = FUniStrokePoint::From(VectorPoints);
// Edge case: Not enough points // Edge case: Not enough points
if (Points.Num() < 2 || FUniStrokePoint::PathLength(Points) < 100.0f) if (Points.Num() < 2 || FUniStrokePoint::PathLength(Points) < 100.0f)
{
return FUniStrokeResult("Too few points made", 0.0); return FUniStrokeResult("Too few points made", 0.0);
}
const FUniStrokeTemplate Candidate = FUniStrokeTemplate("", Points); const FUniStrokeTemplate Candidate = FUniStrokeTemplate("", Points);
int TemplateIndex = -1; int TemplateIndex = -1;
@@ -30,13 +33,18 @@ FUniStrokeRecognizer::Recognize(const TArray<FVector2D>& VectorPoints)
for (int i = 0; i < Templates.Num(); i++) for (int i = 0; i < Templates.Num(); i++)
{ {
// d <- DistanceAtBestAngle(points, T, -theta, theta, threshold) // d <- DistanceAtBestAngle(points, T, -theta, theta, threshold)
const float d = FUniStrokePoint::DistanceAtBestAngle( const float d = UseProtractor
Candidate.Points, ? FUniStrokePoint::OptimalCosineDistance(
Templates[i].Points, Templates[i].Vector,
-AngleRange, Candidate.Vector
AngleRange, )
AnglePrecision : FUniStrokePoint::DistanceAtBestAngle(
); Candidate.Points,
Templates[i].Points,
-AngleRange,
AngleRange,
AnglePrecision
);
// if d < b then // if d < b then
if (d < b) if (d < b)
@@ -49,8 +57,7 @@ FUniStrokeRecognizer::Recognize(const TArray<FVector2D>& VectorPoints)
} }
// score <- 1 b / 0.5 sqrt(size^2 + size^2) // score <- 1 b / 0.5 sqrt(size^2 + size^2)
static const float HalfDiagonal = 0.5 * FMath::Sqrt(2 * FMath::Square(SquareSize)); const float Score = UseProtractor ? 1.0 - b : 1.0 - b / HalfDiagonal;
const float Score = 1.0 - b / HalfDiagonal;
// return <T', score> // return <T', score>
return TemplateIndex == -1 return TemplateIndex == -1
@@ -8,6 +8,8 @@
#include "UniStrokeRecognizer.generated.h" #include "UniStrokeRecognizer.generated.h"
static constexpr int NumTemplates = 16; static constexpr int NumTemplates = 16;
static const float Diagonal = FMath::Sqrt(2 * FMath::Square(SquareSize));
static const float HalfDiagonal = 0.5 * Diagonal;
static constexpr float AngleRange = FMath::DegreesToRadians(45.0); static constexpr float AngleRange = FMath::DegreesToRadians(45.0);
static constexpr float AnglePrecision = FMath::DegreesToRadians(2.0); static constexpr float AnglePrecision = FMath::DegreesToRadians(2.0);
@@ -20,7 +22,7 @@ struct WIZARDINGCENTRAL_API FUniStrokeRecognizer
~FUniStrokeRecognizer(); ~FUniStrokeRecognizer();
FUniStrokeResult FUniStrokeResult
Recognize(const TArray<FVector2D>& VectorPoints); Recognize(const TArray<FVector2D>& VectorPoints, const bool& UseProtractor);
void void
AddTemplate(const FString& Name, const TArray<FVector2D>& VectorPoints); AddTemplate(const FString& Name, const TArray<FVector2D>& VectorPoints);
@@ -8,7 +8,7 @@ FUniStrokeTemplate::FUniStrokeTemplate()
} }
FUniStrokeTemplate::FUniStrokeTemplate(const FString& Name, FUniStrokeTemplate::FUniStrokeTemplate(const FString& Name,
const TArray<FUniStrokePoint>& Points) const TArray<FUniStrokePoint>)
{ {
this->Name = Name; this->Name = Name;
this->Points = Points; this->Points = Points;
@@ -16,7 +16,7 @@ struct WIZARDINGCENTRAL_API FUniStrokeTemplate
FUniStrokeTemplate(); FUniStrokeTemplate();
FUniStrokeTemplate(const FString& Name, FUniStrokeTemplate(const FString& Name,
const TArray<FUniStrokePoint>& Points); const TArray<FUniStrokePoint>);
~FUniStrokeTemplate(); ~FUniStrokeTemplate();
FString Name; FString Name;