2.1 What each one is
- Blueprints are Unreal’s visual scripting language: node graphs you wire together. They compile to bytecode run by a VM. Think of them as a typed, visual, gameplay-focused scripting layer — like a domain-specific language that’s fast to iterate in and impossible to forget-to-recompile.
- C++ is the engine’s native language. Everything Blueprints can do, C++ can do, plus the things Blueprints can’t (low-level systems, performance-critical loops, new core types).
2.2 When to use which (the honest version)
Use Blueprints for: rapid prototyping, level scripting, UI logic, designer-tweakable behavior, anything you want to iterate on without a compile cycle, and one-off gameplay.
Use C++ for: core systems and base classes, performance-critical code (anything in a tight per-frame loop over many objects), complex math/algorithms, things you want under source control as text and diffable, and reusable framework you’ll subclass in Blueprint.
The standard professional pattern: write base classes and systems in C++, expose tunable values and events to Blueprint with UPROPERTY(EditAnywhere, BlueprintReadWrite) and UFUNCTION(BlueprintCallable), then subclass those C++ classes as Blueprints for the designer-facing layer. You get C++ performance + Blueprint iteration speed. You do not have to choose globally.
Performance note: a Blueprint VM node is far slower than native C++ per call. For 5 things per frame it’s irrelevant; for 50,000 it matters. Don’t prematurely rewrite working Blueprints in C++ — profile first (Part 9).
2.3 Reading a Blueprint graph
- Event nodes (red) — entry points:
Event BeginPlay,Event Tick, input events, custom events. - Execution pins (white triangles, the wire along the top) — control flow / order of execution. This is your call stack made visible.
- Data pins (colored, typed) — values flowing between nodes. Color = type (red=bool, green=float, blue=object reference, etc.).
- Variables & Functions (left panel) — your member fields and methods.
- Right-click the graph to search the entire node palette. Drag off a pin to get only context-valid nodes.
2.4 A first taste of C++ (a custom Actor)
Add C++ to a project via Tools → New C++ Class. Pick a parent (e.g. Actor). Unreal generates a header/source pair and regenerates the project files. A minimal Actor:
// Pickup.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Pickup.generated.h" // MUST be the last include
UCLASS()
class MYGAME_API APickup : public AActor
{
GENERATED_BODY()
public:
APickup();
// EditAnywhere -> tweak per-instance in the editor.
// BlueprintReadWrite -> readable/writable from Blueprint.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pickup")
int32 ScoreValue = 10;
UPROPERTY(VisibleAnywhere)
TObjectPtr<class UStaticMeshComponent> Mesh; // GC-tracked member pointer
protected:
virtual void BeginPlay() override;
UFUNCTION() // required so the reflection system can bind this to an event
void OnOverlap(UPrimitiveComponent* Overlapped, AActor* Other,
UPrimitiveComponent* OtherComp, int32 BodyIndex,
bool bFromSweep, const FHitResult& Sweep);
};
// Pickup.cpp
#include "Pickup.h"
#include "Components/StaticMeshComponent.h"
APickup::APickup()
{
PrimaryActorTick.bCanEverTick = false; // no per-frame cost we don't need
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
RootComponent = Mesh;
}
void APickup::BeginPlay()
{
Super::BeginPlay();
Mesh->OnComponentBeginOverlap.AddDynamic(this, &APickup::OnOverlap);
}
void APickup::OnOverlap(UPrimitiveComponent*, AActor* Other, UPrimitiveComponent*,
int32, bool, const FHitResult&)
{
// award score to Other, then:
Destroy();
}
Things to notice as a developer:
- The macros (
UCLASS,UPROPERTY,UFUNCTION,GENERATED_BODY) feed the Unreal Header Tool, which code-generates the reflection/serialization glue at build time. The.generated.hinclude is mandatory and must be last. MYGAME_APIis the module export macro (DLL boundary). Auto-generated per module.Super::is how you call the parent implementation — every override should usually call it.- You build by compiling in your IDE or using Live Coding (
Ctrl+Alt+F11in the editor) to hot-reload C++ without restarting. Live Coding is great for function bodies; structural changes (new UPROPERTYs) want a full rebuild.
In the Third Person template, open BP_ThirdPersonCharacter. Add a float variable Health = 100. On Event BeginPlay, print it with a Print String node. Then (optional) create a C++ Actor subclass, add an EditAnywhere float, compile, drag it into the level, and confirm the property shows in the Details panel. You’ve now touched both worlds and seen them interoperate.