Chapter 3 20 min

Scripting: Blueprint vs C#

From visual nodes to clean C# code

The Scripting Landscape

Unreal gives you two scripting options: Blueprints (visual) and C++ (code). Unity uses C# almost exclusively. Unity does have a visual scripting package, but the industry standard is writing C# scripts.

If you're coming from C++, C# will feel like a relief — no header files, no forward declarations, no manual memory management, and much friendlier compile times.

Script Lifecycle

Both engines have a well-defined lifecycle for scripts. The names differ, but the concepts map directly:

Lifecycle Methods

Unreal EngineUnityNote
ConstructorAwake()First initialization — get own components
BeginPlay()Start()Called after all objects are initialized
Tick(float DeltaTime)Update()Called every frame
TickPhysics / SubsteppingFixedUpdate()Fixed timestep for physics
(no direct equivalent)LateUpdate()After all Updates — great for cameras
EndPlay()OnDestroy()Cleanup when removed
OnEnable / OnDisable (via SetActorHiddenInGame)OnEnable() / OnDisable()Toggling active state

Basic Script Structure

cpp
// Unreal C++ Actor
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"

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

    UPROPERTY(EditAnywhere, Category = "Movement")
    float MoveSpeed = 5.0f;

public:
    AMyActor();
    virtual void BeginPlay() override;
    virtual void Tick(float DeltaTime) override;
};

Exposing Properties to the Editor

Both engines let you expose variables to the editor for designer tuning:

cpp
// Unreal: UPROPERTY macros
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
float Health = 100.0f;

UPROPERTY(VisibleAnywhere, Category = "Debug")
int32 KillCount;
In Unity, prefer [SerializeField] private over public fields. It keeps your API clean while still exposing values in the Inspector.

Events and Delegates

Unreal uses Delegates and Event Dispatchers. Unity uses C# events, Actions, and UnityEvents:

cpp
// Unreal: Declare and broadcast a delegate
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(
    FOnHealthChanged, float, NewHealth);

UPROPERTY(BlueprintAssignable)
FOnHealthChanged OnHealthChanged;

// Broadcasting
OnHealthChanged.Broadcast(CurrentHealth);

Timers and Coroutines

Unreal has FTimerHandle for delayed/repeating calls. Unity uses Coroutines — a powerful pattern for sequences, delays, and async-like operations:

Deep Dive: Coroutines vs UE Timers
cpp
// Unreal: Timer
FTimerHandle TimerHandle;

GetWorld()->GetTimerManager().SetTimer(
    TimerHandle, this,
    &AMyActor::DoSomething,
    2.0f,    // delay
    false);  // no looping

// Repeating timer
GetWorld()->GetTimerManager().SetTimer(
    TimerHandle, this,
    &AMyActor::Heartbeat,
    0.5f,    // interval
    true);   // loop
Coroutines can yield return different things: WaitForSeconds, WaitForEndOfFrame, WaitUntil(() => condition), or even other coroutines.

Finding Objects

Object Lookup

Unreal EngineUnityNote
GetComponentByClass<T>()GetComponent<T>()Get component on same object
GetOwner()->FindComponentByClass<T>()GetComponentInParent<T>()Search up the hierarchy
UGameplayStatics::GetAllActorsOfClass()FindObjectsOfType<T>()Find all instances (expensive)
Cast<AMyClass>(Actor)GetComponent<MyClass>()Type checking / casting
Tags (Actor Tags)Tags + CompareTag()Tag-based filtering