Main contributions
- Created a dynamic flocking system supporting 700+ agents at 60fps with Unity Job system and Burst Compiler
- Developed the enemy AI with behavior trees and Utility AI Theory so our predators react to player actions, patrol areas, chase player, search for them and even show frustration when player hides during a chase
- Created a robust decoupled code architecture for all the systems using observer, singleton and state patterns across the project
- Polished game feel through VFX, lighting, and animation tuning
- Support our audio team by taking the role of audio programmer, dealing with fmod in Unity
- Coordinated and analyzed insights from 20+ player playtests
Experience and Design goals
After multiple iterations (checkout the design process for more) I wanted to achieve specific goals:
- Make the player feel scared and alone in an unknown world. A feeling of “I shouldn’t be here” caused by the environment and the AI behaviors of predators and other creatures around.
- Embrace minimalist design by having just one core mechanic and using visuals to tell the player how to play and progress. The only text you see is the main menu and the pause menu.
- Deliver a strong sense of vulnerability and tension through game feel (vfx, sound and visuals) and pacing
This is an effort on minimalist design with inspirations from games like Alien Isolation and Amnesia.
Making the enemy AI
A system that mixed behavior trees with Utility AI theory alongside complex mechanics and behaviors themselves. The predator can see and hear the player, investigate sounds, search with sonar and even show frustration if they miss the player. Here a list of the most important developments:
1. Eyesight perception

In our Predator code we have an “eyesight check” that runs every couple of frames. In order to be performant, the eyesight check is done in three passes.
#1 Distance check:
We check if the distance from the Predator to the player is at least in the Follow radius. If the distance is greater, we dont continue.
#2 FOV check
Since we know positions, the predator transform.up and the fov we can do some vector math to get the dot threshold which should be Cos(fov/2). So the dot product between the normalized predator transform.up and the normalized dir from predator to player must be at least that value.
#3 Raycast check
We know is close and on the fov, now we do a raycast to check there are no obstacles in between.
2. Deciding actions with Utility AI
When the predator does not see or hear the player we use utility AI to decide to search for the player or following a patrol. I have a PredatorUtility script that takes care of calculating those scores for our behaviors.
(LastEncounterTime * Weight1) + (sonarTime * Weight2) + (closeness * Weight3)
- LastEncounterTime = how long hast it pass since the last encounter? A encounter is when a predator starts following or chasing the player.
- SonarTime = How long has passed since the last time a predator did a sonar?
- Closeness = how close is the predator. Based on the predator own sonar radius of effect
- We use custom weights per predator that they must sum 1
All this are normalized values that use AnimationCurves in Unity to like decide how we want them to move. If the utility is bigger than 0.75 (a manual threshold for now) then the predator does the sonar.

The Sonar Mechanic
In this video you can see the Sonar mechanic with Utility AI in action. After conditions are met and the score is reach the predator decides to do the mechanic that can find where the player is.
2. Following last player position when lost
Earlier iterations had the monster stopping when it couldn’t see the player anymore which is not very natural. Now, every time the monster sees the player (passes ell 3 checks) we are updating the last know player position. If the monster is doing an action (following or pursuing) but suddenly it can’t see the player, then it will continue to the last know player position.
3. Searching POI when lost player
Now, if the monster goes to the last known player position while on an action (following or pursuing) then it starts a “Search loop”. Basically, it takes the last known player position and gets all the Points of Interest (POI) around it and start going to those places. This gives a level a realism and force the player to still be aware of its surroundings
4. All in the behavior tree
Our behavior tree is the one that decides when to each of othe actions: pursuing, following, searching or the default of patrol.

Flocking System
In an effort to make the world feel more alive I created a flocking system with Unity Job system and Burst compiler. First, I started by actually reading a Craig Reynolds original Boids paper, learning about the principles of alignment, cohesion and separation. Afterwards I added my own twist to get specific behavior like following, orbit, hard and soft avoidance.
The FlockManager is responsible for creating and managing the agents, as well as establishing the behaviors that specific flock will have.
- FlockCore behavior that handles the base alignment, cohesion and separation code. Without this theres no flock really
- FlockGoal behavior handles if we want the flock to go somewhere specific like follow the player or patrol a route.
- FlockContainment that handles if we want to contain the flock in a specific area (a collider is used for this)
- FlockAvoid handles if the agents must avoid externals objects. A Hard void is that the agent will act like scary fish, if say the player gets near we make the agent go to the opposite direction with an extra acceleration. A soft avoid is the idea that the agent must “swim around” said object. This is still in progress as it is very costly.
The Design Process
Ideation: Visit to CSC
After experimenting with a few mechanic-based prototypes, my teammate and I visited the California Science Center for inspiration. Observing strange sea creatures turned out to be exactly what we needed. I became fascinated by organisms with reactive, tentacle-like filaments—they sparked the idea of capturing a living, surreal underwater ecosystem that is in constant movement by the use of procedural 2D animation.

Preproduction: experimenting with goals and constraints
First couple of weeks experimenting. I built movement-focused prototypes and experiments to convey character emotions without dialogue. A trip to the California Science Center and procedural animation prototypes inspired our alien underwater world setting, also leading to our key design constraint: no dialogue, minimal text.
Every single prototype tried to answer a design question:


Minimalist stealth gameplay
Aiming for accessibility and simplicity, I focused on movement and a single versatile mechanic, a “call” mechanic. Inspired by games like Super Meat Boy, our character remains unchanged, you get no power ups or anything like that, is the situations that change. Playtesting proved to very extremely important to get the movement just right so that players feel as a fast but fragile underwater creature.

Using the “Call” to communicate with your friend

Using “Call” to get the monster’s attention

Using “Call” to open gates