Games · Unity · Survival prototype

Low poly survival

A Unity prototype focused on core survival mechanics — harvesting, interaction, and a static-to-dynamic pipeline — inside a deliberately simple low-poly world. I built it to learn scalable gameplay systems, not to win a graphics contest.

  • EngineUnity
  • RoleSolo developer
  • FocusHarvesting, static/dynamic, feel
  • StatusPrototype / learning

01 · Intent

Project overview

I built this low poly survival project as a foundational prototype: the kind of game where I care more about systems that work than about realism or shader showcases. I took inspiration from the core loops you see in games like Rust, ARK, and The Forest — gather, collect, expand — but I kept the environment deliberately simple so I could iterate on code without fighting art scope.

My goal was never to ship a finished title in one go. It was to implement functional, scalable gameplay systems, keep a clean interaction loop, and learn how to structure work so it can grow into a fuller survival experience later. I intentionally avoided piling on complexity before the basics felt solid: build systems that work, then refine and expand them.

That mindset pushed me toward modular scripting, reusable components, and performance-friendly design — especially important when the world is full of repeated meshes and props.

If you have played survival games, you already know the fantasy this is chasing: gather → collect → expand. I kept that loop explicit in design so every technical decision — colliders, animation strategy, when to go dynamic — could be judged against whether it made the loop clearer or only heavier.

02 · World

World design & object philosophy

The world is built from low poly assets — trees, bushes, stones — mostly static meshes placed and repeated for performance. I leaned on optimisation habits like static batching, mesh combining where it made sense, and lightweight colliders so the scene could carry plenty of objects without falling over.

That approach created a real design problem: static objects are not interactive by default. Combined meshes do not animate per-instance the way I needed for harvesting feedback. Instead of giving up on batching entirely, I ended up building the dynamic harvestable system described later — the technical heart of the project.

The world still needs to feel populated: repeated trees and rocks are part of the aesthetic and the performance story. The trick is not to pretend every instance is unique at rest, but to know exactly when an instance must wake up and behave like its own interactive object.

03 · Terrain

Procedural terrain

I did not only place assets on a flat plane — I also built the terrain using a custom procedural generation tool I developed for this project. It gave me repeatable landscapes to play in and iterate on without hand-sculpting every hill, which kept the focus on gameplay while still giving the world a sense of place.

Procedural terrain also keeps iteration cheap: when I change harvesting ranges or spawn logic, I can regenerate or adjust the play space without manually rebuilding meshes for every test pass — another place where tooling supports gameplay instead of fighting it.

04 · Core loop

Harvestable system — LpsHarvestables.cs

Harvesting is the core gameplay loop. I wanted the player to interact with the environment, see a reaction, and collect resources without every prop being a heavyweight GameObject running logic every frame. The main controller lives in LpsHarvestables.cs, which manages several harvestable types under one umbrella: trees, bushes, and small stones. Each type behaves differently, but the architecture stays unified so I can extend it instead of copy-pasting.

The design rule I kept returning to: keep objects lightweight until interaction is actually needed. That is how the project stays responsive even with a busy low-poly scene.

05 · Trees

Tree harvesting

Trees are the most complex harvestable. The player can left-click to punch a tree; it shakes on impact, and after enough hits it enters a falling state. I used a CapsuleCollider placed on the trunk only so hits register where they should — not on invisible leaf volume — and so interaction zones stay predictable.

I avoided heavy physics for the prototype. Instead of wrestling with rigidbody edge cases, I used transform-based shaking and controlled rotation for the fall. That keeps performance stable, removes a class of unpredictable physics bugs, and still reads clearly to the player. Feedback is both immediate (shake on hit) and progressive (multiple hits before the fall), so actions feel like they matter.

06 · Quick pickups

Bushes & small stones

Bushes are built as fast pickup resources: press F to collect, a small shake, then the bush disappears. They are deliberately low commitment — early-game nodes that reward exploration without the longer cadence of trees.

Small stones use a similar F-key pickup with a subtle jiggle before they vanish. They act as ground clutter and easy resources: enough to make the world feel alive and interactive without bolting on heavy systems for every rock.

07 · Systems

Dynamic vs static — LpsMakeDynamic & LpsKeepSeparate

This is one of the most important technical pieces I shipped. Static batching and mesh combining are great for performance, but they fight you the moment you need per-object animation or clean interaction on a single instance. Combined meshes do not behave like independent actors.

I built a pipeline that converts objects when the player actually engages. The key pieces are LpsMakeDynamic and LpsKeepSeparate. When interaction starts, I strip static flags and make the object properly dynamic, manage mesh visibility so the combined representation can step aside while the original renderer handles the response, and only then run the shake, jiggle, or fall logic. That way I keep batching benefits for the world at rest and still get fully interactive props on demand — the same class of problem real games solve for destructibles and harvestables.

Without this split, I would have been forced to choose between a fast static world and a responsive harvest loop. The pipeline is my way of refusing that false choice — keep the world cheap until the player proves they care about this particular object.

08 · Input

Player interaction

Interaction is intentionally simple: left click for punching trees, F for bushes and stones. Under the hood the flow is raycast-based — what am I looking at, what component or tag identifies it, which harvestable path runs — so the behaviour stays easy to extend when I add new resource types later.

I wanted the logic to stay readable: detect object, classify type, dispatch the right handler. That keeps the door open for metal ore, oil-style nodes, or special plants without rewriting the whole stack.

09 · Architecture

Modular design

I deliberately avoided hardcoding one-off behaviours everywhere. The payoff is consistent interaction logic, less duplication, and a structure where adding a new harvestable type is mostly configuration and behaviour tweaks, not a new spaghetti script for every asset.

10 · Feel

Visual feedback & game feel

Low poly does not mean low feedback. I spent time on shakes, micro-motions, and immediate response to input — because game feel beats raw fidelity for a prototype. Even simple animations sell the fantasy: the world reacts when you touch it.

11 · Performance

Optimisation choices

Most objects stay static until the dynamic conversion path runs. Animations stay lightweight — no unnecessary rigidbodies, no physics simulation I did not need. Shared systems and careful collider use help the scene stay scalable as I add content.

12 · Iteration

Problems I actually solved

I hit real issues: static meshes that refused to animate the way I wanted, combined meshes obscuring interaction, collider quirks, and raycast reliability. I treated those as design problems, not something to paper over with one-frame hacks — which is how the static-to-dynamic pipeline became central instead of optional.

13 · Roadmap

What exists today & what is next

In place today: harvesting for trees, bushes, and stones; the dynamic object pipeline; interaction and input; feedback loops that read clearly in play.

Not built yet: inventory, storage, crafting, full UI, audio, progression systems — the usual next layers once the core loop is worth investing in. The foundation is deliberately aimed at expansion: more resource types, grid inventory, crafting, biomes, points of interest — all map onto the same modular idea.

14 · Lessons

What I learned

  • Static vs dynamic is a balance — batch for speed, convert when gameplay demands it.
  • Interaction design wins when feedback is immediate and readable.
  • Modular systems pay off the moment you add a second or third resource type.
  • Scope discipline — core mechanics first, expansion once the loop is fun.

15 · Honest take

What this project actually is

This is not just a scene with assets dropped in. It is a foundation: a harvesting loop, a performance-aware approach to static worlds, and a modular architecture I can grow. I am not claiming a shipped indie game — I am claiming I solved real interaction problems in a way that scales, and that is the bar I set for myself here.

16 · Parallel

How this sits next to my other work

The same habits show up in my web projects: modular components, honest performance trade-offs, and systems that do not collapse when content grows. For another games write-up, see the Unreal Engine 5 survival prototype; for client-facing structure and SEO, see Paul Petruzzi or SEO & content architecture. For freelance web work, get in touch.

17 · Stack

Tech stack

What this Unity prototype actually exercises in practice.

Technologies & practice areas

  • Unity
  • C# gameplay scripts
  • Low-poly environment art
  • Harvest & interaction systems

Also involved

  • Static batching & mesh combining
  • Raycast-based interaction
  • Transform-based animation
  • Custom procedural terrain tool