<style>.lazy{display:none}</style> Skip to main content
Tag

fundamentals

Unreal Engine C++ Fundamentals – Using Tags with Transformations !

By Development, Tutorial, Unreal No Comments

Hey guys,

Today we resume our C++ Fundamentals lessons by looking at interfaces and how they can help simply our life by allowing for common contracts to be shared by different game actors.

As usual you can find the start project on our GitHub page.

What are these tags ? And why do I care ?

Tags are essentially a collection of strings that can be applied to an Actor or an Actors Component and then referenced by other Actors or parts of the game world by those tags.

Very similar to using tags on a blog to include metadata for search engines to query … like this blog !

Tags ?! We don’t need to no stinking tags !

Sure you do, and they are really easy to use which is why this post is going to be super short.

Take a look, in this case we are displaying all tags for a specific actor.

// iterate over all of our actors
for(TActorIterator<AActor> ActorIterator(GetWorld()); ActorIterator; ++ActorIterator)
{
  AActor* Actor = *ActorIterator;
  // ensure actor is not null
  // ignore self if found
  // ensure we find actors of a specific interface only
  if(Actor && Actor != this && Actor->GetClass()->ImplementsInterface(UInteractiveActor::StaticClass()))
  {
    // display all available tags for an actor
    for(FName Tag : Actor->Tags)
    {
     	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Cyan, Tag.ToString());
    }
  }
}

We can also just check for a specific tag without iterating over all of them by using ActorHasTag method.

if(Actor->ActorHasTag(TagToCheck))
{
    IInteractiveActor::Execute_Interact(Actor);		
}

Wait you forgot about lerping ? What is lerping !?

Lerping is a way of translating between vector A and vector B over some period of time.

For example if you need to scale an object from one size to another you can use FMath::Lerp to accomplish this.

BaseMesh->SetWorldScale3D(FMath::Lerp(BaseMesh->GetComponentScale(), FVector(2.f, 2.f, 2.f), 0.05f));

In this example we go from vector A ( GetComponentScale() of our mesh ) to vector B ( 2x the size ) over a period of time represented by 0.05f time.

Take a look.

That’s it folks, not much more reading but here are a few links for you to check out:

Unreal Engine C++ Fundamentals – Interfaces!

By Development, Tutorial, Unreal 3 Comments

Hey guys,

Today we resume our C++ Fundamentals lessons by looking at interfaces and how they can help simply our life by allowing for common contracts to be shared by different game actors.

As usual you can find the start project on our GitHub page.

What is an interface ? Tell me !

An interface is an abstract definition of a contract. What this means is an interface defines how our class can be interfaced ( hah ! ) with while keeping the implementation details away.

More than that it allows us to create a common method signature between various disparate objects.

Consider I have an interface that has a method on it called “DoStuff” and I have two objects, Dog and Person, that inherit this interface. When I call Dog->DoStuff he may perform a trick while if I call the same method of Person->DoStuff he may tell me to fuck off and to stop bothering them. But from the point of view of the code interacting with those actors it’s the same behavior.

This allows for a lot of re-use and generic implementations while keeping the details of those implementations specific.

This all seems very abstract, show me code !

So let’s take a look at how an interface class is structured

UINTERFACE(MinimalAPI)
class UInteractiveActor : public UInterface
{
  GENERATED_BODY()
};

/**
 * 
 */
class UE4FUNDAMENTALS09_API IInteractiveActor
{
  GENERATED_BODY()

  // Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:

  UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Interact")
  void Interact();
};

As you can see it’s pretty thin in definition, we simply have a class that inherits from UInterface and then defines the method signature of “Interact”.

Excellent now we are cooking with fire, now what ?

Once we have the interface in place we now start including it on our objects. Let’s take a look at our InteractiveProp.

UCLASS()
class UE4FUNDAMENTALS09_API AInteractiveProp : public AActor, public IInteractiveActor
{
  GENERATED_BODY()
  
public:	
  // Sets default values for this actor's properties
  AInteractiveProp();

  UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Interact")
  class UStaticMeshComponent* BaseMesh;

protected:
  // Called when the game starts or when spawned
  virtual void BeginPlay() override;

public:	
  // Called every frame
  virtual void Tick(float DeltaTime) override;

  UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Interact")
  void Interact();	// prototype declaration
  virtual void Interact_Implementation() override;	// actual implementation of our interact method

private:
  bool bIsBig;
};

The major thing to note is that in order to leverage the interface, we modify our class signature to bring in “IInteractiveActor”

class UE4FUNDAMENTALS09_API AInteractiveProp : public AActor, public IInteractiveActor

Then we overwrite the Interact method by first declaring the prototype method signature and then the implementation one. Please note that the “_Implementation” is important and has to be exact for the reflection mechanic in Unreal to process your interface + implementation.

UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Interact")
void Interact();	// prototype declaration
virtual void Interact_Implementation() override;	// actual implementation of our interact method

So that was pretty straight forward, now how do I use these guys ?

To execute interface definitions we have a few ways of going about.

First we need to determine if an object uses an interface and we have two ways of checking that.

  1. Based on the ImplementsInterface check
  2. Using a cast to an interface object

Here is the first example

InteractHit.GetActor()->GetClass()->ImplementsInterface(UInteractiveActor::StaticClass())

And the second one

IInteractiveActor* InteractiveActor = Cast<IInteractiveActor>(InteractHit.GetActor());
if(InteractiveActor)
{
  // do stuff
}

Once you determine if an object has an interface the way you execute a call on that object is by passing it into the interface “Execute_” call.

IInteractiveActor::Execute_Interact(InteractHit.GetActor());

This basically says, for interface InteractiveActor Execute the method Interact and pass in our Actor on which that method will be triggered.

Here is a full code block that does this logic using a line trace fired from the player against an object.

void AUE4Fundamentals09Character::Interact()
{
  FVector Start;
  FVector End;

  FVector PlayerEyesLoc;
  FRotator PlayerEyesRot;

  GetActorEyesViewPoint(PlayerEyesLoc, PlayerEyesRot);

  Start = PlayerEyesLoc;
  End = PlayerEyesLoc + (PlayerEyesRot.Vector() * LineTraceDistance);

  FCollisionQueryParams TraceParams(FName(TEXT("InteractTrace")), true, this);

  FHitResult InteractHit = FHitResult(ForceInit);

  bool bIsHit = GetWorld()->LineTraceSingleByChannel(InteractHit, Start, End, ECC_GameTraceChannel3, TraceParams);

  if(bIsHit)
  {
    Log(ELogLevel::WARNING, InteractHit.Actor->GetName());
    // start to end, green, will lines always stay on, depth priority, thickness of line
    DrawDebugLine(GetWorld(), Start, End, FColor::Green, false, 5.f, ECC_WorldStatic, 1.f);

    // implements interface
    if(InteractHit.GetActor()->GetClass()->ImplementsInterface(UInteractiveActor::StaticClass()))
    {
      IInteractiveActor::Execute_Interact(InteractHit.GetActor());
    }
  }
}

That’s it folks !

In addition to the video here are a few resources for further reading:

 

Unreal Engine C++ Fundamentals – FTimerHandle & Timers

By Development, Tutorial, Unreal No Comments

Hey guys,

We are bouncing back to C++ Fundamentals this time looking at FTimerHandle and  Timers in general by messing around with our props.

Additionally you can always find the sample project on our GitHub page.

Timers ?! What are they ?

Timers allow us to trigger events based on elapsed time in the form of creating asynchronous callbacks to specific function pointers.

Plain English: we light a fuse, let it burn down, something explodes !

How do we make these magical exploding clocks ?

Well let’s take a look at some code as these things are pretty easy to understand.

.h

FTimerHandle TriggerDestroyTimerHandle;

UFUNCTION()
void TriggerDestroy();

.cpp

GetWorld()->GetTimerManager().SetTimer(TriggerDestroyTimerHandle, this, &ADestructibleProp::TriggerDestroy, 5.f, true);

void ADestructibleProp::TriggerDestroy()
{
  // do stuff
}

So as you can see the implementation is pretty easy to understand.

  • We are creating a timer from our Time Manager object.
  • We are then registering this call back to use our Timer Handle.
  • Then we assign a callback method to be triggered at the end of our countdown.
  • Then finally we set that the countdown duration is 5 seconds.

Excellent ! Let’s blow some things up.

Timers can also be used to trigger modifications to specific values every so often. In this case we are going to simulate a fuse that will count down every second before it triggers an event.

First we are going to call the timer as we did previously, except this time we are going to call a new method and have this timer run every second.

.cpp

GetWorld()->GetTimerManager().SetTimer(TriggerDestroyTimerHandle, this, &ADestructibleProp::TriggerCountdownToDestroy, 1.f, true);

Then we add in our count down logic

.h

int32 TriggerCountdown;

UFUNCTION()
void TriggerCountdownToDestroy();

Finally we add in our implementation where we modify our count down variable by subtracting one from it every second.

Additionally we trigger a second timer call to our original method by randomly generating a delay before it gets triggered.

.cpp

void ADestructibleProp::TriggerCountdownToDestroy()
{
  // count down to zero
  if (--TriggerCountdown <= 0) 
  {
    int32 RandomDelay = FMath::RandRange(1, 5);

    GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Orange, "Boom ! with a delay of: " + FString::FromInt(RandomDelay));
    GetWorld()->GetTimerManager().SetTimer(TriggerDestroyTimerHandle, this, &ADestructibleProp::TriggerDestroy, RandomDelay, true);
  }
  else 
  {
    GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Orange, "Counting down to explosion: " + FString::FromInt(TriggerCountdown));
  }
}

This allows us to have custom implementations in our timers that perform very specific work.

Pretty cool !

 

Below you can find a few more links with some additional reading material: