1445 lines
30 KiB
Markdown
1445 lines
30 KiB
Markdown
Here is a practical phase plan for **YeetGeese**, an over-the-shoulder third-person tower defense game where the main weapon is thrown geese, built in **Godot 4**. I’m assuming the core fantasy is: the player is in a 3D arena, enemies approach, and the player throws geese either as projectiles, temporary turrets, or both. The plan below is structured so you can build a small playable prototype first, then expand into a full indie game.
|
||
|
||
---
|
||
|
||
# YeetGeese Phase Plan
|
||
|
||
## Phase 0: Game Definition & Setup
|
||
**Goal:** Define the core game, set up the Godot project, and create a clear development scope.
|
||
|
||
### Main Tasks
|
||
1. **Write a short design document**
|
||
- One page is enough.
|
||
- Core fantasy: “Yeet geese at enemies and defend a base.”
|
||
- Core loop:
|
||
- Enemies spawn.
|
||
- Player throws geese.
|
||
- Geese damage, distract, or tower-ize enemies.
|
||
- Player earns currency.
|
||
- Player buys/upgrades geese or defenses.
|
||
- Wave ends.
|
||
- Next wave becomes harder.
|
||
|
||
2. **Define the MVP**
|
||
A small but complete version of the game should include:
|
||
- One arena.
|
||
- One player controller.
|
||
- One goose type.
|
||
- Two enemy types.
|
||
- Five waves.
|
||
- Basic economy.
|
||
- Basic UI:
|
||
- Health.
|
||
- Currency.
|
||
- Wave number.
|
||
- Pause menu.
|
||
- Win/lose state.
|
||
|
||
3. **Set up the Godot project**
|
||
- Godot version: Godot 4.x.
|
||
- Project type: 3D.
|
||
- Renderer: Forward+ for better visuals, Mobile/Compatibility if targeting low-end devices.
|
||
- Create folders:
|
||
```text
|
||
res://
|
||
scripts/
|
||
scenes/
|
||
assets/
|
||
audio/
|
||
meshes/
|
||
textures/
|
||
materials/
|
||
animations/
|
||
ui/
|
||
data/
|
||
autoload/
|
||
tests/
|
||
```
|
||
- Set up Git.
|
||
- Add `.gitignore` for Godot artifacts.
|
||
- Add a simple README.
|
||
|
||
4. **Set up basic project architecture**
|
||
Create autoloads such as:
|
||
- `GameState.gd`
|
||
- Handles wave state, score, currency, lives, pause.
|
||
- `EventBus.gd`
|
||
- Central signals for gameplay events.
|
||
- `AudioManager.gd`
|
||
- Plays sfx and music.
|
||
- `SettingsManager.gd`
|
||
- Saves settings and unlockables.
|
||
|
||
5. **Define collision layers**
|
||
Suggested collision setup:
|
||
- `1`: Environment / terrain.
|
||
- `2`: Player.
|
||
- `3`: Enemy.
|
||
- `4`: Goose projectile.
|
||
- `5`: Goose turret.
|
||
- `6`: Pickups / currency.
|
||
- `7`: UI / trigger zones.
|
||
|
||
6. **Set up input map**
|
||
Suggested inputs:
|
||
- `Move_Forward`: W
|
||
- `Move_Backward`: S
|
||
- `Move_Left`: A
|
||
- `Move_Right`: D
|
||
- `Aim`: Mouse look.
|
||
- `Throw_Goose`: Left mouse button.
|
||
- `Switch_Goose`: 1 / 2 / 3 or Q.
|
||
- `Reload_Or_Refill`: R.
|
||
- `Pause`: Escape.
|
||
- `Sprint`: Shift, if used.
|
||
- `Crouch`: C, if used.
|
||
|
||
### Exit Criteria
|
||
- You have a clear MVP scope.
|
||
- Godot project opens cleanly.
|
||
- Basic folders, autoloads, input map, and collision setup exist.
|
||
- The team knows what the first playable prototype must contain.
|
||
|
||
---
|
||
|
||
# Phase 1: Core Playable Prototype
|
||
**Goal:** Prove that throwing geese at enemies in an over-the-shoulder third-person tower defense arena is fun.
|
||
|
||
This is the most important phase. Do not focus on art yet. Use greybox shapes and placeholder audio.
|
||
|
||
## Core Systems to Build
|
||
|
||
### 1. Third-Person Player Controller
|
||
Create an over-the-shoulder third-person player controller using Godot’s `CharacterBody3D`.
|
||
|
||
Basic structure:
|
||
```text
|
||
Player
|
||
- Camera3D
|
||
- ThrowOrigin (Marker3D at hand/gun position)
|
||
```
|
||
|
||
Player behavior:
|
||
- Mouse look.
|
||
- WASD movement.
|
||
- Ground snapping or simple gravity.
|
||
- Optional head bob.
|
||
- Optional sprint.
|
||
- Throw input triggers projectile creation.
|
||
|
||
### 2. Goose Projectile
|
||
The goose can be a simple `Area3D` or `RigidBody3D`.
|
||
|
||
For a first prototype, I recommend:
|
||
```text
|
||
GooseProjectile
|
||
- Area3D
|
||
- MeshInstance3D
|
||
- CollisionShape3D
|
||
- AnimationPlayer
|
||
```
|
||
|
||
Behavior:
|
||
- Spawn from `ThrowOrigin`.
|
||
- Apply velocity based on camera direction.
|
||
- Apply spin.
|
||
- Apply gravity or custom flight curve.
|
||
- Detect collision with enemies.
|
||
- On hit:
|
||
- Damage enemy.
|
||
- Play honk.
|
||
- Spawn hit effect.
|
||
- Queue free after lifetime or impact.
|
||
|
||
Simplified throw logic:
|
||
```gdscript
|
||
var throw_dir := -camera.global_transform.basis.z
|
||
projectile.linear_velocity = throw_dir * throw_speed
|
||
projectile.angular_velocity = Vector3(0, 12, 0)
|
||
```
|
||
|
||
### 3. Enemy
|
||
Start with one enemy type.
|
||
|
||
Enemy structure:
|
||
```text
|
||
Enemy
|
||
- Area3D or CharacterBody3D
|
||
- MeshInstance3D
|
||
- CollisionShape3D
|
||
- Health component
|
||
```
|
||
|
||
Enemy behavior:
|
||
- Spawn at a point.
|
||
- Move toward base or player.
|
||
- Attack player or base when close.
|
||
- Take damage.
|
||
- Die and drop currency.
|
||
|
||
For the first prototype, simple movement is enough:
|
||
```gdscript
|
||
var direction := (target.global_position - global_position).normalized()
|
||
velocity = direction * speed
|
||
move_and_slide()
|
||
```
|
||
|
||
If using a base to defend:
|
||
- Target the base.
|
||
- If base is destroyed, player loses.
|
||
|
||
If the player is the base:
|
||
- Target the player.
|
||
- If player dies, lose.
|
||
|
||
### 4. Basic Wave Spawner
|
||
Create a simple wave manager.
|
||
|
||
Wave manager behavior:
|
||
- Start wave.
|
||
- Spawn enemies over time.
|
||
- Track remaining enemies.
|
||
- When all enemies are dead, start next wave.
|
||
- After final wave, player wins.
|
||
|
||
Data structure example:
|
||
```gdscript
|
||
class_name WaveDef
|
||
extends Resource
|
||
|
||
@export var enemies: Array[EnemyDef] = []
|
||
@export var spawn_interval: float = 1.0
|
||
@export var reward: int = 10
|
||
```
|
||
|
||
### 5. Basic Economy
|
||
- Enemy dies.
|
||
- Player gains goose coins or feathers.
|
||
- Player can buy additional goose throws or a better goose.
|
||
|
||
For the first prototype:
|
||
- 100 starting feathers.
|
||
- Goose throw costs 0.
|
||
- Enemy drops 5 feathers.
|
||
- Every 10 enemies, unlock one extra goose in reserve.
|
||
- Or buy a “Strong Goose” that does more damage.
|
||
|
||
### 6. Minimal UI
|
||
Use Godot’s Control nodes.
|
||
|
||
Required UI:
|
||
- Top-left:
|
||
- Player health.
|
||
- Feathers/currency.
|
||
- Top-right:
|
||
- Wave number.
|
||
- Enemies remaining.
|
||
- Center:
|
||
- Crosshair.
|
||
- Menu:
|
||
- Resume.
|
||
- Restart.
|
||
- Quit.
|
||
|
||
### 7. Win/Lose State
|
||
- Win: survive all prototype waves.
|
||
- Lose: player health reaches 0 or base health reaches 0.
|
||
|
||
Show simple message:
|
||
- “Victory!”
|
||
- “Defeated…”
|
||
|
||
## Prototype Deliverables
|
||
A single playable scene where the player can:
|
||
- Move in first person.
|
||
- Look with the mouse.
|
||
- Throw geese.
|
||
- Geese hit enemies.
|
||
- Enemies move, take damage, and die.
|
||
- Currency increases.
|
||
- Waves progress.
|
||
- Player can win or lose.
|
||
|
||
## Exit Criteria
|
||
- The core loop is playable.
|
||
- Throwing geese feels responsive.
|
||
- Enemies can be killed.
|
||
- Waves work.
|
||
- Economy works minimally.
|
||
- The game has a clear win/lose state.
|
||
|
||
---
|
||
|
||
# Phase 2: Tower Defense Core Systems
|
||
**Goal:** Turn the prototype into a real tower defense game by adding towers, upgrades, enemy variety, and a more complete loop.
|
||
|
||
This phase is where YeetGeese becomes its own genre hybrid: third-person action + tower defense strategy.
|
||
|
||
## Design Decision: How Do Geese Function as Towers?
|
||
|
||
You need to choose one or more goose roles.
|
||
|
||
### Option A: Thrown Goose as Projectile
|
||
The goose is a flying attack.
|
||
|
||
Examples:
|
||
- Standard Goose: medium damage.
|
||
- Heavy Goose: slow, high damage.
|
||
- Fast Goose: fast, low damage, piercing.
|
||
- Exploding Goose: AoE damage.
|
||
- Homing Goose: slight curve toward nearest enemy.
|
||
|
||
### Option B: Goose Becomes a Turret
|
||
When thrown, the goose lands and stays for a short time.
|
||
|
||
Examples:
|
||
- The goose pecks nearby enemies.
|
||
- The goose honks to stun enemies.
|
||
- The goose guards a path.
|
||
- The goose dies after 10 seconds.
|
||
|
||
### Option C: Goose as Companion
|
||
The goose follows the player and occasionally attacks.
|
||
|
||
Examples:
|
||
- Player throws goose.
|
||
- Goose attaches to player for a time.
|
||
- It pecks the nearest enemy.
|
||
- It dies after taking too much damage.
|
||
|
||
I recommend starting with **Option A + Option B** as the core fantasy:
|
||
- Some geese are projectile weapons.
|
||
- Some geese land and become temporary turrets.
|
||
- This gives both action and tower defense.
|
||
|
||
---
|
||
|
||
## Phase 2 Systems
|
||
|
||
### 1. Goose Definitions
|
||
Make geese data-driven using Godot Resources.
|
||
|
||
Example:
|
||
```gdscript
|
||
class_name GooseDef
|
||
extends Resource
|
||
|
||
@export var id: String
|
||
@export var display_name: String
|
||
@export var cost: int
|
||
@export var damage: float
|
||
@export var throw_speed: float
|
||
@export var spin_speed: float
|
||
@export var lifetime: float
|
||
@export var knockback: float
|
||
@export var stun_duration: float
|
||
@export var can_become_turret: bool
|
||
@export var turret_duration: float
|
||
@export var turret_damage: float
|
||
@export var turret_attack_interval: float
|
||
@export var icon: Texture2D
|
||
```
|
||
|
||
Initial goose types:
|
||
1. **Basic Goose**
|
||
- Cheap.
|
||
- Medium damage.
|
||
- Standard speed.
|
||
|
||
2. **Angry Goose**
|
||
- Higher damage.
|
||
- Knockback.
|
||
- Slightly slower.
|
||
|
||
3. **Honk Goose**
|
||
- Low damage.
|
||
- Stuns enemies briefly.
|
||
- Useful for crowd control.
|
||
|
||
4. **Turret Goose**
|
||
- Lands and pecks nearby enemies for 6 seconds.
|
||
- Creates a mini tower.
|
||
|
||
5. **Bomb Goose**
|
||
- Explodes on impact.
|
||
- Area damage.
|
||
|
||
### 2. Enemy Definitions
|
||
Create data-driven enemy resources.
|
||
|
||
Example:
|
||
```gdscript
|
||
class_name EnemyDef
|
||
extends Resource
|
||
|
||
@export var id: String
|
||
@export var display_name: String
|
||
@export var health: float
|
||
@export var speed: float
|
||
@export var damage: float
|
||
@export var attack_range: float
|
||
@export var attack_cooldown: float
|
||
@export var reward: int
|
||
@export var scale: float
|
||
@export var color: Color
|
||
@export var mesh: PackedScene
|
||
```
|
||
|
||
Initial enemy types:
|
||
1. **Slow Grunt**
|
||
- Low health.
|
||
- Low speed.
|
||
- Low damage.
|
||
|
||
2. **Runner**
|
||
- Fast.
|
||
- Low health.
|
||
- Reaches base/player quickly.
|
||
|
||
3. **Tank**
|
||
- Slow.
|
||
- High health.
|
||
- High damage.
|
||
|
||
4. **Spitter**
|
||
- Keeps distance.
|
||
- Ranged attack.
|
||
|
||
5. **Boss**
|
||
- Appears at wave 5 or 10.
|
||
- High health.
|
||
- Special attack.
|
||
|
||
### 3. Wave Manager Expansion
|
||
Add:
|
||
- Enemy groups.
|
||
- Spawn intervals.
|
||
- Enemy paths.
|
||
- Wave scaling.
|
||
- Boss waves.
|
||
- Wave rewards.
|
||
|
||
Example:
|
||
```gdscript
|
||
class_name WaveDef
|
||
extends Resource
|
||
|
||
@export var wave_number: int
|
||
@export var enemies: Array[EnemyGroup]
|
||
@export var reward: int
|
||
```
|
||
|
||
```gdscript
|
||
class_name EnemyGroup
|
||
extends Resource
|
||
|
||
@export var enemy_def: EnemyDef
|
||
@export var count: int
|
||
@export var spawn_interval: float
|
||
@export var spawn_delay: float
|
||
```
|
||
|
||
### 4. Tower Placement System
|
||
If geese become turrets, create a tower placement system.
|
||
|
||
Possible approach:
|
||
- Player throws a Turret Goose at the ground.
|
||
- Goose lands.
|
||
- After a short delay, it becomes a turret.
|
||
- Turret has:
|
||
- Health.
|
||
- Duration.
|
||
- Range.
|
||
- Damage.
|
||
- Attack cooldown.
|
||
- Target priority.
|
||
|
||
Turret target priority:
|
||
1. Closest enemy.
|
||
2. Weakest enemy.
|
||
3. Enemy closest to base/player.
|
||
|
||
### 5. Upgrade System
|
||
Start simple.
|
||
|
||
Upgrade paths:
|
||
- Goose damage.
|
||
- Goose speed.
|
||
- Goose knockback.
|
||
- Turret duration.
|
||
- Turret range.
|
||
- Starting feathers.
|
||
- Enemy slow effect.
|
||
- Player movement speed.
|
||
|
||
Example upgrade structure:
|
||
```gdscript
|
||
class_name UpgradeDef
|
||
extends Resource
|
||
|
||
@export var id: String
|
||
@export var display_name: String
|
||
@export var description: String
|
||
@export var cost: int
|
||
@export var max_level: int
|
||
@export var effects: Dictionary
|
||
```
|
||
|
||
### 6. Player Inventory / Goose Selection
|
||
Add a simple selection system.
|
||
|
||
Player can have:
|
||
- Currently selected goose.
|
||
- Multiple goose slots.
|
||
- Limited reserve count.
|
||
- Refill timer or cost to refill.
|
||
|
||
UI:
|
||
- Bottom center shows selected goose.
|
||
- Number keys switch goose.
|
||
- Mouse wheel could switch goose.
|
||
|
||
### 7. Enemy AI Improvements
|
||
Add:
|
||
- Pathfinding or waypoint movement.
|
||
- Avoidance.
|
||
- Attack behavior.
|
||
- Stun behavior.
|
||
- Fear of honking.
|
||
- Aggro changes.
|
||
|
||
For early development, simple movement is fine:
|
||
- Move toward target.
|
||
- If blocked, slide or rotate.
|
||
- If in attack range, stop and attack.
|
||
|
||
Later, consider:
|
||
- NavigationRegion3D.
|
||
- NavMesh.
|
||
- Waypoints.
|
||
- Behavior tree or simple state machine.
|
||
|
||
### 8. Base / Objective System
|
||
Choose one of these:
|
||
|
||
#### Player as Objective
|
||
Enemies attack the player directly.
|
||
|
||
Pros:
|
||
- Simple.
|
||
- Feels third-person.
|
||
|
||
Cons:
|
||
- Less tower defense feel.
|
||
|
||
#### Base as Objective
|
||
Enemies attack a base, shrine, goose farm, or cheese stockpile.
|
||
|
||
Pros:
|
||
- More tower defense.
|
||
- Player can move freely.
|
||
|
||
Cons:
|
||
- Need base defense logic.
|
||
|
||
Recommended hybrid:
|
||
- There is a base to defend.
|
||
- Player can also be damaged by enemies.
|
||
- Losing happens if base health reaches 0 or player dies.
|
||
|
||
### 9. Audio
|
||
Add placeholder audio first, then replace later.
|
||
|
||
Required sounds:
|
||
- Goose honk.
|
||
- Throw whoosh.
|
||
- Impact.
|
||
- Enemy death.
|
||
- Enemy attack.
|
||
- Wave start.
|
||
- Wave complete.
|
||
- UI click.
|
||
- Coin pickup.
|
||
- Boss warning.
|
||
|
||
Use:
|
||
```text
|
||
AudioStreamPlayer
|
||
AudioStreamPlayer3D
|
||
```
|
||
|
||
For geese and nearby enemies, use 3D audio.
|
||
|
||
### 10. Particles & Juice
|
||
Add small visual/audio feedback:
|
||
- Goose trail.
|
||
- Hit particles.
|
||
- Enemy death burst.
|
||
- Feather explosion.
|
||
- Screen shake on heavy hits.
|
||
- Slow motion on boss kill, if desired.
|
||
|
||
This phase is where the game starts feeling like a game rather than a tech demo.
|
||
|
||
## Exit Criteria
|
||
- Multiple goose types exist.
|
||
- Multiple enemy types exist.
|
||
- Waves are data-driven.
|
||
- Turret geese can be placed.
|
||
- Upgrades exist.
|
||
- Player can select geese.
|
||
- Economy loop is complete.
|
||
- One full level is playable from start to finish.
|
||
- The game has a basic sense of progression.
|
||
|
||
---
|
||
|
||
# Phase 3: Vertical Slice
|
||
**Goal:** Create one polished, complete level that represents the final game quality.
|
||
|
||
This is the phase used for feedback, publisher meetings, demo day, or Steam Next Fest.
|
||
|
||
## Scope
|
||
One full level with:
|
||
- 10 waves.
|
||
- 3–5 goose types.
|
||
- 4–6 enemy types.
|
||
- 1 boss.
|
||
- 1 upgrade shop.
|
||
- 1 themed arena.
|
||
- Final art placeholders or low-poly stylized art.
|
||
- Final UI.
|
||
- Final audio.
|
||
- Tutorial.
|
||
- Options menu.
|
||
- Performance target.
|
||
|
||
## Art Direction
|
||
YeetGeese should probably be:
|
||
- Stylized.
|
||
- Bright.
|
||
- Funny.
|
||
- Slightly absurd.
|
||
- Easy to read in fast action.
|
||
|
||
Visual pillars:
|
||
1. **Readable silhouettes**
|
||
- Enemies must be easy to identify.
|
||
- Geese should be very visible.
|
||
|
||
2. **Strong color separation**
|
||
- Player geese: white, yellow, orange.
|
||
- Enemies: red, purple, dark colors.
|
||
- Environment: neutral or complementary.
|
||
|
||
3. **Comedic animation**
|
||
- Goose flapping.
|
||
- Enemy squish.
|
||
- Honk shockwave.
|
||
- Feather explosion.
|
||
- Boss rage face.
|
||
|
||
## Level Design
|
||
Create one strong arena.
|
||
|
||
Suggested arena concepts:
|
||
- Farmyard at dusk.
|
||
- Mall parking lot.
|
||
- Office building break room.
|
||
- Beach boardwalk.
|
||
- Giant kitchen.
|
||
- Airport terminal.
|
||
- Medieval goose castle.
|
||
|
||
Arena should have:
|
||
- Spawn points.
|
||
- Clear player movement space.
|
||
- Cover or terrain features.
|
||
- 2–3 chokepoints.
|
||
- Visual landmarks.
|
||
- Safe zone.
|
||
- Base or objective.
|
||
|
||
## UI Polish
|
||
Create a clean, humorous UI.
|
||
|
||
Menus:
|
||
- Main menu.
|
||
- Level select.
|
||
- Upgrade shop.
|
||
- Pause.
|
||
- Game over.
|
||
- Victory.
|
||
- Options.
|
||
- Credits.
|
||
|
||
HUD:
|
||
- Health.
|
||
- Base health, if separate.
|
||
- Feathers/currency.
|
||
- Wave counter.
|
||
- Enemies remaining.
|
||
- Selected goose.
|
||
- Goose inventory.
|
||
- Upgrade prompts.
|
||
- Boss health bar.
|
||
|
||
Accessibility:
|
||
- Text size options.
|
||
- Colorblind mode.
|
||
- Subtitles for audio cues.
|
||
- Mouse sensitivity slider.
|
||
- Invert Y axis.
|
||
- Left-hand mode.
|
||
- Reduced screen shake.
|
||
- High contrast mode.
|
||
|
||
## Audio Polish
|
||
Add:
|
||
- Main menu music.
|
||
- Gameplay music.
|
||
- Boss music.
|
||
- Victory theme.
|
||
- Defeat jingle.
|
||
- Final goose honk.
|
||
|
||
Audio mixing:
|
||
- Sfx should not overpower music.
|
||
- Goose honks should feel satisfying.
|
||
- Enemy damage should be clear.
|
||
- UI sounds should be subtle.
|
||
|
||
## Performance Goals
|
||
For a third-person 3D indie game, aim for:
|
||
- 60 FPS on mid-range PC.
|
||
- 30 FPS minimum on low-end PC.
|
||
- Stable frame time.
|
||
- Low memory usage.
|
||
- No major hitching during waves.
|
||
|
||
Optimization checklist:
|
||
- Use instancing for repeated meshes.
|
||
- Limit particle count.
|
||
- Pool projectiles and enemies.
|
||
- Avoid excessive collision checks.
|
||
- Use LOD if needed.
|
||
- Batch static geometry where possible.
|
||
- Avoid dynamic shadows on too many objects.
|
||
- Monitor memory with Godot debugger.
|
||
|
||
## Vertical Slice Deliverables
|
||
- One polished level.
|
||
- Complete gameplay loop.
|
||
- One boss.
|
||
- Upgrades.
|
||
- Full UI.
|
||
- Full audio.
|
||
- Options.
|
||
- Tutorial.
|
||
- Performance acceptable.
|
||
- Playable 10–15 minute experience.
|
||
|
||
## Exit Criteria
|
||
- A first-time player can understand the game within 2 minutes.
|
||
- The level is fun to play.
|
||
- The goose mechanic feels central and satisfying.
|
||
- The game looks and sounds cohesive.
|
||
- It runs well enough to share.
|
||
- You have a demo build for testing.
|
||
|
||
---
|
||
|
||
# Phase 4: Full Production
|
||
**Goal:** Expand the vertical slice into the full game.
|
||
|
||
This phase depends on your final scope, but for an indie game, I would keep it tight.
|
||
|
||
## Recommended Final Game Scope
|
||
For a first indie release, target:
|
||
- 3–5 levels.
|
||
- 8–12 goose types.
|
||
- 8–12 enemy types.
|
||
- 2–3 bosses.
|
||
- 1 upgrade tree or simple upgrade shop.
|
||
- Endless mode.
|
||
- Daily challenge, if feasible.
|
||
- Steam achievements.
|
||
- Localization optional for launch.
|
||
|
||
Do not overexpand. The best indie games are focused.
|
||
|
||
---
|
||
|
||
## Phase 4A: Content Pipeline
|
||
**Goal:** Build a repeatable pipeline for adding content without breaking the game.
|
||
|
||
### Goose Creation Pipeline
|
||
For each goose:
|
||
1. Create `GooseDef` resource.
|
||
2. Add mesh/animation.
|
||
3. Add sound.
|
||
4. Add projectile behavior.
|
||
5. Add turret behavior, if applicable.
|
||
6. Add icon.
|
||
7. Add description.
|
||
8. Add balance values.
|
||
9. Test in game.
|
||
10. Add to shop or unlock system.
|
||
|
||
### Enemy Creation Pipeline
|
||
For each enemy:
|
||
1. Create `EnemyDef` resource.
|
||
2. Add mesh.
|
||
3. Add animations.
|
||
4. Add attack behavior.
|
||
5. Add movement behavior.
|
||
6. Add health/speed/damage.
|
||
7. Add death effect.
|
||
8. Add reward.
|
||
9. Add wave data.
|
||
10. Balance.
|
||
|
||
### Level Creation Pipeline
|
||
For each level:
|
||
1. Build arena.
|
||
2. Place spawn points.
|
||
3. Place base/objective.
|
||
4. Define wave table.
|
||
5. Add level-specific modifiers.
|
||
6. Add level reward.
|
||
7. Add level unlock.
|
||
8. Playtest.
|
||
9. Balance.
|
||
10. Polish.
|
||
|
||
Example level modifiers:
|
||
- Enemies spawn faster.
|
||
- Geese have less range.
|
||
- Turrets last longer.
|
||
- Enemies are immune to stun.
|
||
- Currency drops increase.
|
||
- Dark lighting.
|
||
- Moving platforms.
|
||
- Obstacles.
|
||
|
||
---
|
||
|
||
## Phase 4B: Progression Systems
|
||
**Goal:** Give players a reason to keep playing.
|
||
|
||
Add one or more of these:
|
||
- Level unlocks.
|
||
- Goose unlocks.
|
||
- Upgrade unlocks.
|
||
- Cosmetic goose skins.
|
||
- Achievements.
|
||
- Endless mode.
|
||
- Score leaderboard.
|
||
- Daily challenge seed.
|
||
|
||
Avoid complex RPG stats. Keep it arcade-like.
|
||
|
||
## Phase 4C: Game Modes
|
||
Start with:
|
||
1. **Campaign**
|
||
- Fixed levels.
|
||
- Progressive difficulty.
|
||
|
||
2. **Endless Mode**
|
||
- Waves scale forever.
|
||
- Difficulty increases.
|
||
- Score-based.
|
||
|
||
Optional:
|
||
3. **Speedrun Mode**
|
||
- Timer.
|
||
- Minimal upgrades.
|
||
- High score.
|
||
|
||
4. **Daily Challenge**
|
||
- Seeded wave layout.
|
||
- Seeded goose modifiers.
|
||
|
||
## Phase 4D: Balance
|
||
Create a simple balance sheet.
|
||
|
||
Track:
|
||
- Goose cost.
|
||
- Goose damage.
|
||
- Goose speed.
|
||
- Enemy health.
|
||
- Enemy speed.
|
||
- Enemy damage.
|
||
- Wave reward.
|
||
- Upgrade cost.
|
||
- Level reward.
|
||
|
||
Balance goals:
|
||
- Player should never feel helpless.
|
||
- Player should not one-shot everything.
|
||
- Waves should ramp gradually.
|
||
- Bosses should feel powerful but defeatable.
|
||
- Upgrades should matter.
|
||
- Late-game geese should feel exciting.
|
||
|
||
Use playtesting data:
|
||
- Where do players die?
|
||
- Which goose is never used?
|
||
- Which enemy feels unfair?
|
||
- Is the economy too tight?
|
||
- Are waves too dense?
|
||
|
||
---
|
||
|
||
# Phase 5: Polish & Optimization
|
||
**Goal:** Make the game feel stable, responsive, and fun to play repeatedly.
|
||
|
||
## Gameplay Feel
|
||
Tune:
|
||
- Throw speed.
|
||
- Goose arc.
|
||
- Spin.
|
||
- Hit pause.
|
||
- Knockback.
|
||
- Camera recoil.
|
||
- Screen shake.
|
||
- Enemy death feedback.
|
||
- Coin pickup feedback.
|
||
- Wave transition feel.
|
||
|
||
The “yeet” should feel satisfying.
|
||
|
||
Possible tricks:
|
||
- Slight slow motion on big goose hits.
|
||
- Strong honk sound.
|
||
- Feather burst.
|
||
- Camera punch.
|
||
- Enemy squash animation.
|
||
- Sound layering:
|
||
- Whoosh + honk + impact.
|
||
|
||
## Input Feel
|
||
Tune:
|
||
- Mouse sensitivity.
|
||
- Mouse acceleration.
|
||
- Movement speed.
|
||
- Acceleration.
|
||
- Friction.
|
||
- Air control, if jumping is added.
|
||
- Throw cooldown.
|
||
- Switching goose speed.
|
||
|
||
## Visual Polish
|
||
- Final materials.
|
||
- Lighting.
|
||
- Fog, if used.
|
||
- Skybox.
|
||
- Environmental details.
|
||
- UI animations.
|
||
- Level transitions.
|
||
- Victory/defeat sequences.
|
||
|
||
## Audio Polish
|
||
- Final music.
|
||
- Final sfx.
|
||
- Mix levels.
|
||
- Spatial audio.
|
||
- Ducking of music during important events.
|
||
|
||
## Bug Fixing
|
||
Create bug categories:
|
||
- Critical: crashes, broken save, impossible win/loss.
|
||
- High: broken core mechanic.
|
||
- Medium: annoying gameplay issue.
|
||
- Low: visual or minor audio issue.
|
||
|
||
Use a board:
|
||
- Backlog.
|
||
- In Progress.
|
||
- Ready for Review.
|
||
- Done.
|
||
|
||
## Testing
|
||
Playtest:
|
||
- First-time players.
|
||
- Friends who understand the game.
|
||
- People who do not understand the game.
|
||
|
||
Ask:
|
||
- Did you understand the goal?
|
||
- Did you know how to throw geese?
|
||
- Did you know what currency was for?
|
||
- Did you know what the base was?
|
||
- Which goose was your favorite?
|
||
- Which wave was hardest?
|
||
- What felt unfair?
|
||
|
||
## Optimization
|
||
Check:
|
||
- FPS.
|
||
- Frame time.
|
||
- Memory.
|
||
- Draw calls.
|
||
- Physics cost.
|
||
- Particle count.
|
||
- Audio instance count.
|
||
- Object pooling efficiency.
|
||
- Collision overlap cost.
|
||
- Scene load time.
|
||
|
||
---
|
||
|
||
# Phase 6: Launch Preparation
|
||
**Goal:** Prepare for release or demo distribution.
|
||
|
||
## Store Page
|
||
Prepare:
|
||
- Title.
|
||
- Description.
|
||
- Short description.
|
||
- Features.
|
||
- System requirements.
|
||
- Screenshots.
|
||
- Trailer.
|
||
- Key art.
|
||
- Icon.
|
||
- Tags:
|
||
- Indie.
|
||
- Tower Defense.
|
||
- Third-Person.
|
||
- Action.
|
||
- Strategy.
|
||
- Funny.
|
||
- Animals.
|
||
- Geese.
|
||
|
||
## Build
|
||
Create final build:
|
||
- Windows.
|
||
- Linux, if desired.
|
||
- macOS, if desired.
|
||
- Steam build, if publishing on Steam.
|
||
|
||
## Checklist
|
||
- Game starts correctly.
|
||
- Save file works.
|
||
- Options persist.
|
||
- No missing textures.
|
||
- No missing audio.
|
||
- No console errors.
|
||
- Performance acceptable.
|
||
- Achievements work.
|
||
- Leaderboards work, if present.
|
||
- Localization files work, if present.
|
||
- Legal information included.
|
||
- Credits included.
|
||
- ESRB/PEGI info available, if required.
|
||
- Refund policy understood.
|
||
|
||
## Marketing
|
||
Prepare:
|
||
- Dev log.
|
||
- Screenshots.
|
||
- Short trailer.
|
||
- Gameplay clips.
|
||
- Press kit.
|
||
- Community posts.
|
||
- Demo build, if using Steam Next Fest or similar.
|
||
|
||
---
|
||
|
||
# Phase 7: Post-Launch
|
||
**Goal:** Support the game and extend its life.
|
||
|
||
## Immediate Post-Launch
|
||
- Monitor bugs.
|
||
- Patch critical issues.
|
||
- Respond to player feedback.
|
||
- Balance early.
|
||
- Collect reviews.
|
||
- Track crash reports.
|
||
|
||
## Optional Updates
|
||
- New goose skin.
|
||
- New enemy.
|
||
- New level.
|
||
- New game mode.
|
||
- Boss rush.
|
||
- Daily challenge.
|
||
- Localization.
|
||
- Controller support, if not already present.
|
||
|
||
---
|
||
|
||
# Suggested Godot Architecture
|
||
|
||
Here is a practical scene/component structure.
|
||
|
||
## Autoloads
|
||
|
||
### `GameState.gd`
|
||
Handles global game state.
|
||
|
||
Signals:
|
||
```gdscript
|
||
signal health_changed(value)
|
||
signal base_health_changed(value)
|
||
signal currency_changed(value)
|
||
signal wave_started(wave_number)
|
||
signal wave_completed(wave_number)
|
||
signal game_over()
|
||
signal victory()
|
||
```
|
||
|
||
Variables:
|
||
```gdscript
|
||
var player_health: int = 100
|
||
var base_health: int = 100
|
||
var currency: int = 0
|
||
var current_wave: int = 1
|
||
var total_waves: int = 10
|
||
var is_paused: bool = false
|
||
var is_game_over: bool = false
|
||
```
|
||
|
||
### `EventBus.gd`
|
||
Central gameplay events.
|
||
|
||
Signals:
|
||
```gdscript
|
||
signal goose_thrown(goose: Node3D)
|
||
signal goose_hit(target: Node3D, damage: float)
|
||
signal enemy_died(enemy: Node3D)
|
||
signal enemy_spawned(enemy: Node3D)
|
||
signal turret_placed(turret: Node3D)
|
||
signal upgrade_purchased(upgrade_id: String)
|
||
```
|
||
|
||
### `AudioManager.gd`
|
||
Plays audio.
|
||
|
||
```gdscript
|
||
func play_sfx(id: String) -> void:
|
||
# play sound
|
||
pass
|
||
```
|
||
|
||
---
|
||
|
||
## Scene Structure
|
||
|
||
### `Main.tscn`
|
||
```text
|
||
Main
|
||
- WorldEnvironment
|
||
- DirectionalLight3D
|
||
- Camera3D, if needed
|
||
- Player
|
||
- EnemySpawner
|
||
- Base
|
||
- UI
|
||
- AudioStreamPlayer
|
||
```
|
||
|
||
### `Player.tscn`
|
||
```text
|
||
Player
|
||
- CharacterBody3D
|
||
- CollisionShape3D
|
||
- Camera3D
|
||
- ThrowOrigin
|
||
- Hand / GooseModel
|
||
- AnimationPlayer
|
||
- AudioStreamPlayer3D
|
||
```
|
||
|
||
### `GooseProjectile.tscn`
|
||
```text
|
||
GooseProjectile
|
||
- Area3D
|
||
- CollisionShape3D
|
||
- MeshInstance3D
|
||
- GPUParticles3D
|
||
- AudioStreamPlayer3D
|
||
```
|
||
|
||
### `Enemy.tscn`
|
||
```text
|
||
Enemy
|
||
- CharacterBody3D
|
||
- CollisionShape3D
|
||
- MeshInstance3D
|
||
- AudioStreamPlayer3D
|
||
- HealthBar
|
||
```
|
||
|
||
### `TurretGoose.tscn`
|
||
```text
|
||
TurretGoose
|
||
- Area3D
|
||
- CollisionShape3D
|
||
- MeshInstance3D
|
||
- TargetDetector
|
||
- PeckAnimation
|
||
- AudioStreamPlayer3D
|
||
```
|
||
|
||
---
|
||
|
||
# Suggested Script Examples
|
||
|
||
## Player Throw Input
|
||
Simplified:
|
||
```gdscript
|
||
@onready var camera: Camera3D = $Camera3D
|
||
@onready var throw_origin: Marker3D = $ThrowOrigin
|
||
@onready var goose_projectile_scene: PackedScene = preload("res://scenes/GooseProjectile.tscn")
|
||
|
||
func _unhandled_input(event: InputEvent) -> void:
|
||
if event.is_action_pressed("Throw_Goose"):
|
||
throw_goose()
|
||
|
||
func throw_goose() -> void:
|
||
var goose = goose_projectile_scene.instantiate()
|
||
goose.global_position = throw_origin.global_position
|
||
goose.global_transform = camera.global_transform
|
||
get_parent().add_child(goose)
|
||
EventBus.goose_thrown.emit(goose)
|
||
AudioManager.play_sfx("goose_throw")
|
||
```
|
||
|
||
## Goose Projectile
|
||
```gdscript
|
||
extends Area3D
|
||
|
||
@export var throw_speed: float = 25.0
|
||
@export var spin_speed: float = 15.0
|
||
@export var lifetime: float = 2.0
|
||
|
||
var age: float = 0.0
|
||
|
||
func _ready() -> void:
|
||
body_entered.connect(_on_body_entered)
|
||
|
||
func _process(delta: float) -> void:
|
||
age += delta
|
||
if age > lifetime:
|
||
queue_free()
|
||
|
||
func _on_body_entered(body: Node3D) -> void:
|
||
if body.has_method("take_damage"):
|
||
body.take_damage(10.0)
|
||
AudioManager.play_sfx("goose_hit")
|
||
queue_free()
|
||
```
|
||
|
||
## Enemy Health
|
||
```gdscript
|
||
extends CharacterBody3D
|
||
|
||
@export var max_health: float = 30.0
|
||
var health: float = 30.0
|
||
|
||
func _ready() -> void:
|
||
health = max_health
|
||
|
||
func take_damage(amount: float) -> void:
|
||
health -= amount
|
||
if health <= 0:
|
||
die()
|
||
|
||
func die() -> void:
|
||
EventBus.enemy_died.emit(self)
|
||
AudioManager.play_sfx("enemy_die")
|
||
queue_free()
|
||
```
|
||
|
||
## Wave Manager
|
||
```gdscript
|
||
extends Node
|
||
|
||
@export var waves: Array[Resource] = []
|
||
@export var spawn_position: Marker3D
|
||
|
||
var current_wave_index: int = 0
|
||
|
||
func _ready() -> void:
|
||
start_wave()
|
||
|
||
func start_wave() -> void:
|
||
if current_wave_index >= waves.size():
|
||
GameState.victory.emit()
|
||
return
|
||
|
||
var wave: WaveDef = waves[current_wave_index]
|
||
GameState.wave_started.emit(current_wave_index + 1)
|
||
spawn_wave(wave)
|
||
current_wave_index += 1
|
||
|
||
func spawn_wave(wave: WaveDef) -> void:
|
||
# spawn enemies according to wave data
|
||
pass
|
||
```
|
||
|
||
---
|
||
|
||
# Recommended Development Timeline
|
||
|
||
This assumes a small team or solo developer working part-time.
|
||
|
||
| Phase | Duration | Output |
|
||
|---|---:|---|
|
||
| Phase 0: Definition & Setup | 1–2 weeks | Project setup, MVP scope |
|
||
| Phase 1: Prototype | 2–4 weeks | Playable throw-enemy loop |
|
||
| Phase 2: Core Systems | 4–6 weeks | Waves, economy, towers, upgrades |
|
||
| Phase 3: Vertical Slice | 4–8 weeks | Polished one-level demo |
|
||
| Phase 4: Full Production | 8–16 weeks | Full game content |
|
||
| Phase 5: Polish & Optimization | 2–4 weeks | Stable, fun build |
|
||
| Phase 6: Launch Prep | 2–3 weeks | Store page, build, marketing |
|
||
| Phase 7: Post-Launch | Ongoing | Patches, updates |
|
||
|
||
For a tighter indie scope, the full project could be around **6–12 months part-time** or **2–4 months full-time**, depending on art, animation, and scope.
|
||
|
||
---
|
||
|
||
# Biggest Risks & How to Avoid Them
|
||
|
||
## 1. Scope Creep
|
||
**Risk:** You add too many goose types, enemy types, and mechanics.
|
||
|
||
**Solution:**
|
||
- Finish the vertical slice before adding more content.
|
||
- Keep the MVP small.
|
||
- Cut anything that is not core to “thrown geese.”
|
||
|
||
## 2. Third-Person vs. Tower Defense Confusion
|
||
**Risk:** Players do not understand whether this is a shooter, platformer, or tower defense.
|
||
|
||
**Solution:**
|
||
- Make the base/objective very visible.
|
||
- Use a clear HUD.
|
||
- Use a short tutorial.
|
||
- Make enemies clearly path toward the objective.
|
||
|
||
## 3. Goose Throwing Feels Weak
|
||
**Risk:** The main mechanic does not feel satisfying.
|
||
|
||
**Solution:**
|
||
- Invest heavily in feel.
|
||
- Add spin, arc, honks, feathers, hit pause, and screen shake.
|
||
- Playtest frequently.
|
||
|
||
## 4. Enemy AI Gets Too Complex
|
||
**Risk:** You spend too long making advanced AI.
|
||
|
||
**Solution:**
|
||
- Use simple movement first.
|
||
- Use waypoint paths or straight-line targeting.
|
||
- Add pathfinding only if needed.
|
||
|
||
## 5. Art Scope Becomes Too Big
|
||
**Risk:** You try to build beautiful environments before the game is fun.
|
||
|
||
**Solution:**
|
||
- Use low-poly stylized assets.
|
||
- Keep materials simple.
|
||
- Use strong color and silhouette.
|
||
- Polish one level before expanding.
|
||
|
||
## 6. Performance Problems
|
||
**Risk:** Too many geese, enemies, and particles cause frame drops.
|
||
|
||
**Solution:**
|
||
- Pool projectiles and enemies.
|
||
- Limit simultaneous enemies.
|
||
- Limit particles.
|
||
- Use simple collision shapes.
|
||
- Test performance early.
|
||
|
||
---
|
||
|
||
# Minimum Playable Version Checklist
|
||
|
||
Use this as your Phase 1 target.
|
||
|
||
- [ ] First-person player can move.
|
||
- [ ] Mouse look works.
|
||
- [ ] Player can throw a goose.
|
||
- [ ] Goose flies forward.
|
||
- [ ] Goose spins.
|
||
- [ ] Goose hits enemy.
|
||
- [ ] Enemy takes damage.
|
||
- [ ] Enemy dies.
|
||
- [ ] Player gains currency.
|
||
- [ ] Wave 1 starts.
|
||
- [ ] Wave 2 starts after wave 1 completes.
|
||
- [ ] Player can win after final wave.
|
||
- [ ] Player can lose if health reaches 0.
|
||
- [ ] Basic UI shows health, currency, wave.
|
||
- [ ] Pause menu works.
|
||
- [ ] Placeholder goose sound plays.
|
||
- [ ] Placeholder enemy death sound plays.
|
||
- [ ] No major crashes in a 5-minute playtest.
|
||
|
||
---
|
||
|
||
# Suggested First 14 Days
|
||
|
||
If you want a very concrete start, do this for two weeks.
|
||
|
||
## Days 1–3: Setup
|
||
- Create Godot project.
|
||
- Set up folders.
|
||
- Set up Git.
|
||
- Create autoloads.
|
||
- Create input actions.
|
||
- Create collision layers.
|
||
- Create simple greybox arena.
|
||
|
||
## Days 4–7: Player + Goose
|
||
- Build third-person player controller.
|
||
- Add mouse look.
|
||
- Add throw input.
|
||
- Create goose projectile.
|
||
- Make goose fly forward.
|
||
- Add basic collision.
|
||
- Add placeholder honk.
|
||
|
||
## Days 8–10: Enemy
|
||
- Create enemy.
|
||
- Make enemy move toward player or base.
|
||
- Make enemy take damage.
|
||
- Make enemy die.
|
||
- Add placeholder enemy mesh.
|
||
- Add enemy death sound.
|
||
|
||
## Days 11–13: Waves + UI
|
||
- Create wave manager.
|
||
- Spawn 3 enemies in wave 1.
|
||
- Spawn 5 enemies in wave 2.
|
||
- Add HUD.
|
||
- Add win/lose screens.
|
||
|
||
## Day 14: Playtest
|
||
- Play the full loop.
|
||
- Note what feels bad.
|
||
- Fix the most important issue.
|
||
- Decide the next goose type to add.
|
||
|
||
---
|
||
|
||
# Final Recommendation
|
||
|
||
Start with this exact loop:
|
||
|
||
> **Move → Aim → Yeet Goose → Goose Honks → Enemy Squishes → Feathers Drop → Next Wave**
|
||
|
||
Once that loop feels good, add:
|
||
1. Turret geese.
|
||
2. Upgrades.
|
||
3. Enemy variety.
|
||
4. Bosses.
|
||
5. More levels.
|
||
6. Polish.
|
||
|
||
The game does not need a complicated tower defense economy to be fun. It needs a satisfying goose throw, readable enemies, and a clear objective. If the goose yeet feels great, the rest will follow. |