Hello, help a newbie understand the basics. In a new project, I created two C++ classes: Cube and MyPawn.
Cube.cpp
ACube::ACube()
{
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you dont need it.
PrimaryActorTick.bCanEverTick = true;
static ConstructorHelpers::FObjectFinder<UStaticMesh>C(TEXT("StaticMesh'/Game/StarterContent/Shapes/Shape_Cube.Shape_Cube'"));
UStaticMeshComponent* Cube = CreateDefaultSubobject<UStaticMeshComponent>("Cube");
Cube->SetupAttachment(RootComponent);
Cube->SetWorldScale3D(FVector(0.1f));
Cube->SetStaticMesh(C.Object);
var = rand() % 100;
}
MyPawn.cpp
// Called when the game starts or when spawned
void AMyPawn::BeginPlay()
{
Super::BeginPlay();
ACube* MyCube[5];
for (int i = 0; i <= 4; i++)
{
MyCube[i] = GetWorld()->SpawnActor<ACube>(FVector(0.f + i * 15.f, 150.f, 70.f), FRotator(0.f));
}
ETraceTypeQuery TraceChannel = UEngineTypes::ConvertToTraceType(ECollisionChannel::ECC_Visibility);
TArray<AActor*> ActorsToIgnore;
FHitResult HitResult;
if (UKismetSystemLibrary::LineTraceSingle(GetWorld(), FVector(20.f, 150.f, 100.f), FVector(50.f, 150.f, 0.f), TraceChannel, false,
ActorsToIgnore, EDrawDebugTrace::ForDuration, HitResult, true, FColor::Red, FColor::Green, 500.f))
{
if (HitResult.bBlockingHit)
{
HitResult.GetActor(); // ?????????????????????
}
}
}
Certainly! It looks like you’re working on a new project in Unreal Engine using C++. Let me help you understand the basics of the code you provided:
Constructor Function (ACube::ACube()):
This function is the constructor for the ACube class. It gets called when an instance of the class is created.
PrimaryActorTick.bCanEverTick = true;: This line enables the ticking functionality, meaning the Tick() function will be called every frame.
Loading a Static Mesh (ConstructorHelpers::FObjectFinder<UStaticMesh> C(TEXT("..."));):
This line is using FObjectFinder to find a reference to a static mesh asset in the content browser. The asset is located at “StaticMesh’/Game/StarterContent/Shapes/Shape_Cube.Shape_Cube’”.
The result is stored in the variable C.
Creating a Static Mesh Component (UStaticMeshComponent* Cube = CreateDefaultSubobject<UStaticMeshComponent>("Cube");):
This line creates a new UStaticMeshComponent called Cube and attaches it to the root component.
Cube->SetWorldScale3D(FVector(0.1f)); sets the scale of the cube to 0.1 in all dimensions.
Cube->SetStaticMesh(C.Object); sets the static mesh of the cube component to the one loaded earlier.
Generating a Random Number (var = rand() % 100;):
This line generates a random number between 0 and 99 (inclusive) and stores it in the variable var. Note that rand() is a basic random number generator in C++, and its use might not be suitable for all applications.
Overall, the code is creating a cube in Unreal Engine, setting its scale and mesh, and generating a random number. If you have more specific questions or if there’s anything else you’d like to understand, feel free to ask!
HitResult.GetActor() returns a generic AActor* type by design, because it can be any actor in the world. You need to check that its result is valid (non-null) and that the actor is indeed of type ACube, then you can convert your type to the ACube type and access your variable directly.
I’m not gonna delve into details but feel free to google about type-casting.
A direct translation of what I just said would look like this :
AActor* Actor = HitResult.GetActor();
if (Actor != nullptr && Actor->IsA<ACube>())
{
ACube* ActorAsCube = (ACube*)Actor;
int32 var = ActorAsCube->var;
}
Now in UE you wouldn’t do exactly like this, because :
checking for nullptr is not enough in UE. Using IsValid(Actor) would be a better check, but UE objects are already built to convert to booleans automagically so you just need to check if (Actor) to check validity.
using IsA (or ClassIsChildOf) + c-style cast may work, but it’s not really the standard method. UE provides a Cast function that performs the check and does the cast, or returns nullptr if it fails.
Cast also accepts null (and returns null) so you don’t even need to check for validity of the Actor, you can Cast blindly and check for validity of the result. All of this allows you to perform all three actions in a single line :
AActor* Actor = HitResult.GetActor();
if (ACube* Cube = Cast<ACube>(Actor))
{
int32 var = Cube->var;
}
Chatouille basically summed it up nicely. I just want to mention that you need to define var as a public property for it to be accessible this way(just in case you arent familiar with access modifiers).