Skip to content

Latest commit

 

History

History
191 lines (150 loc) · 5.39 KB

File metadata and controls

191 lines (150 loc) · 5.39 KB

When working with C++ in Unreal Engine 5, there are some unique aspects and nuances you should be aware of to make the most of the engine’s capabilities. Here’s a detailed look at some of the main nuances:

Unreal’s Class System and Macros

GENERATED_BODY() Macro: This macro is essential for enabling reflection, serialization, and other features. It should be used in all classes that need to be exposed to the Unreal Engine’s Reflection System.

UCLASS()
class MYPROJECT_API AMyActor : public AActor
{
    GENERATED_BODY()
public:
    AMyActor();
};

Macro Explanation: UCLASS(), UPROPERTY(), UFUNCTION(), and IMPLEMENT_PRIMARY_GAME_MODULE() are macros provided by Unreal to enable specific functionalities.

Using Unreal's UCLASS, UPROPERTY, and UFUNCTION Macros

  • UCLASS(): Declares a class that should be exposed to Unreal’s reflection system.

  • UPROPERTY(): Declares a variable that will be exposed to the editor and serialized. Use this macro for variables that need to be editable or saved.

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
    float Speed;
  • UFUNCTION(): Declares a function that can be called from Blueprints or exposed to the engine’s reflection system.

    UFUNCTION(BlueprintCallable, Category = "Gameplay")
    void MoveForward(float Value);

Actor Lifecycle Methods

  • Constructor: Use AActor::AActor() for initializing properties.
  • BeginPlay(): Called when the game starts or when the actor is spawned. Good for initializing logic.
    virtual void BeginPlay() override;
  • Tick(): Called every frame. Override this if you need to perform actions every frame.
    virtual void Tick(float DeltaTime) override;

Components and Hierarchy

Adding Components: Use CreateDefaultSubobject<UComponentType>(TEXT("ComponentName")) to add components to your actor.

UPROPERTY(VisibleAnywhere)
UStaticMeshComponent* MeshComponent;

Example:

MyActor::MyActor()
{
    PrimaryActorTick.bCanEverTick = true;
    
    MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));
    RootComponent = MeshComponent;
}

Blueprint-C++ Integration

Expose to Blueprint: Use UPROPERTY() and UFUNCTION() macros to expose C++ functionality to Blueprints. BlueprintCallable Function:

UFUNCTION(BlueprintCallable, Category = "MyCategory")
void MyFunction();

Memory Management and Pointers

Smart Pointers: Use TSharedPtr, TWeakPtr, and TUniquePtr for managing memory safely.

TSharedPtr<MyClass> MySharedPtr;

Garbage Collection: Unreal Engine uses a garbage collector for most objects. Make sure to use UPROPERTY() to handle garbage collection correctly.

Networking

Replicating Variables: Use UPROPERTY(Replicated) to mark variables that should be replicated across the network.

UPROPERTY(Replicated)
float Health;

Handling RPCs: Use UFUNCTION(Server, Reliable) and UFUNCTION(Client, Reliable) for server-client communication.

UFUNCTION(Server, Reliable, WithValidation)
void ServerUpdateHealth(float NewHealth);

Debugging and Logging

Logging: Use UE_LOG() for logging messages. This is helpful for debugging.

UE_LOG(LogTemp, Warning, TEXT("This is a warning message"));

Breakpoints and Debugging: Utilize Visual Studio’s debugging tools. Place breakpoints, watch variables, and step through code to identify issues.

Performance Optimization

Profiling Tools: Use the Unreal Insights and the Profiler in the Unreal Engine Editor to analyze and optimize performance. Best Practices: Optimize tick functions, use efficient data structures, and minimize unnecessary replication.

Common Pitfalls

  • Memory Leaks: Avoid raw pointers without proper memory management. Use smart pointers and ensure proper cleanup.
  • Unreal’s Tick and Update Logic: Be mindful of what code you place inside Tick(). Heavy computations in Tick() can degrade performance.
  • Blueprint vs. C++: Balance between using Blueprints and C++ to leverage the strengths of both.

Sample Code for a Simple Actor

Here’s a basic example of a custom actor with a component:

MyActor.h:

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"

UCLASS()
class MYPROJECT_API AMyActor : public AActor
{
    GENERATED_BODY()

public:
    AMyActor();

protected:
    virtual void BeginPlay() override;

public:
    virtual void Tick(float DeltaTime) override;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mesh")
    UStaticMeshComponent* MeshComponent;

    UFUNCTION(BlueprintCallable, Category = "Movement")
    void Move(float Value);
};

MyActor.cpp:

#include "MyActor.h"
#include "Components/StaticMeshComponent.h"

AMyActor::AMyActor()
{
    PrimaryActorTick.bCanEverTick = true;

    MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));
    RootComponent = MeshComponent;
}

void AMyActor::BeginPlay()
{
    Super::BeginPlay();
}

void AMyActor::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
}

void AMyActor::Move(float Value)
{
    FVector NewLocation = GetActorLocation() + FVector(Value, 0, 0);
    SetActorLocation(NewLocation);
}