惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 司徒正美
aimingoo的专栏
aimingoo的专栏
MongoDB | Blog
MongoDB | Blog
云风的 BLOG
云风的 BLOG
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 聂微东
Y
Y Combinator Blog
T
Tailwind CSS Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
S
SegmentFault 最新的问题
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 【当耐特】
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
J
Java Code Geeks
美团技术团队
Google DeepMind News
Google DeepMind News
博客园_首页
Apple Machine Learning Research
Apple Machine Learning Research
T
The Blog of Author Tim Ferriss

DEV Community

Apache Iceberg Metadata Tables: Querying the Internals Hermes, The Self-Improving Agent You Can Actually Run Yourself Building Agentic Commerce Infrastructure: Overcoming SQLite Concurrency for Autonomous Procurement Agents Solana Accounts vs Databases HTML Table Borders I built a skill that makes AI-generated AWS diagrams actually usable My first post! I'm kinda excited The Page Root Was the Wrong Unit How to audit what your IDE extension actually sends to the cloud I Migrated 23 Make.com Scenarios to n8n and Cut My Bill by 60% — Complete Migration Guide (2026) Solving a Logistics Problem Using Genetic Algorithms Claude Code Skills Explained: What They Are & When to Use Them (2026) Maintaining Apache Iceberg Tables: Compaction, Expiry, and Cleanup Zero-Idle Local LLMs: Running Llama 3 in AWS Lambda Containers We scanned 8 B2B SaaS companies across 5 categories. ChatGPT named the same 12 brands in every answer. How To "Market" Yourself As A Tech Pro We scanned 500 MCP servers on Smithery. Here is what we found. HTML Basics for Beginners – Markup Language, Elements and Types of CSS DiffWhisperer: How I Turned Cryptic Git Diffs into Architectural Stories with Gemma 4 I built a version manager for llama.cpp using nothing but vibe coding. Unit Testing vs System Testing: Key Differences, Use Cases, and Best Practices for 2026 A game design textbook explains why products with fewer features win How to Build a Raydium Launchpad Bonding Curve in 5 Minutes with forgekit How to turn an AI prototype into a production system How Data Lake Table Storage Degrades Over Time Partition and Sort Keys on DynamoDB: Modeling data for batch-and-stream convergence Auto-Generate Optimized GitHub Actions Workflows For Any Stack With This New CLI Tool Unchaining the African Creator Economy The Treasure Hunt Engine Gotcha - A Lesson in Constrained Performance great_cto v2.17 - no more tambourine dance When Catalogs Are Embedded in Storage SafeMind AI: Instant Health & Safety Intelligence What Is PKCE, How It Works & Flow Examples AI Agent Failure Modes Beyond Hallucination Fastest Way to Understand Stryker Solana Accounts Explained to a Web2 Developer TV Yayın Akışı Sitesi Geliştirirken Öğrendiğim Teknik Dersler $500 Challenge Drop My First Look at Google's Gemma 4: A Quick Introduction How I use an LLM as a translation judge Best Calendar and Scheduling API for Developers — 2026 Comparison Agentic AI in Travel: Why UCP Isn't Travel-Ready Yet — and What We Measured I Finished Machine Learning. And Then Changed The Plan. The Five-Thousand-Line File The AI Whirlwind: Why Your Local Agent Matters More Than Ever I Built an Oracle DBA That Lives in Telegram. It Cut a 500K-Row Scan to 5 - After Asking Permission. The Day 2 Reality of Running a Kubernetes Lab on Your Mac: Stop/Start, CKS Scenarios, and What I Learned Building It. n8n for Airtable Power Users: 5 Automations That Take Your Base to the Next Level Validating Gemma 4 for Industrial IoT: A Governance Pattern VS Code Now Credits Copilot on Every Commit by Default Astro and Islands Architecture: Why Your Portfolio Doesn't Need React for Everything Booting from FAT12: How I added file reading to my x86 kernel Unity’s AI agent went public: the developers of a static analysis tool on what that means for code quality Anna's Archive publica un llms.txt para los LLMs que rastrean su catálogo CRDTs for Offline-First Mobile Sync Why I Built Mneme HQ: Preventing AI Agent Architectural Drift Google Antigravity 2.0 Is the I/O 2026 Announcement You Should Actually Care About I Built a Pay-Per-Call Crypto Signal API with x402 — Heres the Architecture JWT Token Refresh Patterns in React 19: Avoiding the Silent Auth Death Spiral 🚀 “From Prompts to Autonomous Agents: What Google I/O 2026 Changed” The Power of Distributed Consensus in Autonomous SOCs Sixteen TUI components, copy-paste, no dependency The Boring Reliability Layer Every Autonomous Agent Needs Nven - Secret manager Building Multi-Tenant Row-Level Security in PostgreSQL: A Production Pattern The Hardest Part of Being a Developer Isn't Coding Building Vylo — Looking for Collaborators, Partners & Early Support I Thought Memory Fades With Time. It Actually Fades With Information. ORA-00064 오류 원인과 해결 방법 완벽 가이드 I registered an AI agent at 1 AM and something cracked open in my head Pitch: Nven - Sync secrets. Ship faster. Why y=mx+b is the heart of AI From Routines to a Crew — Building a System That Plans Its Own Work & executes it 25 React Interview Questions 2026 (With Answers) — Hooks, React 19, Concurrent Mode An open source LLM eval tool with two independent quality signals Using Dashboard Filtering to Get Customer Usage in Seconds from TBs of Data Skills, Java 17, And Theme Accents 4 Hard Lessons on Optimizing AI Coding Agents Arctype: Cross-Platform Database GUI for LLM Artifacts Your robots.txt says GPTBot is welcome. Your server says 403. Organizing How to Use AWS Glue Workflow 5 n8n Automations Every Digital Agency Should Be Running (Bill More, Work Less) Getting Started with TorchGeo — Remote Sensing with PyTorch Designing a Scalable Cross-Platform Appium Framework Google Antigravity 2.0 & Slash Commands Building a Unified Adaptive Learning Intelligence with Gemma 4, Flutter, and Multi-Model Orchestration Looking for beta testers for a £60 server management application The Disk-Pressure Incident That Taught Me to Always Set LimitRanges and Other Lessons from Mirroring EKS Locally. Why AI Should Not Write SQL Against ERP Databases Vibe coding works until it doesn't. The debt is real. Shipping at the Edge: Migrating a Coffee Subscription Platform to Cloudflare Workers Stop Tab-Switching: A Developer's Guide to Color Tools That Actually Fit the Workflow DevOps vs MLOps vs AIOps: What Changes, What Stays, and a Simple Roadmap to Get Started Run Powerful AI Coding Locally on a Normal Laptop 5 n8n Automations Every WooCommerce Store Needs (Save 10+ Hours/Week) What I Learned Building My Own AI Harness Hytale Servers Will Fail Treasure Hunts Until We Fix Our Event Handling Redux in React: Managing Global State Like a Pro Unfreezing Your GitHub Actions: Troubleshooting Stuck Deployments and Protecting Your Git Repo Statistics Unlocking Project Discoverability on GHES: A Key to Software Engineering Productivity
Unity vs Unreal: 5 Things I Had to Relearn the Hard Way
Game Dev Not · 2026-05-22 · via DEV Community

The first time I opened Unreal after years of living in Unity, I sat there for a full ten minutes trying to figure out where the play button was. Not because I couldn't see it. Because I didn't trust that pressing it would do what I expected. Every muscle memory I'd built up — drag a script onto a GameObject, hit play, see the thing wiggle — was suddenly worthless. The viewport looked similar enough to lull me into a false sense of familiarity, and then five seconds later I was fighting the editor over what "save" even means.

Going the other direction is just as bad. Unreal devs who jump into Unity often spend their first week asking why the engine keeps eating their references on hot reload, or why the Inspector won't show their perfectly reasonable struct.

I've shipped work in both engines at this point, and the honest truth is that the syntax barrier (C# vs C++) is the easy part. What actually slows you down is the dozens of small mental model mismatches that nobody warns you about until you've already lost a weekend to them. The engines look like they solve the same problems, so you assume the shape of the solution is the same. It isn't.

Here are five things our studio had to genuinely rewire our brains around. Not engine trivia — the stuff that quietly costs you days if you don't catch it early.

1. Garbage Collection Lives in Different Universes

Unity gives you C# and the .NET GC. Unreal gives you C++ and a custom mark-and-sweep GC that only knows about objects you've explicitly told it about. These sound similar. They are not.

In Unity, you write a class, you new it up, and the GC takes care of it whenever it feels like. The classic gotcha is performance (allocations in Update = GC spikes), but the correctness model is straightforward. Everything's an object, everything's tracked.

In Unreal, the GC only tracks UObject subclasses, and only through references it can see — meaning references marked with UPROPERTY(). If you store a UObject* as a raw pointer without that macro, the GC has no idea you care about it, and your pointer becomes a dangling reference the next sweep. The object literally gets collected out from under you.

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

    // Safe: GC knows you reference this
    UPROPERTY()
    UWeapon* EquippedWeapon;

    // Time bomb: GC will happily delete this
    UWeapon* SecretWeapon;
};

Enter fullscreen mode Exit fullscreen mode

The mental rewire: in Unity, the GC is a performance concern. In Unreal, the GC is a correctness concern. You don't fight it for frame time, you fight it for object lifetime. Once that clicked, half of my "why is my pointer null" bugs disappeared.

The flip side: Unity devs jumping to Unreal often reach for TWeakObjectPtr reflexively because they're scared of the GC. Most of the time you just want a UPROPERTY()-marked pointer — it keeps the object alive and tracked. Save TWeakObjectPtr for the case it's actually designed for: you want to reference something without preventing its destruction (a UI panel watching a target actor that might die first).

2. Tick Is Not Update (And Lifecycle Is Not Awake)

On paper, MonoBehaviour.Update() and AActor::Tick() look like the same idea. Per-frame callback, runs every frame, do your thing. In practice the lifecycle and scope rules around them are different enough that you can't just port habits across.

Unity's MonoBehaviour has a fairly chatty lifecycle (Awake, OnEnable, Start, Update, LateUpdate, OnDisable, OnDestroy) and most of those fire reliably in the editor too. You can lean on Start for cheap initialization and forget about it.

Unreal splits actor lifetime across PostInitializeComponents, BeginPlay, Tick, EndPlay, with components having their own OnRegister / InitializeComponent flow. BeginPlay only fires when the game actually starts, which catches a lot of Unity converts off guard the first time they try to do initialization in the constructor and wonder why nothing's wired up yet.

AEnemy::AEnemy() {
    // Constructor runs for the CDO at engine init, and again for every instance.
    // In both cases the world isn't valid — no gameplay state, no other actors.
    // Defaults only; gameplay setup goes in BeginPlay.
    PrimaryActorTick.bCanEverTick = true;
}

void AEnemy::BeginPlay() {
    Super::BeginPlay();
    // Now the world exists. Do gameplay setup here.
}

Enter fullscreen mode Exit fullscreen mode

And then there's the other direction, which bites just as hard. Unreal devs coming into Unity expect a staged lifecycle and instead get a flat one with a bunch of quietly-different rules. Awake runs early, sure, but it runs before the scene's other objects are guaranteed to be wired up — so anything that reaches across to a sibling MonoBehaviour belongs in Start, not Awake. Start itself doesn't fire when you Instantiate the object; it waits for the first frame the object is active. OnEnable and OnDisable fire every time you toggle the GameObject, not just at creation — which is great for pooling and a trap if you treated them as one-shot setup hooks. And the C++ instinct to "just put real init in the constructor" has to be unlearned outright: Unity reserves the right to construct MonoBehaviours for serialization purposes when no scene exists, so gameplay code in the constructor is at best ignored, at worst crashes the editor on domain reload. On top of all that, Update runs at a variable rate; physics-coupled logic belongs in FixedUpdate, and that distinction is one of those things you only learn after your character starts vibrating at high frame rates.

The rewire: in Unity, lifecycle is flat and most things fire on a single timeline. In Unreal, lifecycle is staged: constructor for defaults, BeginPlay for runtime, and Tick is opt-in (you have to enable it explicitly, which is honestly a feature, not a bug). Treat them as different shaped tools.

3. Reflection Is the Whole Engine

This is the one I underestimated the longest.

Unity uses [SerializeField], [Serializable], and [SerializeReference] to drive its inspector and YAML serializer. It feels lightweight — public fields serialize by default, private ones need a single attribute — but the rules quietly bite: polymorphic references need [SerializeReference], custom classes need [Serializable] to appear in the inspector at all, and IL2CPP will happily strip any type only reached via reflection unless you preserve it with a link.xml or [Preserve]. It's lower-ceremony than Unreal, but it's not free.

Unreal's UPROPERTY(), UFUNCTION(), and UCLASS() macros look like the same idea but they're load-bearing structural pillars. They feed the reflection system that powers serialization, the editor, Blueprint exposure, network replication, GC tracking (see #1), and the property system. A field without UPROPERTY is invisible to all of it. A function without UFUNCTION can't be called from Blueprint or RPCs. A class without UCLASS doesn't exist to the engine at all.

UCLASS(Blueprintable)
class AEnemy : public AActor {
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Combat")
    float Health = 100.f;

    UFUNCTION(BlueprintCallable, Category="Combat")
    void TakeHit(float Damage);
};

Enter fullscreen mode Exit fullscreen mode

Each meta specifier (EditAnywhere, BlueprintReadWrite, Category, Replicated, etc.) is a load-bearing instruction to a different subsystem. You'll find yourself reading the Unreal docs on property specifiers more than any other page.

The rewire: in Unity, attributes are sugar. In Unreal, macros are the API. When something doesn't show up in the editor, doesn't replicate, doesn't appear in Blueprint, or gets GC'd unexpectedly, 90% of the time it's because you forgot a specifier. Build the habit of writing the macro first, the field second.

4. Editor Extension Is a Different Sport

Both engines let you extend the editor. Both will let you build custom inspectors, tool windows, asset processors. But the shape of how you do it diverges so hard that your tooling knowledge basically doesn't carry over.

Unity editor scripting is mostly C# in an Editor/ folder, using UnityEditor APIs, EditorWindow, CustomEditor, and either IMGUI for quick stuff or UI Toolkit (UXML/USS) for anything you'd actually want to maintain. It's the same language as your gameplay code, which makes it cheap to start writing. Half our internal tools at the studio started as a 50-line EditorWindow someone wrote during lunch.

Unreal splits editor code into separate modules (you'll be editing .Build.cs files), and the UI is Slate, a declarative C++ DSL that looks like nothing else you've ever written. It's powerful, but the learning curve is real.

// Slate looks like this. Yes, really.
SNew(SVerticalBox)
+ SVerticalBox::Slot()
  .AutoHeight()
  [
      SNew(STextBlock)
      .Text(FText::FromString("Hello, tools"))
  ];

Enter fullscreen mode Exit fullscreen mode

You can avoid Slate for a while using Editor Utility Widgets (UMG in the editor) or Editor Utility Blueprints, which is honestly where I tell anyone starting out to live. Pure Slate is for when you need something that genuinely belongs in the editor chrome.

The rewire: in Unity, "I'll write a quick editor tool" is a fifteen-minute commitment. In Unreal, it's an afternoon if you go native, or fifteen minutes if you accept that Editor Utility Widgets are good enough for 80% of cases. Pick the right tier for the job. Don't try to write Slate for a button that just renames some assets.

5. The Asset Pipeline Has Opinions

The thing nobody tells you: your project structure isn't just organization. It's a contract with the build system.

Unity treats anything in Assets/ as fair game. You move things around freely, the .meta files keep references intact, AssetBundles are an opt-in deployment thing you set up when you need streaming or DLC. The pipeline is forgiving. Maybe too forgiving. Most Unity projects I've inherited had Assets/ folders that looked like a teenager's desktop.

Unreal's Content/ directory is a more structured place. Every asset is a .uasset with cooked variants, references are tracked by path, and moving things around outside the editor will absolutely break your references in ways that aren't always obvious until you try to package. The cook step at build time is a whole second pipeline you have to think about: what's referenced, what gets included, what gets stripped.

// Unity                  // Unreal
Assets/                   Content/
  Scripts/                  Blueprints/
  Prefabs/                  Maps/
  Scenes/                   Materials/
  Materials/                Characters/
  Resources/                ...
                          (Cooked output → Saved/Cooked/<Platform>/)

Enter fullscreen mode Exit fullscreen mode

Two specific traps worth flagging early:

  • Unity's Resources/ folder is convenient and almost always the wrong answer at scale. Anything in there ships in your build whether you reference it or not. For anything beyond a prototype, move to Addressables (or whichever streaming asset system your Unity version blesses — the recommendation has shifted more than once).
  • Unreal's hard-vs-soft references (UPROPERTY() of UObject* vs TSoftObjectPtr<>) determine what gets pulled into memory when. Get this wrong on a mid-size project and your initial map load time will quietly balloon.

The rewire: Unity's pipeline lets you defer thinking about deployment until late. Unreal's pipeline forces you to think about it early. Neither approach is wrong, but pretending you're in the other engine's model is how you ship a 4 GB build that should've been 800 MB.

Closing Thoughts

The pattern across all five of these: the engines look like they solve the same problems with slightly different syntax, and that's the trap. They actually have different philosophies about who owns what — the GC, the editor, the build, the lifecycle, the reflection system. Once you stop trying to translate Unity habits into Unreal (or vice versa) and start learning each engine's actual mental model, everything gets faster.

The other thing this taught me: every time I assumed two systems were "basically the same," I was about to lose a day. Now when I jump into something new, I make myself find the one thing that's structurally different from what I'm used to, before I touch any code. Saves a lot of grief.

If you've made the jump in either direction, I'd genuinely love to hear what tripped you up the worst. The five above are the ones that hit our studio hardest, but I'm sure there's a sixth waiting for the next person who switches engines. Probably something about input systems, knowing my luck.

This blog's where we plan to write down the small, unglamorous stuff we keep learning the hard way. No newsletter pitch — just more of these when we hit the next one.