- Create a new StaticMeshActor class called Spotter. Remember to use the Show All Classes button to select StaticMeshActor as the parent class.
- Make sure that the following functions are defined and overridden in the class header:
#pragma once
#include "CoreMinimal.h"
#include "Engine/StaticMeshActor.h"
#include "Spotter.generated.h"
UCLASS()
class CHAPTER_09_API ASpotter : public AStaticMeshActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ASpotter();
// Called every frame
virtual void Tick(float DeltaSeconds) override;
UFUNCTION(BlueprintImplementableEvent)
void OnPlayerSpotted(APawn* Player);
};
- In the implementation file (Spotter.cpp), update the code to the following:
#include "Spotter.h"
#include "ConstructorHelpers.h"
#include "DrawDebugHelpers.h"
// Sets default values
ASpotter::ASpotter()
{
// 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;
// Set up visual aspect of the spotter
auto MeshAsset =
ConstructorHelpers::FObjectFinder<UStaticMesh>
(TEXT("StaticMesh'/Engine/BasicShapes/Cone.Cone'"));
UStaticMeshComponent * SM = GetStaticMeshComponent();
if (SM != nullptr)
{
if (MeshAsset.Object != nullptr)
{
SM->SetStaticMesh(MeshAsset.Object);
SM->SetGenerateOverlapEvents(true);
}
SM->SetMobility(EComponentMobility::Movable);
SM->SetRelativeRotation(FRotator(90, 0, 0));
}
}
// Called every frame
void ASpotter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
auto EndLocation = GetActorLocation() +
ActorToWorld().TransformVector(FVector(0, 0, -200));
// Check if there is an object in front of us
FHitResult HitResult;
GetWorld()->SweepSingleByChannel(HitResult,
GetActorLocation(), EndLocation, FQuat::Identity,
ECC_Camera, FCollisionShape::MakeSphere(25),
FCollisionQueryParams("Spot", true, this));
APawn* SpottedPlayer = Cast<APawn>(HitResult.Actor.Get());
// If there is call the OnPlayerSpotted function
if (SpottedPlayer != nullptr)
{
OnPlayerSpotted(SpottedPlayer);
}
// Displays where we are checking for collision
DrawDebugLine(GetWorld(), GetActorLocation(), EndLocation, FColor::Red);
}
- Compile and start the editor. Find your Spotter class in Content Browser, then left-click and drag a copy out into the game world.
- When you play the level, you'll see the red line showing the trace that the Actor is performing:
- However, nothing will happen if the player walks in front of it because we haven't implemented our OnPlayerSpotted event.
- To implement this event, we need to create a blueprint subclass of our Spotter.
- Right-click on Spotter in the Content Browser and select Create Blueprint class based on Spotter. Name the class BPSpotter:
Creating a Blueprint class based on Spotter
- Inside the Blueprint editor, click on the Override button in the Functions section of the My Blueprint panel:
- Select On Player Spotted:
- To see the event, click on the Event Graph tab. Left-click it and drag it away from the white execution pin on our event. In the context menu that appears, select and add a Print String node so that it is linked to the event:
- Delete your previous Spotter object in the level and then drag and drop a BPSpotter in. Play the level again and verify that walking in front of the trace that the BPSpotter is using now prints a string to the screen: