Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@pdfrod
Last active April 29, 2023 11:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pdfrod/7fc57e914e23d07587dfba28658e8d96 to your computer and use it in GitHub Desktop.
Save pdfrod/7fc57e914e23d07587dfba28658e8d96 to your computer and use it in GitHub Desktop.
UnrealEngine

Introduction

The notes taken here apply as of version version 4.24.3 of Unreal Engine for Linux.

Shortcuts

  • Shift + End - Snap object to the ground

Classes

  • AActor - an object that can be placed in the world. It has location, rotation and scale.
  • APawn - an Actor than can receive inputs.
  • ACharacter - a Pawn that is designed to be controlled by a player.
  • APlayerController - the PlayerController possesses a single Pawn and acts as its brain.
  • AGameMode - there's only one GameMode per level. In a multiplayer game, the GameMode only exists on the server and the rules are replicated to each of the connected clients.
  • UGameInstance - is created at the start of the game and persists even when there's a level change.
  • AGameState - The GameState contains the state of the game, which could include things like the list of connected players, the score, where the pieces are in a chess game, or the list of what missions you have completed in an open world game. The GameState exists on the server and all clients and can replicate freely to keep all machines up to date.
  • PlayerState

Code

Miscellaneous

// Logging to console
FString Var(TEXT("X"));
UE_LOG(LogTemp, Warning, TEXT("Value of %s is %d %s"), *Var, X);

// Show debug message on game screen
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Hello"));

// Casting
AMyActor MyActor = Cast<MyActor>(Object);

// Enums
UENUM(BlueprintType)
enum class EDays: uint8
{
  ED_Sunday UMETA(DisplayName = "Sunday"),
  ED_Monday UMETA(DisplayName = "Monday"),
  ...
}

// To use inside a Pawn constructor - make this pawn control player 0.
// GameMode also needs to be configured to allow control by Pawns of this class.
AutoPossessPlayer = EAutoReceiveInput::Player0;

// To draw debug shapes use DrawDebug*(...) family of functions.
// Examples:
DrawDebugCircle(GetWorld(), Location, Radius, 10, FColor::Red, true, -1.f, 0, 5.f);
UKismetSystemLibrary::DrawDebugCircle(GetWorld(), Location, Radius, 10.f, FColor::Red, -1.f, 5.f);

// Get viewport coordinates of a 3D location
FVector2D ScreenLocation;
ProjectWorldLocationToScreen(WorldLocation, ScreenLocation);

Actors

// Instantiate an actor
GetWorld()->SpawnActor<AMyActor>(AMyActor::StaticClass(), Location);

Components

// Instantiate a component
Component = CreateDefaultSubobject<USceneComponent>(TEXT("XptoComponent"));
Component->SetupAttachment(ParentComponent); // By default it gets attached to root component

// Instantiate a component dynamically (i.e., outside the Actor contructor)
Component = NewObject<USceneComponent>(this, TEXT("XptoComponent"));
Component->SetupAttachment(RootComponent);
// When created dynamically, components need to be manually registered.
Component->RegisterComponent();

Camera

// USpringArmComponent can be used to create a camera with lag.
SpringArmComponent = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
SpringArmComponent->TargetArmLength = 70;
CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent"));
CameraComponent->SetupAttachment(SpringArmComponent);

Events

Actors overlap

// Both Actors need to be configured to allow overlap events.

void AMyActor::NotifyActorBeginOverlap(class AActor* OtherActor)  
{  
  Super::NotifyActorBeginOverlap(OtherActor);
  if (OtherActor && (OtherActor != this))
  {
    // Do something
  }
}

void AMyActor::NotifyActorEndOverlap(class AActor* OtherActor)  
{  
  Super::NotifyActorBeginOverlap(OtherActor);
  if (OtherActor && (OtherActor != this))
  {
    // Do something
  }
}

Components overlap

// Requirements:
// - both components need to be configured to allow overlap events
// - event handler functions need to be marked with UFUNCTION

Component->OnComponentBeginOverlap.AddDynamic(this, &AMyPawn::OnOverlapBegin);
Component->OnComponentEndOverlap.AddDynamic(this, &AMyPawn::OnOverlapEnd);

void AMyPawn::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)  
{  
  // Other Actor is the actor that triggered the event. Check that is not ourself.  
  if ((OtherActor != nullptr) && (OtherActor != this) && (OtherComp != nullptr))  
  {  
    // Do something
  }  
}

void AMyPawn::OnOverlapEnd(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)  
{  
  // Other Actor is the actor that triggered the event. Check that is not ourself.  
  if ((OtherActor != nullptr) && (OtherActor != this) && (OtherComp != nullptr))  
  {  
    // Do something 
  }  
}

Actor mouse over

// Requirements:
// - "Mouse Over Events" need to be enabled on the Player Controller
// - collision must be enabled ("Query only" or "Query and Physics") 
// - collision response to "Visibility" must be "Block"

void AMyPawn::NotifyActorBeginCursorOver()
{
  Super::NotifyActorBeginCursorOver();
  // Do something
}

void AMyPawn::NotifyActorEndCursorOver()
{
  Super::NotifyActorEndCursorOver();
  // Do something
}

Component mouse over

// Requirements:
// - "Mouse Over Events" need to be enabled on the Player Controller
// - collision must be enabled ("Query only" or "Query and Physics") 
// - collision response to "Visibility" must be "Block"
// - event handler functions need to be marked with UFUNCTION

Component->OnBeginCursorOver.AddDynamic(this, &AMyPawn::OnBeginCursorOver);
Component->OnEndCursorOver.AddDynamic(this, &AMyPawn::OnEndCursorOver);

void AMyPawn::OnBeginCursorOver(UPrimitiveComponent* Component)
{
  // Do something
}

void AMyPawn::OnEndCursorOver(UPrimitiveComponent* Component)
{
  // Do something
}

Component mouse click

// Requirements:
// - "Mouse Click Events" need to be enabled on the Player Controller
// - collision must be enabled ("Query only" or "Query and Physics") 
// - collision response to "Visibility" must be "Block"
// - event handler function needs to be marked with UFUNCTION

Component->OnClicked.AddDynamic(this, &AMyPawn::OnClick)

void AMyPawn::OnClick(UPrimitiveComponent* Component, FKey ButtonPressed)
{
  // Do something
}

Player actions

Version A

For either versions, key bindings need to be configured on the "Input" section of the Project settings.

// Only works for Pawns (or descendants).

void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
  Super::SetupPlayerInputComponent(PlayerInputComponent);
  PlayerInputComponent->BindAxis("MoveForward", this, &AMyPawn::HandleMoveForward);
  PlayerInputComponent->BindAxis("MoveSideways", this, &AMyPawn::HandleMoveSideways);
  PlayerInputComponent->BindAxis("RotateYaw", this, &AMyPawn::HandleRotateYaw);
}

void AMyPawn::HandleMoveForward(float Value)
{
  SetActorLocation(GetActorLocation() + GetActorForwardVector() * Value, true);
}

void AMyPawn::HandleMoveSideways(float Value)
{
  SetActorRelativeLocation(GetActorLocation() + GetActorRightVector() * Value, true);
}

void AMyPawn::HandleRotateYaw(float Value)
{
  FRotator Rotation = GetActorRotation();
  Rotation.Yaw += Value;
  SetActorRelativeRotation(Rotation);
}

Version B

// Only works for Characters (or descendants).

void AMyCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
  check(PlayerInputComponent);
  PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
  PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);
  PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &AMyCharacter::HandleFire);
  PlayerInputComponent->BindAxis("MoveForward", this, &AMyCharacter::MoveForward);
  PlayerInputComponent->BindAxis("MoveRight", this, &AMyCharacter::MoveRight);

  // We have 2 versions of the rotation bindings to handle different kinds of devices differently
  // "turn" handles devices that provide an absolute delta, such as a mouse.
  // "turnrate" is for devices that we choose to treat as a rate of change
  // such as an analog joystick
  PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
  PlayerInputComponent->BindAxis("TurnRate", this, &AMyCharacter::TurnAtRate);
  PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
  PlayerInputComponent->BindAxis("LookUpRate", this, &AMyCharacter::LookUpAtRate);
}

void AMyCharacter::HandleFire()
{
  // Fire
}

void AMyCharacter::MoveForward(float Value)
{
  AddMovementInput(GetActorForwardVector(), Value);
}

void AMyCharacter::MoveRight(float Value)
{
  AddMovementInput(GetActorRightVector(), Value);
}

void AMyCharacter::TurnAtRate(float Rate)
{
  AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}

void AMyCharacter::LookUpAtRate(float Rate)
{
  AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}

Mesh instantiation

// First we need to fetch the mesh asset from the project content.
// Right-click on the asset (in the editor) and select "Copy Reference" to get the path.
static auto MeshPath = TEXT("StaticMesh'/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere'");
static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(MeshPath);

if (MeshAsset.Succeeded())
{
  Component = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));
  Component->SetStaticMesh(MeshAsset.Object);
  Component->SetWorldScale3D(FVector(2.f, 2.f, 2.f));
}
else
{
  // Handle the error
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment