Technical Design · Competitive 1v3 Asymmetric Game
Capybara vs. Granny
A competitive 1v3 asymmetric game where three capybaras coordinate to outplay Granny and survive until extraction.

The challenge
How can three capybaras coordinate to outplay Granny without making stacking a free advantage?
My contribution
- Stacking and team interaction design
- Destructible environment implementation decisions
- Ability design for the asymmetric teams
Overview
Project background
Capybara vs. Granny is a competitive 1v3 asymmetric game: one player controls Granny and tries to catch three capybaras before their extraction helicopter arrives. The capybara team uses coordinated abilities and stacking to evade and counter Granny. The concept combined the team's interest in local multiplayer across two monitors with capybaras forming wobbly stacks, leading to an asymmetric format inspired by Dead by Daylight.
Strength in collaboration
We encourage the players to trust their teammates and work with one another to gain an advantage. However, it is not through numbers they gain their strength, but through how they coordinate as a single unit.
Accessible and replayable
Players should be able to pick up a controller and compete within the first minute. Straightforward controls, clear objectives, and short rounds make it easy to learn the matchup and try a new approach in the next match.
Relieve tension through chaos
Chaos shouldn't always make the level more stressful. Instead, through physics simulation we want to allow the players to have fun and enjoy the squishy characters and arbitrary wall collapses.
MoreLess
Design deep dive
Stacking
I made stacking useful across different team lineups, with shared benefits and a clear cost for getting hit.
Design intent, rules & gameplay
Design Intent
Stacking is the clearest expression of Strength in Collaboration: it only creates an advantage when capybaras act together, and the risk scales with how much they commit to stacking, reinforcing that coordination, not raw numbers, is the multiplier. It also touches Relieve Tension Through Chaos, since taking a hit while stacked visibly and physically breaks formation rather than just draining a shared health bar.
Rules
- Any living, unstacked capybara may join by colliding into the stack, no role restriction
- Movement is driven by the combined directional input of all stacked members
- Damage per stacked member: 100% at 1 (unstacked), 90% at 2, 80% at 3, meaning total group damage taken is higher than a single capybara's
- Every hit ejects the top capybara from the stack automatically, regardless of stack size
- Each ability defines independent stacked/unstacked values (speed, range, duration) rather than sharing one universal modifier
Design decision 1Collaboration shouldn't require a "right lineup"
Problem
An early version locked stack position to role, dash on the bottom, shield in the middle, cast on top, with no exceptions. If the specific capybara needed to fill a slot wasn't present, the remaining players simply couldn't stack, punishing players for wanting to collaborate.
Decision
Any living, unstacked capybara can join a stack regardless of role, with one fixed rule: whichever capybara has the movement ability drives the stack's direction. This matters because a mechanic built around Strength in Collaboration shouldn't gatekeep collaboration behind team composition, removing the role requirement meant any group of players, regardless of who's present, could still stack and gain its benefits.
Implementation code
void OnCollisionEnter(Collision collision) {
if (collision.transform.root.TryGetComponent(out CapybaraController capybaraController)) {
if (!capybarasStack.Contains(capybaraController)
&& capybaraController.hp > 0f
&& GetComponent<CapybaraController>().hp > 0f) {
AddCapybara(capybaraControllerIteration
Playtesting surfaced players hitting the wrong lineup and simply being unable to stack, directly contradicting the pillar the mechanic was meant to serve. So, we iterated on the idea and ensured that the players do not have to stack on top of one another in a fixed order.
Outcome
Stacking now accommodates whatever combination of players is actually present, rather than gatekeeping collaboration behind a specific team composition, while movement control stays clear and predictable.
Design decision 2Getting hit while stacked should cost both health and formation
Problem
Stacking needed a real cost, not a free power multiplier. A flat "split the damage evenly" rule or "only top capybara takes the damage" felt too small a risk to pay considering all the buffs each capybara gets.
Decision
Each additional capybara takes a fraction of incoming damage (90% at two stacked, 80% at three), so the group takes more total damage than a single capybara would. Every hit also knocks the top capybara off the stack entirely, regardless of the mitigation. This makes stacking a genuine risk rather than a numbers play, and watching a capybara go flying off a stack is funny rather than punishing, serving Relieve Tension Through Chaos directly.
Implementation code
public void TakeDamage(float damage, bool splitDamageAmongStack = true) {
if (splitDamageAmongStack) {
if (capybarasStack.Count == 2) damage *= 0.9f;
else if (capybarasStack.Count == 3) damage *= 0.8f;
foreach (CapybaraController capybara in capybarasStack)
capybara.TakeDamage(damage);
}
...
RemoveCapybara(transform.forward + transform.up); // top member always ejected on hitGetting hit while stacked is genuinely costly in aggregate, but the ejection mechanic turns the moment into something chaotic and funny rather than purely punishing.
Design decision 3Stacking should bring meaningful "power-up"
If stacking only scaled numbers, it would feel like a stat buff rather than genuine empowerment through teamwork.
Stacking unlocks real behavioral changes per role. For example, a stacked dash breaks through walls, a stacked shield protects all capybaras on the stack, and a stacked spell freezes Granny outright instead of slowing her. All of these are additional behaviors on top of the expected numeric tuning per role. This gives each role a genuinely new capability while stacked, the strongest proof that Strength in Collaboration is a real mechanical philosophy.
Implementation code
public virtual void SetOnStack(bool onStack) {
currentCD = onStack ? stackedCD : regularCD;
}
// CapybaraDash: stacked dash gains wall-breaking capability, distinct from regular dash's speed-only change
// CapybaraShield: currentParryRange = onStack ? stackedParryRange : regularParryRange;
// CapybaraSpell: stacked cast applies a freeze effect on Granny instead of a slow, in addition to lifetime scalingOutcome
Stacking now unlocks genuinely different capabilities per role rather than just bigger numbers, making committing to a stack feel like real empowerment through coordination.
Destructible environment
I chose pre-sliced objects and controlled debris lifetimes to support destruction within the project scope.
Design intent, rules & gameplay
Design Intent
Destructible environments are the physical embodiment of "Relieve Tension Through Chaos": walls breaking apart should read as satisfying and funny rather than just a hazard, with debris scattering and chain-reacting like a real physics event rather than a scripted "wall disappears" trigger. It also touches "Strength in Collaboration", since destruction is deliberately gated behind stacking, a solo capybara's dash can't break walls, only a stacked one can, giving coordinated players a form of environmental power a lone capybara doesn't have.
Rules
- Only intact (kinematic) destructibles respond to a triggering collision
- A capybara's dash only triggers destruction if that capybara is stacked and is the movement-anchor member; a solo dash cannot break walls
- Granny's dash always triggers destruction
- Missiles pass through broken walls and continue toward their target; the capybara's own spell is destroyed on wall impact instead
- On trigger, all destructibles within a 4-unit radius are released and given an outward impulse force
- Broken destructibles remain physical for several seconds, then sink into the ground over 12 seconds before removal
Design decision 1Pre-sliced chunks over real-time fracturing or voxels
Problem
Convincing destruction has three real approaches, voxel-based destruction, real-time procedural fracturing, or pre-authored breakable chunks, and getting this choice wrong would be costly to unwind given a short development timeline.
Decision
The team prototyped both alternatives before settling on pre-sliced chunks. Real-time fracturing was ruled out first, the fracture calculations caused sudden freezes, and the computational cost wasn't justified for a competitive game where responsive play and readable action mattered more than physical realism. Voxel-based destruction was tried next, but individual voxels read as too small and granular, walls broke into fine debris rather than substantial chunks, undermining the idea that broken fragments should act as meaningful, chaotic obstacles a player has to navigate around, not just decorative dust.
Outcome
Pre-sliced chunks gave the team full authorial control over chunk size and shape, ensuring debris reads as substantial and obstructive rather than fine dust, while avoiding the freeze-inducing cost of real-time fracturing entirely, better serving both performance and Relieve Tension Through Chaos, since chaos needs to feel chunky and physical, not fine and computational.
Design decision 2Debris needs to linger long enough to matter, without piling up forever
Three constraints pulled against each other. Debris needed to stay tactically relevant for a while (a broken wall still affects pathing and line of sight), it needed to feel satisfying rather than vanishing cheaply the instant it broke, and it couldn't be allowed to accumulate indefinitely without hurting performance over a long session.
The team's first version simply left broken debris in the world permanently, which surfaced real performance problems as pieces piled up over a match. The fix was a staged lifecycle: debris stays fully visible and physical for a meaningful window (so it still matters tactically and reads as a real event, not a disappearing act), then sinks gradually into the ground rather than popping out of existence, giving it a graceful exit instead of an abrupt one, before finally being cleaned up.
Implementation code
IEnumerator DestroyWall(GameObject target)
{
yield return new WaitForSeconds(0.1f);
target.layer = LayerMask.NameToLayer("Destroyed");
yield return new WaitForSeconds(5f);
target.GetComponent<Collider>().enabled = false;
target.GetComponent<Rigidbody>().isKinematic = true;
// Slowly sink into the ground
float elapsed = 0f;
float duration = 12f;
Vector3 initialPosition = target.transform.position;
Vector3 targetPosition = initialPosition + Vector3.down * 12f;
while (elapsed < duration)
{
target.transform.position = Vector3.Lerp(
initialPosition,
targetPosition,
elapsed / duration
);
elapsed += Time.deltaTime;
yield return null;
}
Destroy(targetIteration
The original approach (never removing debris) worked fine early in a match but degraded performance as destruction accumulated, since hundreds of fragments would have accumulated already, each with their own NavMesh Obstacle and Colliders and Rigidbodies, which is what forced the staged cleanup design, both for performance and a cleaner scene.
Debris now stays around long enough to matter both tactically and tonally, contributing to Relieve Tension Through Chaos by giving destruction real physical presence, while the gradual sink-and-cleanup keeps the game performant over a full session rather than accumulating debris indefinitely.
Abilities
I designed each ability to counter Granny’s actions, giving coordinated teams distinct ways to outplay their opponent.
Design intent, rules & gameplay
Design Intent
Rules
- Dash: grants movement-based traversal/offense; gains wall-breaking capability specifically when the user is stacked (see Stacking Decision 3)
- Shield: opens a timed parry window; destroys Granny's missile on contact; knocks Granny back only if she is actively dashing when the parry connects, idle or non-dashing Granny is not affected by parry
- Spell: casts a projectile with crowd-control effect on Granny; applies a freeze effect instead of a slow specifically when the user is stacked
- Each ability defines independent stacked/unstacked values (speed, range, duration)
- Using any ability locks movement input for its duration until the ability completes
Design decision 1Abilities mirror Granny's kit
Problem
Three abilities as different as a dash, a defensive parry, and an offensive spell risk one becoming the obvious best pick, undermining any sense of real choice or team composition strategy.
Decision
Rather than balancing three unrelated abilities against each other in the abstract, each capybara ability was designed to answer a specific piece of Granny's own kit, movement counters movement, Shield counters Granny's missile and dash specifically, and Spell provides the capybaras' own crowd control to match Granny's. This gives each ability a clear, distinct job tied to what the opposing side can do, rather than needing to be independently "balanced" against sibling abilities in a vacuum.
Outcome
Each ability has an unambiguous purpose defined by what it answers on Granny's side, rather than competing directly with the other two capybara abilities for "best pick" status, supporting Strength in Collaboration by making different roles genuinely necessary rather than interchangeable.
Design decision 2Shields should only react to certain Granny actions
A parry-based Shield needed a clear, specific window it rewards, if it could counter Granny regardless of what she was doing, it would become a passive, always-safe answer rather than a skill-based read. But narrowing it too far risked making Shield feel situational to the point of uselessness.
Shield's parry already handles Granny's missile (destroying it on a successful block). Dashing was identified as the other genuinely punishable Granny action worth rewarding, it's a committed, telegraphed move, similar to how missiles are a committed, telegraphed threat. Anything outside those two (idle movement, other attacks) intentionally isn't parryable, keeping the ability's power tied to specific, readable moments rather than blanket protection.
Implementation code
if (root != null && root.CompareTag("Granny")) {
if (root.TryGetComponent(out GrannyController grannyController) && grannyController.GetIsDashing()) {
// apply knockback forceShield rewards players for reading and reacting to Granny's two most committed, telegraphed actions, keeping it a skill-based tool rather than a passive safety net, while still giving it enough opportunity to matter across a match.