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!!