A technical checklist for building your game right. The systems listed are required — how you design them is completely up to you.
The old way to read keyboard input looks like if (Input.GetKey(KeyCode.W)) Move(); — it works, but it's glued to your physical keyboard. When you add multiplayer, other players aren't pressing your keyboard. They send inputs over the network, and your code won't understand that at all.
The fix: Install Unity's Input System package and set up Input Actions. Your movement code reads from an action (moveAction.ReadValue<Vector2>()) instead of a key. That same code works for local players, network players, gamepads, and mobile — no changes needed.
if (Input.GetKey(KeyCode.W)) Move();var dir = moveAction.ReadValue<Vector2>();Imagine your wagon hits a river and the player loses food. The obvious way is to have your WagonController reach into SupplySystem and subtract food directly. Simple, right? The problem: now these two scripts are permanently glued together. You can't change one without risking breaking the other. And when you add multiplayer, you'd need to sync that connection over the network — painful.
The fix: Create an EventBus — a middleman all scripts can broadcast to and listen on. Instead of calling SupplySystem directly, your wagon fires an event: "food lost, amount: 10." SupplySystem listens for that event and handles it. They never touch each other.
Think of it like a group chat. Your wagon posts "lost 10 food." Anyone who cares reads it and reacts. Your wagon doesn't need to know who read it — and the listeners don't need to know who posted.
SupplySystem.instance.food -= 10. Now they're glued together forever.EventBus.Publish(new FoodLostEvent(10)). SupplySystem handles it independently.Your HUD shows the food count. It's tempting to store the food value in your HUD script since it's already there. Don't. The HUD should only read from SupplySystem and display what it finds — it should never change anything or keep its own copy of the number.
Why: If food is stored in two places (HUD and SupplySystem), they'll get out of sync. You'll hit bugs where the HUD shows 50 food but the actual value is 0. In multiplayer, you'd have to sync both separately and they'll contradict each other. One source of truth — the manager owns it, everyone else reads it.
Your settlers (party members) are data — names, health, status. They don't need to be GameObjects in a scene with MonoBehaviours attached. Making them plain C# classes means they're just objects in a list — easy to save to disk, easy to serialize, and when multiplayer comes, easy to sync over the network without any refactoring.
Think of it like: a party member is a row in a spreadsheet. You don't need to place a whole Unity scene object in the world just to hold a spreadsheet row.
Don't write your own camera follow script. Cinemachine is a free Unity package that handles follow cameras, spring lag, collision avoidance, smooth blending between shots — all out of the box. More importantly, it works correctly with multiplayer without you needing to touch anything. Writing your own camera logic now means rewriting it later.
Keep scripts organized by what they do. When you hit 50+ scripts (and you will), you'll need to find things fast.
You're not starting over. You already know how game systems should be structured from Unity. Unreal uses the same concepts, just with different names. Here's the full translation table:
Get Game Instance → Cast. This is where you put your supply system, party data, etc.