Hello guys, how are you doing?
I’m here one more time to ask for help.
You see, I have a class derived from AActor, where I’m coding a black hole skill, and a interface, where I have coded a sorting algorithm.
For some reason, in one of the subroutines of the sorting algorithm (ISortingAlgorithmsInterface::PartitionateArray), the compiler isn’t going through the if where a TIsPointer<> is verifying the generic type T present in the parameter list, and is going through the else, where a UObject member function is being accessed using . , not ->. In the code block where the sorting algorithm is being called (Tick method), a TArray<UPrimitive*> is passed as an argument. The type T is a pointer to some class, in this case, to a UPrimitiveComponent, and the else should deal only with non-pointer types.
Below, you can find the code:
INTERFACE
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "SortingAlgorithmsInterface.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI, Blueprintable, BlueprintType)
class USortingAlgorithmsInterface : public UInterface
{ GENERATED_BODY()
};
/**
*
*/
class PRJ_PROJECTILETESTEX_API ISortingAlgorithmsInterface
{ GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
protected:
template<typename T>
static uint8 PartitionateArray(TArray<T>& Arr, uint8 LowerBoundary, uint8 UpperBoundary);
template<typename T>
static uint8 PartitionateArrayRandomly(TArray<T>& Arr, uint8 LowerBoundary, uint8 UpperBoundary);
template<typename T>
static void Swap(T SwappableSubjectA, T SwappableSubjectB);
public: template<typename T>
static void RandomizedQuickSort(TArray<T>& Arr, uint8 LowerBoundary, uint8 UpperBondaury);
};
template<typename T>
static uint8 ISortingAlgorithmsInterface::PartitionateArray(TArray<T>& Arr, uint8 LowerBoundary, uint8 UpperBoundary)
{ static_assert(TIsDerivedFrom<TRemovePointer<T>::Type, UObject>::IsDerived, "T is not derived from UObject class");
uint8 SortingIndex = LowerBoundary - 1;
//if (std::is_pointer<T>::value)
if(TIsPointer<T>::Value)
{
[INDENT=2]uint8 Pivot = Cast<UObject>(Arr[UpperBoundary])->GetUniqueID();
for (int Index = LowerBoundary; Index <= UpperBoundary - 1; Index++)
{[/INDENT]
[INDENT=3]if (Cast<UObject>(Arr[Index])->GetUniqueID() <= Pivot)
{
SortingIndex++;
Swap(Arr[SortingIndex], Arr[Index]);
}[/INDENT]
[INDENT=2]}[/INDENT]
}
else
{
[INDENT=2]uint8 Pivot = Cast<UObject>(Arr[UpperBoundary]).GetUniqueID();
for (int Index = LowerBoundary; Index <= UpperBoundary - 1; Index++)
{[/INDENT]
[INDENT=3]if (Cast<UObject>(Arr[Index]).GetUniqueID() <= Pivot)
{
SortingIndex++;
Swap(Arr[SortingIndex], Arr[Index]);
}[/INDENT]
[INDENT=2]}[/INDENT]
}
Swap(Arr[SortingIndex + 1], Arr[UpperBoundary]);
return SortingIndex + 1;
}
template<typename T>
static uint8 ISortingAlgorithmsInterface::PartitionateArrayRandomly(TArray<T>& Arr, uint8 LowerBoundary, uint8 UpperBoundary)
{ //static_assert(std::is_base_of<UObject, T>::value, "T is not derived from UObject class");
static_assert(TIsDerivedFrom<TRemovePointer<T>::Type, UObject>::IsDerived, "T is not derived from UObject class");
uint8 RandomIndex = FMath::RandRange(LowerBoundary, UpperBoundary);
Swap(Arr[RandomIndex], Arr[UpperBoundary]);
return PartitionateArray(Arr, LowerBoundary, UpperBoundary);
}
template<typename T>
static void ISortingAlgorithmsInterface::RandomizedQuickSort(TArray<T>& Arr, uint8 LowerBoundary, uint8 UpperBoundary)
{ //static_assert(std::is_base_of<UObject, T>::value, "T is not derived from UObject class");
static_assert(TIsDerivedFrom<TRemovePointer<T>::Type, UObject>::IsDerived, "T is not derived from UObject class");
if (LowerBoundary < UpperBoundary)
{
[INDENT=2]uint8 PartitionIndex = PartitionateArrayRandomly(Arr, LowerBoundary, UpperBoundary);
RandomizedQuickSort(Arr, LowerBoundary, PartitionIndex - 1);
RandomizedQuickSort(Arr, PartitionIndex + 1, UpperBoundary);[/INDENT]
}
}
template<typename T>
static void ISortingAlgorithmsInterface::Swap(T SwappableSubjectA, T SwappableSubjectB)
{ //static_assert(std::is_base_of<UObject, T>::value, "T is not derived from UObject class");
static_assert(TIsDerivedFrom<TRemovePointer<T>::Type, UObject>::IsDerived, "T is not derived from UObject class");
T Temp = SwappableSubjectA;
SwappableSubjectA = SwappableSubjectB;
SwappableSubjectB = Temp;
}
SKILL
// Fill out your copyright notice in the Description page of Project Settings.
#include "BlackHoleSkill.h"
#include "Components/SphereComponent.h"
#include "Gameframework/ProjectileMovementComponent.h"
#include "GameFramework/Character.h"
#include "Engine/SkeletalMeshSocket.h"
#include "PRJ_ProjectileTestEXCharacter.h"
#include "NiagaraSystem.h"
#include "NiagaraComponent.h"
#include "NiagaraFunctionLibrary.h"
#include "DrawDebugHelpers.h"
#include "ProjectileTestEXConstants.h"
#include "Kismet/KismetMathLibrary.h"
#include "SortingAlgorithmsInterface.h"
#include "SearchingAlgorithmsInterface.h"
// Sets default values
ABlackHoleSkill::ABlackHoleSkill(const FObjectInitializer& ObjectInitializer)
{ // 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;
BlackHoleGravitationalInfluenceSpace = ObjectInitializer.CreateDefaultSubobject<USphereComponent>(this, TEXT("BlackHoleGravitationalInfluenceSpace"));
BlackHoleGravitationalInfluenceSpace->SetSphereRadius(500);
BlackHoleGravitationalInfluenceSpace->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
FCollisionResponseContainer CollisionResponseContainer = FCollisionResponseContainer(ECollisionResponse::ECR_Ignore);
CollisionResponseContainer.SetResponse(ECollisionChannel::ECC_PhysicsBody, ECollisionResponse::ECR_Overlap);
BlackHoleGravitationalInfluenceSpace->SetCollisionResponseToChannels(CollisionResponseContainer);
BlackHoleGravitationalInfluenceSpace->SetGenerateOverlapEvents(true);
BlackHoleGravitationalInfluenceSpace->SetSimulatePhysics(false);
RootComponent = BlackHoleGravitationalInfluenceSpace;
/*BlackHoleEventHorizon = ObjectInitializer.CreateDefaultSubobject<UStaticMeshComponent>(this, TEXT("BlackHoleEventHorizon"));
BlackHoleEventHorizon->SetWorldScale3D(FVector(.25f, .25f, .25f));
BlackHoleEventHorizon->SetRelativeLocation(FVector(0.f, 0.f, 0.f));
BlackHoleEventHorizon->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
BlackHoleEventHorizon->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Overlap);
BlackHoleEventHorizon->SetGenerateOverlapEvents(true);
BlackHoleEventHorizon->SetSimulatePhysics(false);
BlackHoleEventHorizon->SetupAttachment(RootComponent);*/
BlackHoleVFXComp = ObjectInitializer.CreateDefaultSubobject<UNiagaraComponent>(this, TEXT("BlackHoleVFX"));
BlackHoleVFXComp->SetupAttachment(RootComponent);
BlackHoleMovementComp = ObjectInitializer.CreateDefaultSubobject<UProjectileMovementComponent>(this, TEXT("BlackHoleMovementComp"));
BlackHoleMovementComp->SetUpdatedComponent(BlackHoleGravitationalInfluenceSpace);
BlackHoleMovementComp->InitialSpeed = 0.f;
BlackHoleMovementComp->MaxSpeed = 0.f;
BlackHoleMovementComp->bRotationFollowsVelocity = true;
BlackHoleMovementComp->bShouldBounce = false;
BlackHoleMovementComp->ProjectileGravityScale = 0.f;
}
// Called when the game starts or when spawned
void ABlackHoleSkill::BeginPlay()
{ Super::BeginPlay();
SetLifeSpan(5.f);
UE_LOG(LogTemp, Warning, TEXT("Actor lifespan = %f"), InitialLifeSpan);
if (BlackHoleVFX)
{
[INDENT=2]ACharacter* BlackHoleOwner = Cast<ACharacter>(GetOwner());
if (BlackHoleOwner)
{[/INDENT]
[INDENT=3]BlackHoleVFXComp = UNiagaraFunctionLibrary::SpawnSystemAttached(
BlackHoleVFX,
RootComponent,
FName("BlackHoleVFX"),
BlackHoleOwner->GetMesh()->GetSocketLocation("hand_r"),
GetActorForwardVector().ToOrientationRotator(),
EAttachLocation::KeepWorldPosition,
false
);[/INDENT]
[INDENT=2]}[/INDENT]
}
}
bool ABlackHoleSkill::Compare(TArray<UPrimitiveComponent*> Arr1, TArray<UPrimitiveComponent*> Arr2)
{ bool IsEqual = false;
if(Arr1.Num() == Arr2.Num())
{
[INDENT=2]IsEqual = true;
for(int Index = 0; Index <= Arr1.Num() - 1; Index++)
{[/INDENT]
[INDENT=3]if(Arr1[Index]->GetUniqueID() != Arr2[Index]->GetUniqueID())
{[/INDENT]
[INDENT=4]IsEqual = false;
return IsEqual;[/INDENT]
[INDENT=3]}[/INDENT]
[INDENT=2]}[/INDENT]
}
return IsEqual;
}
FBlackHoleOrbitData ABlackHoleSkill::GenerateOrbitData(UPrimitiveComponent* OverlappedComponent)
{ FBlackHoleOrbitData NewOrbitData = FBlackHoleOrbitData();
NewOrbitData.OrbitID = OverlappedComponent->GetUniqueID();
return FBlackHoleOrbitData();
}
void ABlackHoleSkill::EndPlay(const EEndPlayReason::Type EndPlayReason)
{ Super::EndPlay(EndPlayReason);
if (PreviouslyOverlapppedComponentArr.Num() > 0)
{
[INDENT=2]for (UPrimitiveComponent* PreviouslyOverlappedComponent : PreviouslyOverlapppedComponentArr)
{[/INDENT]
[INDENT=3]PreviouslyOverlappedComponent->SetEnableGravity(true);[/INDENT]
[INDENT=2]}[/INDENT]
}
}
void ABlackHoleSkill::MoveInDirection(FVector Direction)
{ BlackHoleMovementComp->Velocity = Direction * BlackHoleMovementComp->InitialSpeed;
}
void ABlackHoleSkill::PostInitializeComponents()
{ Super::PostInitializeComponents();
BlackHoleMass = BlackHoleMassScale * SUN_MASS;
}
// Called every frame
void ABlackHoleSkill::Tick(float DeltaTime)
{ Super::Tick(DeltaTime);
DrawDebugSphere(GetWorld(), GetActorLocation(), BlackHoleGravitationalInfluenceSpace->GetScaledSphereRadius(), 20, FColor::Red, false, .1f, 0, 2.f);
TArray<UPrimitiveComponent*> OverlappedComponentArr;
GetOverlappingComponents(OverlappedComponentArr);
TArray<UPrimitiveComponent*> TempArr;
for(UPrimitiveComponent* OverlappedComponent : OverlappedComponentArr)
{
[INDENT=2]if(OverlappedComponent->GetOwner()->GetClass() != ACharacter::StaticClass())
{
TempArr.Add(OverlappedComponent);
}[/INDENT]
}
ISortingAlgorithmsInterface::RandomizedQuickSort(TempArr, 0, TempArr.Num() - 1);
if(!Compare(TempArr, PreviouslyOverlapppedComponentArr) && TempArr.Num() > 0)
{
[INDENT=2]for(int Index = 0; Index <= TempArr.Num() - 1; Index++)
{[/INDENT]
[INDENT=3]if(OrbitDataArr.Num() == 0 || Index > OrbitDataArr.Num() - 1)
{
}
else
{[/INDENT]
[INDENT=4]if(Index <= OrbitDataArr.Num() - 1 && (OrbitDataArr[Index].OrbitID != TempArr[Index]->GetUniqueID()))
{
}[/INDENT]
[INDENT=3]}[/INDENT]
[INDENT=2]}[/INDENT]
}
if(PreviouslyOverlapppedComponentArr.Num() > 0)
{
[INDENT=2]for(UPrimitiveComponent* PreviouslyOverlappedComponent : PreviouslyOverlapppedComponentArr)
{[/INDENT]
[INDENT=3]if(!OverlappedComponentArr.Contains(PreviouslyOverlappedComponent))
{[/INDENT]
[INDENT=4]PreviouslyOverlappedComponent->SetEnableGravity(true);[/INDENT]
[INDENT=3]}[/INDENT]
[INDENT=2]}[/INDENT]
}
PreviouslyOverlapppedComponentArr = OverlappedComponentArr;
}
OUTPUT LOG
1>------ Build started: Project: PRJ_ProjectileTestEX, Configuration: Development_Editor x64 ------
2>------ Skipped Build: Project: UE4, Configuration: BuiltWithUnrealBuildTool Win32 ------
2>Project not selected to build for this solution configuration
1>Building PRJ_ProjectileTestEXEditor...
1>Using Visual Studio 2019 14.22.27905 toolchain (D:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905) and Windows 10.0.18362.0 SDK (C:\Program Files (x86)\Windows Kits\10).
1>Building 4 actions with 12 processes...
1> [1/4] BlackHoleSkill.cpp
1>D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Source\PRJ_ProjectileTestEX\SortingAlgorithmsInterface.h(60): error C2228: left of '.GetUniqueID' must have class/struct/union
1> D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Source\PRJ_ProjectileTestEX\SortingAlgorithmsInterface.h(60): note: type is 'To *'
1> with
1>
1> To=UObject
1> ]
1> D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Source\PRJ_ProjectileTestEX\SortingAlgorithmsInterface.h(60): note: did you intend to use '->' instead?
1> D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Source\PRJ_ProjectileTestEX\SortingAlgorithmsInterface.h(84): note: see reference to function template instantiation 'uint8 ISortingAlgorithmsInterface::PartitionateArray<UPrimitiveComponent*>(TArray<UPrimitiveComponent *,FDefaultAllocator> &,uint8,uint8)' being compiled
1> D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Source\PRJ_ProjectileTestEX\SortingAlgorithmsInterface.h(95): note: see reference to function template instantiation 'uint8 ISortingAlgorithmsInterface::PartitionateArrayRandomly<UPrimitiveComponent*>(TArray<UPrimitiveComponent *,FDefaultAllocator> &,uint8,uint8)' being compiled
1> D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Source\PRJ_ProjectileTestEX\BlackHoleSkill.cpp(266): note: see reference to function template instantiation 'void ISortingAlgorithmsInterface::RandomizedQuickSort<UPrimitiveComponent*>(TArray<UPrimitiveComponent *,FDefaultAllocator> &,uint8,uint8)' being compiled
1>D:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160\Microsoft.MakeFile.Targets(44,5): error MSB3073: The command ""D:\Program Files\Epic Games\UE_4.25\Engine\Build\BatchFiles\Build.bat" PRJ_ProjectileTestEXEditor Win64 Development -Project="D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\PRJ_ProjectileTestEX.uproject" -WaitMutex -FromMsBuild" exited with code 6.
1>Done building project "PRJ_ProjectileTestEX.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 1 skipped ==========
What am I doing wrong? Doesn’t TIsPointer<> work properly?
Thanks!