My Building Escape after Pointer Protection Process? lecture

Hi There!!

In this lecture, we learn to protect ourselves from pointers. If not protected, Unreal can crash horribly without any error messages. This lecture prevents that by showing how to protect ourselves from every pointer being used.

(No Changes were made in UE Editor.)

VS Code-

OpenDorr.cpp-

// Copyright Ateeb Ahmed 2021

#include "Engine/World.h"

#include "Components/PrimitiveComponent.h"

#include "GameFramework/PlayerController.h"

#include "OpenDoor.h"

#include "GameFramework/Actor.h"

#define OUT

// Sets default values for this component's properties

UOpenDoor::UOpenDoor()

{

    // Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features

    // off to improve performance if you don't need them.

    PrimaryComponentTick.bCanEverTick = true;

}

// Called when the game starts

void UOpenDoor::BeginPlay()

{

    Super::BeginPlay();

    InitialYaw = GetOwner()->GetActorRotation().Yaw; // Stores the current yaw(Z axis) of the door.

    CurrentYaw = InitialYaw; 

    OpenAngle += InitialYaw;

    if(!PressurePlate)

    {

        UE_LOG(LogTemp, Error, TEXT("%s this actor does not have a pressure plate!!"), *GetOwner()->GetName());

    } 

    if(OpenAngle == 0.0f)

    {

        UE_LOG(LogTemp, Error, TEXT("%s this actor has 0 retation!!"), *GetOwner()->GetName());

    }

}

// Called every frame

void UOpenDoor::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)

{

    Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

    if (TotalMassOfActors() > MassToOpenDoors)

    {

        OpenDoor(DeltaTime);

        DoorLastOpened = GetWorld()->GetTimeSeconds();

    }

    else

    {

        if (GetWorld()->GetTimeSeconds() - DoorLastOpened > DoorCloseDelay)

        {

            CloseDoor(DeltaTime);

        }

    }

}

void UOpenDoor::OpenDoor(float DeltaTime)

{

    CurrentYaw = FMath::Lerp(CurrentYaw, OpenAngle, DeltaTime * DoorOpenVelocity); // Changing the yaw to the target yaw

    FRotator DoorRotation = GetOwner()->GetActorRotation(); // Getting the rotation of the door

    DoorRotation.Yaw = CurrentYaw; // Changing yaw of the door

    GetOwner()->SetActorRotation(DoorRotation);

}

void UOpenDoor::CloseDoor(float DeltaTime)

{

    CurrentYaw = FMath::Lerp(CurrentYaw, InitialYaw, DeltaTime * DoorCloseVelocity); // Changing the yaw to the target yaw

    FRotator DoorRotation = GetOwner()->GetActorRotation(); // Getting the rotation of the door

    DoorRotation.Yaw = CurrentYaw; // Changing yaw of the door

    GetOwner()->SetActorRotation(DoorRotation);

}

float UOpenDoor::TotalMassOfActors() const

{

    float TotalMass = 0.f; 

    // Find All Overlapping Actors.

    TArray<AActor*> OverlappingActors;

    // Add up their Masses.

    if(PressurePlate) {return TotalMass;}

    PressurePlate->GetOverlappingActors(OUT OverlappingActors);

    

    // for(AActor* Actor : OverlappingActors)

    for(AActor* Actor : OverlappingActors)

    {

        TotalMass += Actor->FindComponentByClass<UPrimitiveComponent>()->GetMass();

        UE_LOG(LogTemp, Warning, TEXT("%s is on the pressureplate!"), *Actor->GetName());

    }

    return TotalMass;

}

Grabber.cpp-

// Copyright Ateeb Ahmed 2021

#include "DrawDebugHelpers.h"
#include "Engine/World.h"
#include "GameFramework/PlayerController.h"
#include "Grabber.h"

#define OUT

// Sets default values for this component's properties
UGrabber::UGrabber()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = true;
}

// Called when the game starts
void UGrabber::BeginPlay()
{
	Super::BeginPlay();

	FindPhysicsHandle();
	SetupInputComponent();
}

// This function takes all the inputs from the action mapping.
void UGrabber::SetupInputComponent()
{
	InputComponent = GetOwner()->FindComponentByClass<UInputComponent>();
	if(InputComponent)
	{
		UE_LOG(LogTemp, Warning, TEXT("Input component found on %s"), *GetOwner()->GetName());
		InputComponent->BindAction("Grab", IE_Pressed, this, &UGrabber::Grab);
		InputComponent->BindAction("Grab", IE_Released, this, &UGrabber::Release);
	}
}


// This function is called when LMB is pressed. Also grabs the objects with ECC_PhysicsBody.
void UGrabber::Grab()
{
	FHitResult HitResult = GetFirstPhysicsBodyInReach();
	UPrimitiveComponent* ComponentToGrab = HitResult.GetComponent();
	AActor* ActorHit = HitResult.GetActor();

	// If we hit something then attach the physics handle.

	if(ActorHit)
	{
		if (!PhysicsHandle) {return;}
		PhysicsHandle->GrabComponentAtLocation
			(ComponentToGrab,
			NAME_None,
			GetPlayersReach()
			);
	}
}

// This function is called when LMB is released. Releases the currently held actor.
void UGrabber::Release()
{
	if (!PhysicsHandle) {return;}
	PhysicsHandle->ReleaseComponent();
}


// Finds Physics handle on the actor.
void UGrabber::FindPhysicsHandle()
{
	PhysicsHandle = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>();
	if (!PhysicsHandle)
	{
		UE_LOG(LogTemp, Error, TEXT("NO PHYSICS HANDLE COMPONENT FOUND ON %s!!!"), *GetOwner()->GetName());
	}
}

// Called every frame
void UGrabber::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// If the physics handle is attached.
	if (!PhysicsHandle) {return;}
	if(PhysicsHandle->GrabbedComponent)
	{
		PhysicsHandle->SetTargetLocation(GetPlayersReach());
	}
		// Move the object we are holding.
}

// Return the first Actor within reach with physics body.
FHitResult UGrabber::GetFirstPhysicsBodyInReach() const
{
	FHitResult Hit;
	// Ray-cast out to a certain distance (Reach)
	FCollisionQueryParams TraceParams(FName(TEXT("")), false, GetOwner());

	GetWorld()->LineTraceSingleByObjectType(
		OUT Hit,
		GetPlayerWorldPos(),
		GetPlayersReach(),
		FCollisionObjectQueryParams(ECollisionChannel::ECC_PhysicsBody),
		TraceParams
	);

	return Hit;
}

// Get Players Position in World.
FVector UGrabber::GetPlayerWorldPos() const
{
	// Get player's viewpoint
	FVector PlayerViewPointLocation;
	FRotator PlayerViewPointRotation;

	GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(
		OUT PlayerViewPointLocation,
		OUT PlayerViewPointRotation
	);

	return PlayerViewPointLocation;
}

// Return the Line Trace End
FVector UGrabber::GetPlayersReach() const
{
	FVector PlayerViewPointLocation;
	FRotator PlayerViewPointRotation;

	GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(
		OUT PlayerViewPointLocation,
		OUT PlayerViewPointRotation
	);

	return PlayerViewPointLocation + PlayerViewPointRotation.Vector() * Reach;	 
}

Previous post: My Building Escape after Iteration Through Valid Actors lecture

Don’t forget to drop in your likes, share, replies, and suggestions!

Thanks for reading,
BYE!!

1 Like

Protecting pointers is one of the most important lessons you will learn.

1 Like

I agree! UE crashes are the worst thing any learner cant catch at the first glance.