// dev plan v2

Oregon Trail
Game Roadmap

A technical checklist for building your game right. The systems listed are required — how you design them is completely up to you.

OVERALL PROGRESS Loading…
Connecting to Firebase…
Unity — how to build it right
New to all this? These aren't rules you need to memorize right now. They're habits that prevent you from having to rewrite your whole game later when you add multiplayer. Read through once, then come back when something breaks.
RULE 1Use the new Input System — not Input.GetKey()

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();
Breaks completely in multiplayer.
var dir = moveAction.ReadValue<Vector2>();
Works for local, remote, gamepad, everything.
RULE 2Systems don't talk to each other directly — use an EventBus

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.

WagonController directly calls SupplySystem.instance.food -= 10. Now they're glued together forever.
WagonController fires EventBus.Publish(new FoodLostEvent(10)). SupplySystem handles it independently.
RULE 3One place owns the data. The UI just reads and displays it.

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.

RULE 4Party members = plain C# classes, not GameObjects

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.

RULE 5Use Cinemachine for cameras

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.

STRUCTUREHow to organize your project folders

Keep scripts organized by what they do. When you hit 50+ scripts (and you will), you'll need to find things fast.

Assets/
_Scripts/
Core/ ← GameManager, EventBus, SceneLoader
Player/ ← PlayerController, PlayerInput
Wagon/ ← WagonController, WagonHealth
Systems/ ← SupplySystem, PartySystem, WeatherSystem
Events/ ← RandomEventSystem, EventData (SO)
UI/ ← HUDController, EventUIPanel, MenuManager
Multiplayer/ ← leave empty for now
_ScriptableObjects/   _Prefabs/   _Scenes/
Unreal Engine — after you ship v1
When to start this: After your Unity v1.0 is live on itch.io. By then you'll know exactly what your game is — and you rebuild it in Unreal with Nanite terrain, Lumen lighting, and Chaos physics to make it look incredible.
TRANSLATIONEverything from Unity has an Unreal equivalent — just different names

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:

GameManager (Unity)Game Instance (UE)
Set your Blueprint Game Instance in Project Settings. It persists across level loads and is accessible from anywhere with Get Game Instance → Cast. This is where you put your supply system, party data, etc.
ScriptableObjectData Asset
A Blueprint class that inherits from Data Asset. Define your fields, then create instances in the content browser. Same workflow as ScriptableObjects — just different buttons.
EventBusEvent Dispatcher
Same pattern — broadcast instead of calling directly. Event Dispatchers are defined on the sending Blueprint. Other Blueprints bind to them on BeginPlay. Same idea, different syntax.
CinemachineSpring Arm + Camera
A Spring Arm component handles camera lag and collision automatically. Attach a camera to the end and it just works. Sequencer handles cutscenes. Both are Blueprint-native, no plugins needed.
NGO MultiplayerBlueprint Replication
No external library needed. Just tick "Replicated" on your Blueprint variables and use Server/Client event types. Unreal's networking is built in and handles the rest.
TRAPSCommon Unreal mistakes to avoid
Don't use baked lightingYou're using Lumen — it's fully dynamic and real-time. Baking lighting disables Lumen entirely and makes every small change take 20+ minutes to rebuild. Never bake.
Don't store changing values in Data AssetsData Assets are read-only config (like a settings file). Values that change during gameplay — like the current food count — live in the Game Instance, not in a Data Asset.
Don't use Get Player Controller for game logicIn multiplayer, Player Controller behaves differently on servers vs clients and will give you wrong data. Use Game State and Game Instance for anything all players need to agree on.
Blueprint is completely fine — you don't need C++Blueprint handles 100% of what this game needs. Unreal's C++ exists for performance-critical engine-level stuff, not gameplay. Use the same principles as Unity: managers own state, components own behavior, dispatchers handle communication.