feat/teaser-prototype-playable-core (#1)

Co-authored-by: John Lamb <j.lamb13@gmail.com>
Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
2026-02-05 02:30:45 +00:00
parent b1b3e4d0b3
commit 0de174eb1a
21 changed files with 1780 additions and 14 deletions

View File

@@ -0,0 +1,67 @@
---
date: 2026-02-01
topic: teaser-prototype
---
# Teaser Prototype: Playable Game Core
## What We're Building
A minimal playable teaser that captures the "practiced chaos" of Neighborhood Quarterback - the Rocket League-style feeling where chaos has patterns you can learn to exploit.
**Scope:**
- 1v1 vs AI opponent
- 5 identical units per side
- Draw-routes for commanding units
- Tag-out respawn (captured units respawn at base after delay)
- Simple fog of war (see near your units only)
- Backyard-style asymmetric map with houses/fences
- First to 3 points (points for flag grab AND returning flag to base)
## Why This Approach
We chose **Minimal Playable Core** over polished slice or systems-first approaches because:
1. **Validate the feel first** - The soul doc's "practiced chaos" needs playtesting to verify
2. **Fast iteration** - Rough edges are fine if we can quickly change what matters
3. **Avoid over-engineering** - Don't build robust systems for unvalidated design
## Key Decisions
- **AI opponent over multiplayer**: Simpler to build, can playtest alone, control pacing
- **Draw routes over click-to-move**: More tactical, matches the "quarterback" command fantasy
- **Tag-out over jail escort**: Simpler first pass; jail escort adds complexity we can add later
- **Fog of war included**: Core to the mind game, worth the complexity
- **5 units (not 3)**: Matches soul doc, enables interesting squad tactics
- **All identical units**: No classes yet; focus on positioning/routes before differentiation
- **Asymmetric map**: Thematic "backyard" feel even if harder to balance
- **First to 3 with grab+return points**: Creates multiple scoring opportunities per round
## What Success Looks Like
When playing, you should see:
- Moments where you read the AI's pattern and exploit it
- Chaotic scrambles when plans collide
- "Almost had it" flag runs that feel learnable
- Fog reveal moments that create tension
## Out of Scope (For Now)
- Class differentiation (Sneak/Patrol/Speed)
- Jail escort mechanics
- Motion lights
- Pre-phase setup (placing flag/jail)
- Multiplayer networking
- Polish/juice/animations
## Open Questions for Planning
1. **Map layout**: What's the minimum topology for interesting play? Lanes, chokepoints, shortcuts?
2. **AI behavior**: How smart does AI need to be to create "practiced chaos"?
3. **Route-drawing UX**: Click-drag? Waypoints? How to visualize planned route?
4. **Fog implementation**: Tile-based? Raycast? Mesh-based reveal?
5. **Scoring flow**: What happens after a point? Reset positions? Continuous play?
## Next Steps
Run `/workflows:plan` to break this down into implementation tasks.

View File

@@ -254,18 +254,18 @@ Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>"
## Acceptance Criteria
- [ ] Unity 6 LTS project opens without errors
- [ ] URP 2D Renderer is active (check Graphics settings)
- [ ] New Input System is the active input handling mode
- [ ] Folder structure matches spec (`Features/`, `Shared/`, `Settings/`, `Scenes/`)
- [ ] `GameInputActions` asset exists with placeholder actions
- [ ] Android build target configured (IL2CPP, ARM64, API 24+)
- [ ] iOS build target configured (IL2CPP, ARM64, iOS 13+)
- [ ] Desktop build targets configured
- [ ] Main.unity scene has Global Light 2D with low intensity
- [ ] `.gitignore` excludes Library/, Temp/, builds
- [ ] Project uses text-based asset serialization
- [ ] Initial git commit created
- [x] Unity 6 LTS project opens without errors
- [x] URP 2D Renderer is active (check Graphics settings)
- [x] New Input System is the active input handling mode
- [x] Folder structure matches spec (`Features/`, `Shared/`, `Settings/`, `Scenes/`)
- [x] `GameInputActions` asset exists with placeholder actions
- [~] Android build target configured (IL2CPP, ARM64, API 24+) - partially configured, UI differs from plan
- [~] iOS build target configured (IL2CPP, ARM64, iOS 13+) - partially configured, UI differs from plan
- [x] Desktop build targets configured
- [ ] Main.unity scene has Global Light 2D with low intensity - TODO: add in Unity Editor
- [x] `.gitignore` excludes Library/, Temp/, builds
- [x] Project uses text-based asset serialization
- [x] Initial git commit created
## Files Created/Modified

View File

@@ -0,0 +1,346 @@
---
title: "feat: Teaser Prototype Playable Core"
type: feat
date: 2026-02-01
revised: 2026-02-01
---
# Teaser Prototype: Playable Core (Simplified)
## Overview
Build a minimal playable 1v1 capture-the-flag teaser that captures the "practiced chaos" of Neighborhood Quarterback - where chaos has patterns you can learn to exploit, like Rocket League.
**Target experience:** Fast rounds with flag grabs, chases, tag-outs, and scrambles. Players should feel "I almost had it" and "I can learn this."
## Guiding Principle
**Build the skateboard, not the car chassis.** Get something playable in days, not weeks. Polish comes after validating the core loop is fun.
## Proposed Solution
6 scripts, 3 phases, ~15 tasks:
```
Assets/Scripts/
├── Game.cs # Score, reset, win, spawn
├── Unit.cs # Movement, state, respawn, flag carrying
├── RouteDrawer.cs # Click-drag to draw routes
├── Flag.cs # Pickup, drop, return
├── Visibility.cs # Simple sprite show/hide (no shaders)
└── SimpleAI.cs # Chase flag or flag carrier
```
No feature folders for MVP. No managers. Refactor when needed.
## Technical Decisions
| Decision | Choice | Rationale |
|----------|--------|-----------|
| Pathfinding | None | Draw route, unit follows, stops at obstacles |
| Fog of War | Sprite SetActive | Hide enemies outside vision radius. No shaders. |
| State | Bools/enums on scripts | No state machine frameworks |
| AI | One behavior | Chase player flag (or flag carrier) |
| Events | Direct method calls | No event bus for 6 scripts |
## Constants (Hardcoded, Tune Later)
```csharp
// In Game.cs - move to ScriptableObject if needed
const float UnitSpeed = 5f;
const float VisionRadius = 4f;
const float TagRadius = 0.75f;
const float RespawnDelay = 3f;
const float FlagReturnDelay = 5f;
const int WinScore = 3;
```
---
## Phase 1: Movement & Map (3-4 days)
**Goal:** Draw routes, units follow them, obstacles block.
### Tasks
- [x] **1.1** Create placeholder art in Main.unity:
- Green plane (ground, ~40x30 units)
- Gray rectangles (4-6 houses as obstacles with BoxCollider2D)
- Colored circles (units - blue team, red team)
- Two base zones (opposite corners)
- [x] **1.2** Create `Unit.cs`:
```csharp
public class Unit : MonoBehaviour
{
public enum Team { Player, Enemy }
public Team team;
public bool isTaggedOut;
public bool hasFlag;
List<Vector2> route;
int routeIndex;
public void SetRoute(List<Vector2> waypoints) { ... }
void Update() { /* follow route, stop at end */ }
public void TagOut() { /* disable, start respawn coroutine */ }
IEnumerator Respawn() { /* wait 3s, teleport to base, enable */ }
}
```
- [x] **1.3** Create `RouteDrawer.cs`:
- On mouse down over player unit: start route
- While dragging: collect points, draw LineRenderer preview
- On mouse up: call `unit.SetRoute(points)`
- Clear line after route applied
- [x] **1.4** Create `Game.cs` (partial):
```csharp
public class Game : MonoBehaviour
{
public Unit[] playerUnits; // Assign in inspector
public Unit[] enemyUnits;
public Transform playerBase;
public Transform enemyBase;
void Start() { SpawnUnits(); }
void SpawnUnits() { /* position 5 units at each base */ }
}
```
- [x] **1.5** Wire up scene:
- Create 5 Unit prefabs per team
- Add colliders to obstacles
- Test: draw route, unit follows, stops at obstacle
**Verification:**
- [ ] Can draw route on player unit, unit follows
- [ ] Unit stops when hitting obstacle
- [ ] Unit stops at end of route
- [ ] New route replaces old route
- [ ] Enemy units visible but not controllable
---
## Phase 2: Flag, Tagging, Scoring (2-3 days)
**Goal:** Grab flag, tag enemies, score points, win.
### Tasks
- [x] **2.1** Create `Flag.cs`:
```csharp
public class Flag : MonoBehaviour
{
public Unit.Team team;
public Transform homePosition;
public Unit carriedBy;
float dropTimer;
void Update()
{
if (carriedBy != null)
transform.position = carriedBy.transform.position;
else if (transform.position != homePosition.position)
HandleDroppedState();
}
public void Pickup(Unit unit) { carriedBy = unit; unit.hasFlag = true; }
public void Drop() { carriedBy.hasFlag = false; carriedBy = null; dropTimer = 5f; }
void ReturnHome() { transform.position = homePosition.position; }
}
```
- [x] **2.2** Add flag pickup detection:
- OnTriggerEnter2D: if enemy unit enters flag trigger, Pickup()
- In `Game.cs`: when unit with flag enters own base, Score()
- [x] **2.3** Add tagging to `Unit.cs`:
- OnTriggerEnter2D: if enemy unit overlaps
- Determine loser: farther from own base gets tagged
- (Or for more chaos: both get tagged)
- If tagged unit has flag, call flag.Drop()
- [x] **2.4** Add scoring to `Game.cs`:
```csharp
int playerScore, enemyScore;
public void Score(Unit.Team team)
{
if (team == Unit.Team.Player) playerScore++;
else enemyScore++;
Debug.Log($"Score: {playerScore} - {enemyScore}");
if (playerScore >= WinScore || enemyScore >= WinScore)
EndGame();
else
ResetRound();
}
void ResetRound()
{
// Return flags, respawn all units at bases
}
```
- [x] **2.5** Add simple UI:
- TextMeshPro showing score
- "YOU WIN" / "YOU LOSE" text on game end
- (No menu - press Play in editor)
**Verification:**
- [ ] Walking over enemy flag picks it up
- [ ] Flag follows carrier
- [ ] Reaching base with flag scores point
- [ ] Overlapping enemy triggers tag-out
- [ ] Tagged unit respawns after 3 seconds
- [ ] Dropped flag returns home after 5 seconds
- [ ] First to 3 wins
---
## Phase 3: Visibility & AI (2-3 days)
**Goal:** Can't see enemies outside vision range. AI provides opposition.
### Tasks
- [x] **3.1** Create `Visibility.cs`:
```csharp
public class Visibility : MonoBehaviour
{
public Unit[] playerUnits;
public Unit[] enemyUnits;
public Flag enemyFlag;
void Update()
{
foreach (var enemy in enemyUnits)
{
bool visible = IsVisibleToAnyPlayerUnit(enemy.transform.position);
enemy.GetComponent<SpriteRenderer>().enabled = visible;
}
// Also hide enemy flag if not carried and not visible
if (enemyFlag.carriedBy == null)
enemyFlag.GetComponent<SpriteRenderer>().enabled =
IsVisibleToAnyPlayerUnit(enemyFlag.transform.position);
}
bool IsVisibleToAnyPlayerUnit(Vector2 pos)
{
foreach (var unit in playerUnits)
{
if (unit.isTaggedOut) continue;
if (Vector2.Distance(unit.transform.position, pos) < VisionRadius)
return true;
}
return false;
}
}
```
- [x] **3.2** Create `SimpleAI.cs`:
```csharp
public class SimpleAI : MonoBehaviour
{
public Unit[] aiUnits;
public Flag playerFlag;
public Transform aiBase;
float decisionTimer;
void Update()
{
decisionTimer -= Time.deltaTime;
if (decisionTimer <= 0)
{
MakeDecisions();
decisionTimer = 0.5f; // Decide every 0.5s
}
}
void MakeDecisions()
{
foreach (var unit in aiUnits)
{
if (unit.isTaggedOut) continue;
Vector2 target;
if (unit.hasFlag)
target = aiBase.position; // Return flag
else if (playerFlag.carriedBy != null)
target = playerFlag.carriedBy.transform.position; // Chase carrier
else
target = playerFlag.transform.position; // Go for flag
// Simple route: straight line to target
unit.SetRoute(new List<Vector2> { target });
}
}
}
```
- [x] **3.3** Add slight route randomness:
- Offset target by small random amount
- Prevents all AI units clumping perfectly
- [x] **3.4** Playtest & tune:
- Adjust VisionRadius, TagRadius, speeds
- Make AI beatable but not trivial
**Verification:**
- [ ] Enemy units hidden when far from player units
- [ ] Enemies appear when player unit gets close
- [ ] AI units move toward player flag
- [ ] AI chases player flag carrier
- [ ] AI returns flag to base when carrying
- [ ] Can beat AI after 2-3 attempts
---
## Acceptance Criteria (MVP)
- [ ] Game starts with 5 units per side at bases
- [ ] Draw route on unit, unit follows path
- [ ] Unit stops at obstacles
- [ ] Grabbing enemy flag awards 1 point
- [ ] Returning flag to base (with own flag present) awards 1 more point
- [ ] Overlapping enemies triggers tag-out (farther from base loses)
- [ ] Tagged units respawn at base after 3 seconds
- [ ] Enemies only visible within vision radius of player units
- [ ] AI controls enemy team, chases flag
- [ ] First to 3 points wins
---
## Out of Scope (v2)
- Shader-based fog of war (smooth edges, feathering)
- Unit classes (Sneak/Patrol/Speed)
- Jail escort mechanics
- Motion lights
- Pre-phase setup
- Multiplayer
- AI with strategic roles
- Route obstacle preview
- Audio
- Main menu
- Mobile optimization
---
## What We're Testing
This prototype answers one question: **Is commanding units in CTF fun?**
If yes → Add fog polish, AI strategy, classes
If no → Revisit core mechanics before adding complexity
---
## References
- Soul Doc: `soul.md`
- Brainstorm: `docs/brainstorms/2026-02-01-teaser-prototype-brainstorm.md`
- Input actions: `Assets/Settings/Input/GameInputActions.inputactions`