<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Niko</title>
    <description>The latest articles on DEV Community by Niko (@aggressivesinger3432).</description>
    <link>https://dev.to/aggressivesinger3432</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4046553%2Ff113efdf-bcf3-4a94-b940-3320d59226d2.png</url>
      <title>DEV Community: Niko</title>
      <link>https://dev.to/aggressivesinger3432</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aggressivesinger3432"/>
    <language>en</language>
    <item>
      <title>How Unreal Engine Works: Not an API, but Engineering Thinking</title>
      <dc:creator>Niko</dc:creator>
      <pubDate>Sat, 25 Jul 2026 11:01:53 +0000</pubDate>
      <link>https://dev.to/aggressivesinger3432/how-unreal-engine-works-not-an-api-but-engineering-thinking-ao4</link>
      <guid>https://dev.to/aggressivesinger3432/how-unreal-engine-works-not-an-api-but-engineering-thinking-ao4</guid>
      <description>&lt;h3&gt;
  
  
  Hi everyone,
&lt;/h3&gt;

&lt;p&gt;I've been working with Unreal Engine C++ for a while, and I kept running into the same frustration: most tutorials tell you &lt;em&gt;how&lt;/em&gt; to use a feature, but never &lt;em&gt;why&lt;/em&gt; the engine is designed that way.&lt;/p&gt;

&lt;p&gt;I wanted to understand the reasoning behind UObject, Reflection, Garbage Collection, and why Unreal is a Framework, not a Library — so I wrote this deep-dive article.&lt;/p&gt;




&lt;h1&gt;
  
  
  How Unreal Engine Works: Not an API, but Engineering Thinking
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;FOUNDATION · REFERENCE ARTICLE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This isn't an article about "how to write a game in Unreal." It's about why the engine is structured the way it is in the first place — and if you truly understand the reasoning below, you'll be able to predict the architecture of any engine system you haven't studied yet, instead of having to memorize it from scratch each time.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  01. What Is It?
&lt;/h2&gt;

&lt;p&gt;Unreal Engine is not one single thing, but a layered cake of several distinct engineering solutions, each addressing a separate problem: &lt;strong&gt;Engine&lt;/strong&gt; (the engine itself as a program and a ready-made infrastructure), &lt;strong&gt;Framework&lt;/strong&gt; (the execution model into which your code is embedded), &lt;strong&gt;UObject&lt;/strong&gt; (an object model shared between C++ and the editor), &lt;strong&gt;Reflection&lt;/strong&gt; (the engine's ability to "see" the layout of your classes at runtime), and &lt;strong&gt;Garbage Collector&lt;/strong&gt; (automatic lifetime management of objects).&lt;/p&gt;

&lt;p&gt;This article shows that all five are not a random set of features, but a single chain of causes and effects: each subsequent solution exists because the previous one creates a problem that needs to be solved. Going through this chain once, consciously, gives you not five facts to memorize, but one way of thinking applicable to any other engine system.&lt;/p&gt;




&lt;h2&gt;
  
  
  02. Why It Exists
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Problem: 1997, a Studio Making a Shooter
&lt;/h3&gt;

&lt;p&gt;Imagine a team sitting down in 1997 to build a 3D shooter. Just to get the game to launch and react to anything, they have to write from scratch: 3D graphics rendering on top of a specific manufacturer's video card, a loader for 3D models and textures from disk files, keyboard and mouse input handling, collision physics and gravity, a sound engine, multiplayer networking code with latency compensation, a level editor so designers can place objects with a mouse instead of lines of code, and a save/load system for game state.&lt;/p&gt;

&lt;p&gt;None of these eight things have anything to do with what makes the game this particular game and not any other — it's pure infrastructure, without which the game literally cannot run, but which in itself is not gameplay.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Exactly Is Wrong
&lt;/h3&gt;

&lt;p&gt;The team spends the overwhelming majority of its time reinventing the renderer, the asset loader, and the editor — i.e., things that do not differentiate one game from another — and only a small remainder on what players actually see and feel: weapon balance, level design, animation timing, the feel of shooting.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Cause: Infrastructure Does Not Transfer Between Projects by Itself
&lt;/h3&gt;

&lt;p&gt;The problem is not that writing infrastructure is hard (though it is) — the problem is that the knowledge of how to write it does not structurally transfer between projects. If a studio has no shared engine, the next game starts nearly from scratch: even if the same programmer who wrote the renderer for the first game writes the renderer for the second, they write it from scratch because there is no shared, reusable piece of code — only experience in one person's head, which is hard to pass to a team and impossible to quickly adapt for a new task.&lt;/p&gt;

&lt;h3&gt;
  
  
  The First Attempt at a Solution — Buying Separate, Independent Libraries
&lt;/h3&gt;

&lt;p&gt;The natural next step is not to write everything from scratch, but to take ready-made third-party solutions: a third-party renderer, a third-party physics engine like early PhysX, a third-party audio SDK — and write your own code that calls each library separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why This Doesn't Solve the Problem Completely
&lt;/h3&gt;

&lt;p&gt;Every such library is just a set of functions that you call. The library knows nothing about your game objects: it doesn't know what an "actor" is, that the player just entered the level or picked up an item. The glue between several independent libraries — the shared game object model, an editor that can work with all systems at once, a state saving system, synchronizing all this over the network — you have to write yourself once again, and this gluing turns out to be the hardest part of the work, not the easiest, because now you have to reconcile APIs that were not designed for each other.&lt;/p&gt;




&lt;h2&gt;
  
  
  03. What Problem It Solves
&lt;/h2&gt;

&lt;p&gt;Epic's answer to this problem is not a "more convenient library," but a change in the very model of the relationship between your code and the infrastructure. Instead of you calling a set of independent libraries and being the integration hub of the entire project, the engine itself becomes that hub: it owns the main program loop, owns the shared object model, owns the editor, owns the load/save system — and your code becomes a set of extension classes that the engine uses at predictable, predetermined points.&lt;/p&gt;

&lt;p&gt;This solves the original problem not by "writing infrastructure faster," but by not having to write the vast majority of it again at all: Epic wrote it once, and now it is reused in every project on the engine, so the team really spends its time on what differentiates its game from others.&lt;/p&gt;




&lt;h2&gt;
  
  
  04. What an Engine Is, and Why That Is Not Enough to Answer "What Is Unreal"
&lt;/h2&gt;

&lt;p&gt;The word "Engine" by itself describes only part of the picture: a collection of technical subsystems that together turn data (models, textures, sounds, code) into a working interactive simulation — renderer, physics, audio, networking, asset system.&lt;/p&gt;

&lt;p&gt;That alone is a huge engineering effort, but if Unreal were "only" a set of such subsystems exposed through an API, it would remain that very set of independent libraries from section 2, just written by one company instead of assembled from different sources. What turns a collection of technical subsystems into a cohesive system that a development team can work with productively is not about rendering or physics, but about who controls whom. That question is answered by the next concept — &lt;strong&gt;Framework&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  05. What a Framework Is — and Why Unreal Engine Is a Framework, Not a Library
&lt;/h2&gt;

&lt;p&gt;The difference between a library and a framework is not a difference in size or feature count. It is a difference in who holds the main program loop and decides when to call your code.&lt;/p&gt;

&lt;p&gt;If you write a program using a regular library (for example, a library for reading PNG files), the following happens: you have your own main() function, you write your own program loop, and at some point you, on your own initiative, call a library function — "read this file for me." Control is always with you: you decide when what gets called, in what order, and what to do with the result.&lt;/p&gt;

&lt;p&gt;If you write a class inside Unreal Engine, the exact opposite happens. You have no main() — the program entry point belongs to the engine and is not written by you. You write a derived class (for example, a descendant of AActor), implement certain functions in it with known names — BeginPlay, Tick, EndPlay — and the engine itself decides exactly when to call each of them. Your function is not an entry point, but a "hole" in someone else's ready-made lifecycle, which the engine calls at the right moment.&lt;/p&gt;

&lt;p&gt;This is called &lt;strong&gt;Inversion of Control (IoC)&lt;/strong&gt;: control no longer belongs to your code; it belongs to the framework, and your code is a set of extension points that the framework invokes on its own schedule.&lt;/p&gt;

&lt;h3&gt;
  
  
  Regular program with a library (control is yours):
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ProcessInput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You decide what and when gets called.&lt;/li&gt;
&lt;li&gt;The PNG library has no idea your loop exists, you call LoadPNG() yourself when you need it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Class inside Unreal Engine (control is with the framework):
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;ASA_Character&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BeginPlay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* your code */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;ASA_Character&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;DeltaTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* your code */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;main() belongs to the engine, you have none.&lt;/li&gt;
&lt;li&gt;The engine itself decides: &lt;strong&gt;WHEN&lt;/strong&gt; to call &lt;strong&gt;BeginPlay&lt;/strong&gt; (after the actor is fully placed in the world and all its components are initialized), how many times per second to call &lt;strong&gt;Tick&lt;/strong&gt;, and what to do &lt;strong&gt;AFTER&lt;/strong&gt; your code finishes — update the renderer, send replicated data over the network, process tasks deferred until the end of the frame.&lt;/li&gt;
&lt;li&gt;Your function is an extension point, not an entry point.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why This Is Fundamental, Not "Just a Different Code Style"
&lt;/h3&gt;

&lt;p&gt;Inversion of control is not an aesthetic choice by Epic, but the only way to make the shared code (the engine itself) reusable across projects that have different gameplay logic. If the engine did not own control, each project would have to solve anew in what order to initialize rendering, physics, networking, and your game logic — and any mistake in that order (for example, accessing a level that hasn't been loaded yet) would crash the game. By owning the entire loop, the engine guarantees the same correct initialization order for absolutely any project built on it — and your responsibility shrinks to filling in specific, already safe extension points.&lt;/p&gt;




&lt;h2&gt;
  
  
  06. Why Plain C++ Was Chosen as the Foundation — and Why It Alone Is Not Enough
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Limitation #1: Frame Budget
&lt;/h3&gt;

&lt;p&gt;A real-time game must recompute physics, AI, animation, rendering, and game logic within a single frame. At 60 frames per second, that is 16.6 milliseconds combined for everything listed. Languages with automatic memory management via a garbage collector that can unpredictably "pause" and scan the entire heap at any moment (the classic model of early Java, as well as most managed runtime implementations) introduce unpredictable pauses exactly when the collector feels like it. This is unacceptable when the frame budget is already at its limit: one such pause in the middle of a combat scene is a noticeable frame rate hitch (a so-called micro-stutter). C++ provides direct control over object lifetimes and memory layout, necessary to reliably meet that budget frame after frame.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limitation #2: Thousands of Interconnected Objects Managed Not Only by the Programmer
&lt;/h3&gt;

&lt;h3&gt;
  
  
  But Raw C++ with Manual Memory Management Is Not the Complete Solution Either
&lt;/h3&gt;

&lt;p&gt;Manual memory management in C++ (custom &lt;strong&gt;new&lt;/strong&gt; / &lt;strong&gt;delete&lt;/strong&gt; for each game object) in a project where thousands of actors hold pointers to each other — an actor holds a pointer to a target, a component holds a pointer to its owner, an AI holds a pointer to the last spotted enemy — is a direct source of constant use-after-free bugs if managed manually. The problem is compounded by the fact that in Unreal, objects are created and destroyed not only by your code, but also by the editor, the level loading system, and the networking code when a player disconnects — meaning you, as the author of a specific class, physically cannot trace all the places from which a pointer to your object might arrive.&lt;/p&gt;

&lt;p&gt;The conclusion from these two limitations simultaneously: we need a language with manual control over execution timing (meaning C++, not a managed language with an unpredictable GC), but we also need protection from use-after-free for objects referenced by many different, unrelated engine systems (meaning some form of automatic lifetime management, but only for this specific category of objects, not for all memory in the program).&lt;/p&gt;

&lt;p&gt;This limitation is the direct cause of everything described later in this article: Unreal does not choose between "fast but dangerous C++" and "safe but pausing managed language" — it builds a third option: performant C++ as the core, and a thin, predictable garbage collection overlay only for one specific category of objects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Historical Context That Explains a Lot
&lt;/h3&gt;

&lt;p&gt;Reflection and the Garbage Collector in Unreal are not inventions of the modern engine version. Early versions of the engine (Unreal, 1998, and subsequent Unreal Engine 2 and 3) used a separate language for gameplay logic — UnrealScript: interpreted, with built-in garbage collection and reflection from the start, while the low-level engine core (renderer, physics) was written in C++.&lt;/p&gt;

&lt;p&gt;Unreal Engine 4 (2014) removed UnrealScript as a separate language and moved its role onto "real" C++, augmented with code generation via the Unreal Header Tool — but preserved the same idea: game objects must be managed, reflected, and easy to write on the fly, even though the engine core stays low-level and without those overheads. In other words, Reflection and GC in modern Unreal C++ are not a new idea added on top of "ordinary" C++, but the transfer of an almost twenty-year-old, proven architecture onto a new, more performant implementation language.&lt;/p&gt;




&lt;h2&gt;
  
  
  07. Why UObject Emerged
&lt;/h2&gt;

&lt;p&gt;The limitation from the previous section defines the problem: we need a separate category of objects for which the engine takes on automatic lifetime management, integration with the editor, and serialization — but at the same time, the bulk of the engine's code (math, containers, low-level systems) remains ordinary, "bare" C++ without these overheads.&lt;/p&gt;

&lt;p&gt;Epic's answer is to introduce an explicit boundary: any class that needs these capabilities inherits from a common base class &lt;strong&gt;UObject&lt;/strong&gt;, and that very fact of inheritance is a signal to the rest of the engine infrastructure (garbage collector, editor, serialization system) that this particular object should be handled under special rules. Ordinary C++ classes that do not meet these requirements (for example, a simple math structure like a vector) remain outside this system — and do not pay for capabilities they don't need.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Key Takeaway of This Section
&lt;/h3&gt;

&lt;p&gt;UObject is not the "base class for everything in Unreal." It is a deliberately drawn boundary: on one side — objects managed by the engine infrastructure (lifecycle, GC, editor, networking, serialization), on the other — ordinary C++ without all that. The decision whether to inherit from UObject is an architectural decision with a real cost, not an automatic default for every new class.&lt;/p&gt;

&lt;p&gt;A detailed breakdown of UObject internals — constructors, Class Default Object, the difference between UObject and AActor — is separated into its own article, as the topic is substantial enough to deserve its own full treatment. Here it is important to lock down only one thing: UObject is an answer to a specific engineering constraint, not an arbitrary architectural decision.&lt;/p&gt;




&lt;h2&gt;
  
  
  08. Why Reflection Emerged
&lt;/h2&gt;

&lt;p&gt;The introduction of UObject as a boundary answers the question "which objects are special," but does not answer the next, equally important question: how does the engine infrastructure — the garbage collector, the editor, the save system — find out which specific fields exist in your particular UObject descendant class, if that infrastructure itself is written once, long before you write your class?&lt;/p&gt;

&lt;p&gt;Ordinary C++ erases nearly all information about the type's structure after compilation (this phenomenon is called type erasure) — in the compiled binary, there is no built-in, runtime-accessible list like "class ASwordActor has a field float BaseDamage at such-and-such offset in memory." The compiler knows this precisely at build time, but does not leave that knowledge available to the program at runtime.&lt;/p&gt;

&lt;p&gt;For writing game code, this is usually enough — you know the names of your own fields at code-writing time. But for writing a universal editor that must be able to display a Details panel for absolutely any class that any programmer will ever write on this engine, including classes written years after that editor version was released — this limitation is fatal. The editor physically cannot be written to "know" in advance about every future class of every future project.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution — Code Generation on Top of Your Class, Before the Main Compilation
&lt;/h3&gt;

&lt;p&gt;Epic solves this problem not by changing the C++ language, but with an additional build step before the main compilation: &lt;strong&gt;Unreal Header Tool (UHT)&lt;/strong&gt; — a separate program that scans your header &lt;strong&gt;.h&lt;/strong&gt; files, finds special macros (&lt;strong&gt;UCLASS&lt;/strong&gt;, &lt;strong&gt;UPROPERTY&lt;/strong&gt;, &lt;strong&gt;UFUNCTION&lt;/strong&gt;), and generates additional C++ code — a &lt;strong&gt;.generated.h&lt;/strong&gt; file — that registers your class's structure in the engine's runtime system: a list of fields, their types, their memory offsets, a list of functions.&lt;/p&gt;

&lt;p&gt;This generated code is &lt;strong&gt;Reflection&lt;/strong&gt; in Unreal — runtime-accessible information about the class structure, synthesized automatically from your source code before the ordinary C++ compiler even sees the file.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ordinary C++ project compilation:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;your .cpp/.h files  →  compiler (clang/MSVC)  →  binary
                       (class structure information
                        erased after compilation)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Unreal Engine project compilation:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;your .h file with UCLASS()/UPROPERTY()
        │
        ▼
Unreal Header Tool reads .h, SEES the macros,
generates MyClass.generated.h — code that
registers the class structure in UClass/FProperty
        │
        ▼
your .cpp/.h + .generated.h  →  compiler (clang/MSVC)  →  binary
                                (now the binary contains both your logic
                                 AND the runtime description of the class structure —
                                 the editor and GC can read it at runtime)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why Macros, Not Something Else
&lt;/h3&gt;

&lt;p&gt;Macros (&lt;strong&gt;UCLASS()&lt;/strong&gt;, &lt;strong&gt;UPROPERTY()&lt;/strong&gt;, &lt;strong&gt;GENERATED_BODY()&lt;/strong&gt;) are not a stylistic whim, but the only way available to Epic to mark the necessary classes and fields directly in an ordinary, valid C++ file so that: (a) a separate program (UHT) can find these marks with a simple text parse of the header before full compilation, and at the same time (b) the file itself remains compilable by a normal C++ compiler, which expands those macros into nothing or into service code during preprocessing.&lt;/p&gt;

&lt;p&gt;The alternative — a separate interface description file (IDL) — would force the developer to maintain two synchronized sources of truth (the C++ class and its IDL description) instead of one. Macros allow keeping the entire description in one place — right above the field or class to which it belongs.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Look Inside the Engine Source: What Really Happens to UPROPERTY() During Compilation
&lt;/h3&gt;

&lt;p&gt;In &lt;strong&gt;UObject/ObjectMacros.h&lt;/strong&gt;, the macros themselves are deceptively simple: &lt;strong&gt;UPROPERTY(...)&lt;/strong&gt; and &lt;strong&gt;UFUNCTION(...)&lt;/strong&gt; literally expand into nothing — &lt;strong&gt;#define UPROPERTY(...)&lt;/strong&gt; without a single symbol to the right. The engine developers' comment right above them says: &lt;em&gt;"These macros wrap metadata parsed by the Unreal Header Tool, and are otherwise ignored when code containing them is compiled by the C++ compiler."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UCLASS()&lt;/strong&gt; and &lt;strong&gt;GENERATED_BODY()&lt;/strong&gt; expand not into nothing, but into a token glued from the file name and line number, which at compile time substitutes in its place the code generated by UHT in &lt;strong&gt;.generated.h&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And a detail that often surprises those who studied the engine from old materials: UHT itself in current engine versions is no longer a C++ program, as it was in UE4, but a C# toolchain (in the source tree it lives as &lt;strong&gt;Engine/Source/Programs/Shared/EpicGames.UHT&lt;/strong&gt;, alongside Unreal Build Tool). This does not affect the model described above — "first UHT reads the macros, then the ordinary compiler builds the result" — only the implementation language of the tool itself changes.&lt;/p&gt;




&lt;h2&gt;
  
  
  09. Why the Garbage Collector Is Needed
&lt;/h2&gt;

&lt;p&gt;Reflection solves the problem "the engine knows your class structure at runtime" — but that very same knowledge turns out to be exactly the missing piece needed to solve the safe memory management problem formulated in section 6: if the Reflection system already can find all pointer fields to other UObjects inside your class (through UPROPERTY, which marks precisely such fields), then the engine can build a complete reference graph among all live UObject objects in the game — who points to whom — and periodically traverse this graph, starting from known "alive" root objects (the world, GameInstance, and similar), marking everything reachable as alive, and deleting everything unreachable.&lt;/p&gt;

&lt;p&gt;This is Unreal's Garbage Collector — a mechanism made possible precisely because of Reflection, not something that appeared independently of it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simplified GC traversal model (mark-and-sweep):
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Root objects (GameInstance, UWorld, objects with AddToRoot)
        │
        ▼ traversal via UPROPERTY references (known thanks to Reflection)
        │
   ┌────┴────┐
   ▼         ▼
Actor A   Actor B ──▶ Component X ──▶ InventoryItem Y
   │
   ▼
(if no one else references this — object is NOT marked as alive)

After traversal: everything that was NOT marked as reachable
is considered garbage and freed at the next GC pass.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why This Works Only for UPROPERTY References
&lt;/h3&gt;

&lt;p&gt;The GC can traverse only those references whose existence it knows about — and it knows only about fields registered by Reflection, i.e., fields marked with &lt;strong&gt;UPROPERTY&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;An ordinary "raw" C++ pointer to a UObject (&lt;strong&gt;AActor* CachedTarget;&lt;/strong&gt; without UPROPERTY) is invisible to the GC: it is not part of the traversal graph, and the object it points to can be deleted by the collector even if that "raw" pointer still exists somewhere in memory. You get a pointer that looks valid (not nullptr) but points to already freed memory — a classic use-after-free, only disguised as a normally working engine, because at first glance the code compiles and seems to work.&lt;/p&gt;

&lt;p&gt;This is the direct reason why in real projects any pointer field to a UObject almost always must be marked with UPROPERTY — not for visibility in the editor, but for the physical safety of memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Look Inside the Source: A UPROPERTY Field on a UObject Is No Longer Exactly a "Raw" Pointer
&lt;/h3&gt;

&lt;p&gt;Starting with UE5, when UHT sees &lt;strong&gt;UPROPERTY() AActor* Target;&lt;/strong&gt;, the generated code declares this field not as a bare &lt;strong&gt;AActor&lt;/strong&gt;&lt;em&gt;, but as **TObjectPtr&lt;/em&gt;* (&lt;strong&gt;UObject/ObjectPtr.h&lt;/strong&gt;) — a wrapper around an object "handle" (&lt;strong&gt;UObject/ObjectHandle.h&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;The Epic comment above &lt;strong&gt;TObjectPtr&lt;/strong&gt; directly explains why: &lt;em&gt;"is meant to function as a drop-in replacement for raw pointer member properties... supports access tracking and optional lazy load behavior in editor builds... When resolved, its participation in garbage collection is identical to a raw pointer."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For everyday code (&lt;strong&gt;Target-&amp;gt;DoSomething()&lt;/strong&gt;), this changes nothing — same size, same direct address access, same participation in GC traversal. But every access to the field becomes a point the engine can track, rather than an opaque address in memory — this is used by the GC barrier and (in editor builds) deferred loading of not-yet-loaded objects.&lt;/p&gt;

&lt;p&gt;It is important that this GC does not work like in managed languages such as C# or Java — it does not scan unpredictably at any moment, but runs on a controlled schedule (usually once every few seconds, the exact interval is configurable), and the traversal itself is designed to fit within the frame budget rather than stop the entire game. This is a direct consequence of constraint #1 from section 6 — predictability is more important than instant reaction to memory freeing.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. How It All Connects — a Single Chain of Causes
&lt;/h2&gt;

&lt;p&gt;Now that each element has been broken down individually, it is worth explicitly tracing the entire chain — because its integrity, not the individual facts, is the main lesson of this article.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; Rewriting the entire game infrastructure from scratch for each project is economically unviable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution 1 — Framework:&lt;/strong&gt; The engine takes control of the main loop (inversion of control); your code becomes a set of extension points.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constraint:&lt;/strong&gt; A real-time engine needs a predictable, fast language without managed runtime pauses — &lt;strong&gt;C++&lt;/strong&gt; is chosen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New problem from this choice:&lt;/strong&gt; Manual memory management in C++ for thousands of mutually referencing game objects managed not only by the programmer — a source of use-after-free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution 2 — UObject:&lt;/strong&gt; An explicitly designated category of objects for which the engine takes on automatic management and integration with infrastructure; the rest of C++ remains "ordinary" and without these overheads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New problem from this choice:&lt;/strong&gt; The universal editor and other infrastructure must "know" the structure of absolutely any future class — but C++ erases this information after compilation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution 3 — Reflection via UHT and macros:&lt;/strong&gt; A separate build step generates a runtime description of the class structure from the macro-annotated C++ source code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capability this unlocks:&lt;/strong&gt; Knowing the graph of UPROPERTY references between objects, the engine can automatically find unreachable objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution 4 — Garbage Collector:&lt;/strong&gt; Periodic, schedule-controlled traversal of this graph, freeing unreachable UObjects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why You Should Remember This as a Chain, Not a List of Facts
&lt;/h3&gt;

&lt;p&gt;If you memorize five facts separately — "Unreal is a framework," "there is UObject," "there is Reflection," "there is GC" — you will know the API. If you hold onto precisely the chain of dependencies — you will be able to take any new, unfamiliar engine system (Gameplay Ability System, Niagara, Enhanced Input) and ask the same question: &lt;em&gt;"what problem of the previous layer does this particular system solve, and what new constraint does it, in turn, create?"&lt;/em&gt; — and this will work even for systems that Epic adds to the engine after you finish reading this article.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. Impact on Blueprint
&lt;/h2&gt;

&lt;p&gt;Blueprint — Unreal's visual scripting language — is not a separate, independently built system on top of C++. It directly piggybacks on the Reflection infrastructure described above: when UHT generates a runtime description of your class from UPROPERTY/UFUNCTION, that exact same description is used by the Blueprint editor to show your C++ field as a configurable pin on a node or your C++ function as a callable node in the graph.&lt;/p&gt;

&lt;p&gt;Blueprint does not "know" about your class through any separate path — it sees exactly the same runtime structure description that the GC, the editor Details panel, and the serialization system see.&lt;/p&gt;

&lt;p&gt;This explains a practical consequence that would otherwise look like an arbitrary rule: if you want a designer to see your field or function in Blueprint, the only way is the same Reflection mechanism (&lt;strong&gt;UPROPERTY(BlueprintReadWrite)&lt;/strong&gt;, &lt;strong&gt;UFUNCTION(BlueprintCallable)&lt;/strong&gt;), not some separate "Blueprint API."&lt;/p&gt;




&lt;h2&gt;
  
  
  12. When to Think in These Categories — and When It Is Overkill
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Worth explicitly stating the "problem → constraint → solution" chain&lt;/th&gt;
&lt;th&gt;Not worth — the reasoning is excessive&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You are designing a new engine system/plugin and are unsure whether a class should be a UObject descendant or a plain C++ class&lt;/td&gt;
&lt;td&gt;You are using an already existing, established engine class (e.g., UStaticMeshComponent) for its direct purpose&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You see an unfamiliar macro or specifier and want to understand its architectural meaning, not just copy from a tutorial&lt;/td&gt;
&lt;td&gt;A task is fully solved by a standard, documented combination of existing systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You are explaining to a team newcomer why the project is done this way and not another&lt;/td&gt;
&lt;td&gt;Edits within a single function without architectural consequences&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  13. How Epic Itself Uses This
&lt;/h2&gt;

&lt;p&gt;A telling fact: even the Unreal Engine editor itself is not a separate program written outside this architecture, but the same kind of Unreal application, built on the very same framework as your game.&lt;/p&gt;

&lt;p&gt;Classes like &lt;strong&gt;UCharacterMovementComponent&lt;/strong&gt;, responsible for character movement, do not have their own separate "privileged" way to gain control each frame — they likewise override &lt;strong&gt;TickComponent&lt;/strong&gt;, the exact same extension point available to your own component.&lt;/p&gt;

&lt;p&gt;When you open the source code of this class and see the familiar &lt;strong&gt;TickComponent&lt;/strong&gt; signature, you are seeing not "engine magic," but the same mechanism you yourself use — just applied by Epic to a more complex task. This is a direct consequence of inversion of control: the engine has no backdoor, closed-off way to gain control that bypasses the system it itself provides to all developers.&lt;/p&gt;




&lt;h2&gt;
  
  
  14. Common Mistakes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Beginner Mistake: Looking for main() and Writing a Sequential Script
&lt;/h3&gt;

&lt;p&gt;A beginner coming from the world of regular programs instinctively looks for an "entry point" and tries to write a sequential script of the entire game in one place — "first load the menu, then wait for a button press, then start the level." This mistake arises because all previous programming experience is built around a single entry point, and Unreal physically does not give you one — the framework expects the game state to be expressed through classes and explicit transitions between them (GameMode/GameState change match state, UI reacts to events), not through a manually, imperatively written script.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mid-Level Developer Mistake: Thinking of UPROPERTY as "Just a Way to Show a Field in the Editor"
&lt;/h3&gt;

&lt;p&gt;A mid-level developer usually already knows to write UPROPERTY, but explains this necessity with an incorrect reason — "so the designer can see the field in the editor" — and therefore sometimes skips the macro for fields that "the designer doesn't need," including pointers to other UObjects. The danger lies precisely in this wrong mental model: the real reason is visibility to the Garbage Collector, and visibility in the editor is merely a side effect of the same Reflection mechanism. A skipped UPROPERTY on a pointer deemed "insignificant" by the developer is a direct path to a use-after-free that may not manifest for months.&lt;/p&gt;

&lt;h3&gt;
  
  
  How a Senior Thinks
&lt;/h3&gt;

&lt;p&gt;A senior developer does not ask "how do I make this work" — they ask "which extension point has the framework already provided for this, and why is it designed exactly that way and not otherwise."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task:&lt;/strong&gt; Add an inventory to the game.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A beginner thinks in object terms:&lt;/strong&gt; "I need an inventory — so I need a class UInventoryComponent with an array of items inside," then goes looking for a ready-made tutorial specifically for that task and copies the found solution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A senior does not look for an inventory tutorial&lt;/strong&gt; — they walk through the chain of already known causes:

&lt;ol&gt;
&lt;li&gt;The inventory data must survive the character's death, and the Pawn itself is destroyed on death — so the inventory physically cannot be stored inside it. &lt;strong&gt;PlayerState&lt;/strong&gt; exists exactly for this case — it is specifically designed to live longer than a particular character body.&lt;/li&gt;
&lt;li&gt;How to store the item list inside &lt;strong&gt;PlayerState&lt;/strong&gt;? &lt;strong&gt;TArray&lt;/strong&gt; is the typical choice where element order matters, unlike &lt;strong&gt;TMap&lt;/strong&gt;, which is optimized for key-based lookup.&lt;/li&gt;
&lt;li&gt;How should an item reference its unchanging characteristics (damage, weight, icon) separately from its mutable state (current quantity, durability)? Immutable item data is a job for a separate &lt;strong&gt;DataAsset&lt;/strong&gt;, while mutable state remains an ordinary field in the inventory slot struct.&lt;/li&gt;
&lt;li&gt;How should this list synchronize over the network without sending the entire inventory when only one single item changes? Replicate the minimum sufficient to reconstruct the state; for arrays, the engine has a separate, purpose-built mechanism for efficient replication.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  15. Practice
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Exercise 1 — Inversion of Control in Your Own Words
&lt;/h3&gt;

&lt;p&gt;Explain the difference between "calling a library function" and "being called by the framework," using the pair &lt;strong&gt;SpawnActor&lt;/strong&gt; / &lt;strong&gt;BeginPlay&lt;/strong&gt;: who calls whom in each of the two cases, and why are these different call directions?&lt;/p&gt;

&lt;h3&gt;
  
  
  Exercise 2 — Chain of Causes on a New Example
&lt;/h3&gt;

&lt;p&gt;Take a system this article did not mention — for example, &lt;strong&gt;Enhanced Input&lt;/strong&gt; or &lt;strong&gt;Gameplay Ability System&lt;/strong&gt;. Formulate a hypothesis: what problem of the previous, simpler approach does this system likely solve, and what new constraint does it, according to your hypothesis, introduce?&lt;/p&gt;




&lt;h2&gt;
  
  
  16. Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: If C# or Java already provide Reflection and GC "out of the box," why didn't Epic just write the engine in one of them?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Because Reflection and GC in managed languages are designed for the general case — they do not give control over WHEN exactly a GC pause occurs, and a real-time engine critically needs predictability in every single frame. Unreal solves this differently: takes a language (C++) that inherently imposes no GC, and adds its own, schedule-controlled collector only for one clearly delineated category of objects (UObject), leaving the entire rest of the low-level engine completely free of those overheads.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Q: Does every one of my classes have to inherit from UObject?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No, and this is a deliberate architectural decision, not an oversight. Simple data structures that do not need GC, the editor, or serialization (a mathematical vector, an auxiliary utility struct used only within one function) most often remain ordinary C++ classes/structs — they do not pay the Reflection/GC price because they don't need it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Q: Does inversion of control mean I can't control the execution order of my own code at all?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No — you fully control the execution order INSIDE your own functions (what happens inside your &lt;strong&gt;BeginPlay&lt;/strong&gt;, you decide yourself, line by line). You only do not control WHEN the framework will call those functions relative to other parts of the engine and your other classes — and for that, the framework has explicitly documented ordering guarantees.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Q: Does Reflection slow down ordinary code that simply reads or writes a UPROPERTY field?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No — accessing a field value like &lt;strong&gt;Health = 100.f;&lt;/strong&gt; in compiled code remains an ordinary, direct memory access operation by offset, exactly as fast as for any regular C++ field. Reflection overhead manifests not during normal read/write of a field from C++ code, but during operations that SPECIFICALLY use the runtime structure description (e.g. serialization, editor Details panel, Blueprint calls).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Q: Is it true that Blueprint will eventually completely replace C++ in Unreal?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No, and the architecture analyzed in this article explains why: Blueprint technically cannot exist without the C++ layer that it visualizes — the very Reflection information that the Blueprint editor sees is generated from C++ classes marked with UPROPERTY/UFUNCTION.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  17. What the Reader Should Start Noticing
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;After this article, an unfamiliar macro or specifier in someone else's code stops being a reason to simply copy it from a tutorial — instead, a reflex arises to ask which piece of engine infrastructure (GC, editor, Blueprint, serialization) it hooks into, and whether that cost is truly warranted.&lt;/li&gt;
&lt;li&gt;A pointer to a UObject without UPROPERTY in someone else's or your own code is now read not as a minor oversight, but as a potential use-after-free — because invisibility to the GC is a direct consequence of how reference graph traversal is built.&lt;/li&gt;
&lt;li&gt;And when encountering any new, yet-unstudied engine system (Niagara, Mass Entity, Chaos), the natural first question becomes not "how do I use this," but "what problem of the previous architectural layer does it solve, and what new constraint does it create."&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  18. Summary
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Unreal Engine is a framework, not a library:&lt;/strong&gt; It owns the main program loop, and your code is a set of extension points called by the engine at predetermined moments (inversion of control), rather than a set of functions you call yourself in the order you choose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inversion of control is not aesthetics, but the only way to make the same engine reusable across projects with different game logic:&lt;/strong&gt; The engine guarantees a single correct initialization order for any project, and your responsibility shrinks to filling in already safe extension points.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C++ was chosen as the implementation language because of the tight frame budget:&lt;/strong&gt; Managed languages with an unpredictable GC introduce pauses a real-time engine cannot afford — but raw C++ with manual &lt;strong&gt;new&lt;/strong&gt;/&lt;strong&gt;delete&lt;/strong&gt; also doesn't scale to thousands of mutually referencing objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UObject is not the "base class for everything," but a deliberately drawn boundary:&lt;/strong&gt; On one side — objects for which the engine infrastructure (GC, editor, serialization, networking) takes responsibility and overhead; on the other — ordinary C++ that does not pay that price.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reflection exists because the universal engine infrastructure needs to "know" the structure of absolutely any class:&lt;/strong&gt; Ordinary C++ erases that information after compilation — the Unreal Header Tool restores it in a separate build step, generating a runtime class description from UCLASS/UPROPERTY/UFUNCTION.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Garbage Collector became possible precisely thanks to Reflection:&lt;/strong&gt; By knowing through UPROPERTY which fields are references to other UObjects, the engine can build a reachability graph and free unreachable objects on a controlled, predictable schedule.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blueprint does not have its own, separate source of knowledge about your classes:&lt;/strong&gt; It reads exactly the same Reflection description that the GC and the editor Details panel use, so the only way to expose a field or function to a designer is the same UPROPERTY/UFUNCTION.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;These are not five isolated facts, but a single chain of causes and effects:&lt;/strong&gt; "What problem of the previous layer does this system solve, and what new constraint does it in turn create" — a question applicable to any yet-unstudied engine system.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  💡 Senior Thoughts
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;When you encounter an unfamiliar engine system, don't ask &lt;em&gt;"how do I use this"&lt;/em&gt; — ask &lt;em&gt;"what problem of the previous architectural layer does it solve, and what new problem does it create with this solution."&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;The Framework solved the infrastructure problem at the cost of inversion of control. UObject solved the use-after-free problem at the cost of a boundary between "expensive" and "cheap" parts of C++. Reflection solved the type erasure problem at the cost of macros and an extra build step. The GC solved the reference graph safety problem at the cost of periodic overhead. &lt;/p&gt;

&lt;p&gt;There is no magic in Unreal's architecture — only the yet-undiscovered price that the previous solution pays.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;More articles like this:&lt;/strong&gt; &lt;a href="https://uecppacademy.com" rel="noopener noreferrer"&gt;uecppacademy.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm already covering on UE C++ Academy
&lt;/h2&gt;

&lt;p&gt;I've built a complete engineering curriculum that explains not just &lt;em&gt;how&lt;/em&gt; to use Unreal Engine features, but &lt;em&gt;why&lt;/em&gt; they exist and &lt;em&gt;how&lt;/em&gt; they work under the hood. Here's what's already available:&lt;/p&gt;

&lt;h3&gt;
  
  
  Level 0 — How Unreal Thinks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Why Unreal is a Framework, not a Library&lt;/li&gt;
&lt;li&gt;When Epic's documentation is enough — and when it's time to open the engine source&lt;/li&gt;
&lt;li&gt;How to physically read .h and .cpp files in the engine codebase&lt;/li&gt;
&lt;li&gt;Why Public/Private/Classes is a compiler boundary, not a convention&lt;/li&gt;
&lt;li&gt;How to trace a dependency across modules in 5 minutes instead of an hour&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Level 1 — Object System
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;UObject architecture: the object managed by more than just your code&lt;/li&gt;
&lt;li&gt;Reflection: how the engine sees your code at runtime&lt;/li&gt;
&lt;li&gt;UPROPERTY, UFUNCTION, UINTERFACE — why macros, not magic&lt;/li&gt;
&lt;li&gt;Class Default Object (CDO) — why static constants aren't enough for defaults&lt;/li&gt;
&lt;li&gt;Garbage Collector: why Unreal decides when to delete your object&lt;/li&gt;
&lt;li&gt;FName / FString / FText — three string types, one reason&lt;/li&gt;
&lt;li&gt;Asset Registry: how the engine finds assets without loading them&lt;/li&gt;
&lt;li&gt;UObject in memory: byte-by-byte breakdown&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Level 2 — Runtime Objects
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Actor lifecycle: from SpawnActor to Destroy&lt;/li&gt;
&lt;li&gt;UActorComponent: why Unreal chose composition over inheritance&lt;/li&gt;
&lt;li&gt;Transform and RootComponent: why transformation is a tree, not three vectors&lt;/li&gt;
&lt;li&gt;Tick: why "every frame" is an engineering trade-off, not a free call&lt;/li&gt;
&lt;li&gt;TArray, TMap, TSet — why Unreal doesn't use std::vector&lt;/li&gt;
&lt;li&gt;TSharedPtr, TWeakObjectPtr, and GC — two independent worlds of memory management&lt;/li&gt;
&lt;li&gt;TSoftObjectPtr and asynchronous loading&lt;/li&gt;
&lt;li&gt;Collision architecture: Object Channel, Trace Channel, Response Matrix&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Level 3 — Gameplay Framework
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;UWorld: the level container&lt;/li&gt;
&lt;li&gt;Pawn, Controller, PlayerState — who controls what&lt;/li&gt;
&lt;li&gt;ACharacter vs APawn — when movement is state, not just relocation&lt;/li&gt;
&lt;li&gt;GameMode and GameState — why game rules exist only on the server&lt;/li&gt;
&lt;li&gt;Subsystems: why Unreal doesn't write global singletons by hand&lt;/li&gt;
&lt;li&gt;Delegates: why Unreal has several different kinds of callbacks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Level 4 — Data
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;UDataAsset: why weapon stats shouldn't live in code&lt;/li&gt;
&lt;li&gt;UDataTable: why hundreds of balance records shouldn't be hundreds of assets&lt;/li&gt;
&lt;li&gt;UAssetManager and TSoftObjectPtr&lt;/li&gt;
&lt;li&gt;FGameplayTag: why hierarchical strings are better than enums&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Level 5 — Systems (Input, UI, GAS, AI, World Streaming, Animation)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Enhanced Input: why the key is no longer hardcoded&lt;/li&gt;
&lt;li&gt;UMG, CommonUI, MVVM, Slate&lt;/li&gt;
&lt;li&gt;Gameplay Ability System: full deep-dive&lt;/li&gt;
&lt;li&gt;Behavior Tree, Blackboard, EQS, Perception, NavMesh&lt;/li&gt;
&lt;li&gt;Level Streaming, World Partition, PCG, Nanite, Lumen&lt;/li&gt;
&lt;li&gt;Animation: AnimInstance, Montages, IK, State Machine, Blend Spaces&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Level 6 — Multiplayer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Replication: Actor roles and Authority&lt;/li&gt;
&lt;li&gt;RPC: Server/Client/NetMulticast&lt;/li&gt;
&lt;li&gt;Property Replication from the inside&lt;/li&gt;
&lt;li&gt;Replication Graph, Fast Array Serializer&lt;/li&gt;
&lt;li&gt;Client-Side Prediction outside GAS&lt;/li&gt;
&lt;li&gt;Seamless Travel&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Level 7 — Engine Internals
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Compilation pipeline: from .cpp to .exe&lt;/li&gt;
&lt;li&gt;UnrealBuildTool, UnrealHeaderTool&lt;/li&gt;
&lt;li&gt;Modules and Plugins&lt;/li&gt;
&lt;li&gt;FArchive: serialization&lt;/li&gt;
&lt;li&gt;Cooker, Runtime Loading&lt;/li&gt;
&lt;li&gt;Threading: Game Thread, Task Graph&lt;/li&gt;
&lt;li&gt;FMalloc, FMemory, Alignment, Cache Lines&lt;/li&gt;
&lt;li&gt;TArray/TMap/TSet memory models&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Level 8 — Production
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;UE_LOG, Visual Logger, Gameplay Debugger&lt;/li&gt;
&lt;li&gt;Unreal Insights, stat commands&lt;/li&gt;
&lt;li&gt;Profiling as a way of thinking&lt;/li&gt;
&lt;li&gt;USaveGame: versioning and migration&lt;/li&gt;
&lt;li&gt;Architectural patterns: Composition, Subsystem, Observer, Factory, Command, Dependency Injection&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Level 9 — Afterword
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Full Game Lifecycle&lt;/li&gt;
&lt;li&gt;Complete Asset Loading Pipeline&lt;/li&gt;
&lt;li&gt;Complete Input Path to GAS&lt;/li&gt;
&lt;li&gt;Complete Frame Pipeline&lt;/li&gt;
&lt;li&gt;Complete Replication Flow&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Total: 150+ engineering articles&lt;/strong&gt; — all following the same standard: problem → constraint → solution → implementation → common mistakes → practice.&lt;/p&gt;




&lt;p&gt;This is a long-term engineering project, built from scratch. Every topic explains not "what to use," but "why it exists," "what problem it solves," "how it works internally," and "when not to do it."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://uecppacademy.com" rel="noopener noreferrer"&gt;uecppacademy.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  19. Question for the Community
&lt;/h3&gt;

&lt;p&gt;What Unreal system would you want to see explained with this same "problem → constraint → solution" approach?&lt;/p&gt;

&lt;p&gt;I'm deciding which topics to cover next.&lt;/p&gt;

&lt;p&gt;Feedback welcome — positive or negative.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>cpp</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
