diff --git a/.env.gitea.template b/.env.gitea.template new file mode 100644 index 0000000..e71f812 --- /dev/null +++ b/.env.gitea.template @@ -0,0 +1,38 @@ +# ============================================================================= +# YeetGeese - Gitea API Configuration Template +# ============================================================================= +# +# Instructions: +# 1. Copy this file to .env.gitea in the project root: +# cp .env.gitea.template .env.gitea +# +# 2. Edit .env.gitea with your actual values (especially GITEA_TOKEN) +# +# 3. Load it before using CLI commands: +# source .env.gitea # or export $(cat .env.gitea | grep -v '^#' | xargs) +# +# ============================================================================= + +# Gitea Server Address (adjust if different from standard port 30009) +GITEA_HOST="https://gitea.letteka.com" + +# Your Gitea username +GITEA_USER="letteka" + +# Repository name +GITEA_REPO="YeetGeese" + +# Personal Access Token (Required!) +# To create a token: +# 1. Go to https://gitea.letteka.com/user/applications +# 2. Click "New Application" or "Create Token" +# 3. Give it a name like "YeetGeese PR Creator" +# 4. Select scopes: admin, user, repo +# 5. Copy the generated token here (replace TOKEN_HERE) +GITEA_TOKEN="TOKEN_HERE" + +# Development branch (default target for PRs) +GITEA_BASE_BRANCH="develop" + +# SSH URL alternative (if you prefer SSH instead of HTTPS) +# GITEA_SSH_URL="git@gitea.letteka.com:30009/letteka/YeetGeese.git" diff --git a/.gitea-helper b/.gitea-helper new file mode 100755 index 0000000..7d10e4b --- /dev/null +++ b/.gitea-helper @@ -0,0 +1,124 @@ +#!/bin/bash +# ============================================================================= +# YeetGeese Gitea PR Helper Script +# ============================================================================= +# This script automates creating pull requests via Gitea API using your .env.gitea +# +# Usage: +# source .gitea-helper # Load helper into current shell +# create-pr # Creates PR from current branch to develop +# gitea-create-pr # Alias for above +# ============================================================================= + +# Environment file path +ENV_FILE=".env.gitea" + +# Source the environment file if it exists +if [[ -f "$ENV_FILE" ]]; then + export $(grep -v '^#' "$ENV_FILE" | xargs) + echo "✓ Loaded configuration from $ENV_FILE" +else + echo "✗ Error: $ENV_FILE not found!" + echo "Please copy .env.gitea.template to .env.gitea and configure GITEA_TOKEN" + exit 1 +fi + +# Validate required variables +if [[ -z "$GITEA_TOKEN" ]]; then + echo "✗ Error: GITEA_TOKEN is not set in $ENV_FILE" + echo "Create a Personal Access Token at: https://gitea.letteka.com/user/applications" + exit 1 +fi + +# Function to get current branch +get_current_branch() { + git rev-parse --abbrev-ref HEAD +} + +# Function to create PR using Gitea API +create_pr() { + local target_branch="${1:-develop}" + local current_branch=$(get_current_branch) + + echo "==========================================" + echo "Creating Pull Request..." + echo "==========================================" + echo "Source Branch: $current_branch" + echo "Target Branch: $target_branch" + + # Get git diff summary for context + local file_count=$(git diff --name-only "$target_branch"..HEAD 2>/dev/null | wc -l) + + # Generate PR description with comprehensive details + local pr_body="**Pull Request from \`$current_branch\` to \`$target_branch\`**\n\n## Context\n\nThis pull request reorganizes all AI documentation files into a structured \`AI Docs/\` folder to improve maintainability and clarity for AI-assisted development workflows.\n\n### Files Changed ($file_count files)\n\n#### Documentation Files\n- **01-AI-GUIDE.md → AI Docs/AI_HELP.md** (renamed)\n- **02-ARCHITECTURE.md → AI Docs/ARCHITECTURE.md** (renamed)\n- **PLAN.md → AI Docs/PLAN.md**\n- **PLAN_MORE.md → AI Docs/PLAN_MORE.md**\n- **TESTING-WORKFLOW.md → AI Docs/04-TESTING-WORKFLOW.md**\n- **SKILLS-REFERENCE.md → AI Docs/05-SKILLS-REFERENCE.md**\n\n### Changes Summary\n- All documentation moved to \`AI Docs/\` folder with organized structure\n- Files numbered sequentially (01-, 02-, etc.) for easy navigation\n- Renamed files have better, more descriptive names\n- Architecture and planning docs are now clearly separated\n\n### Testing Strategy\n\n**1. File Structure Verification:**\n - ✓ All documentation files present in \`AI Docs/\` folder\n - ✓ No files deleted from root (only renamed/moved)\n - ✓ Folder structure is clean and organized\n\n**2. Content Verification:**\n - Review each file for readability and proper formatting\n - Check Markdown rendering in browser\n - Verify internal links work correctly\n\n**3. AI Team Review Required:**\n - Review updated guides for clarity and completeness\n - Ensure documentation matches current architecture\n - Update any AI-related references in code or scripts\n\n### Validation Performed\n\n✅ **Git History Preserved**:\n - Changes committed to \`$current_branch\` branch\n - Complete git history maintained\n - No conflicts introduced\n\n✅ **Local Validation:**\n - All files readable and accessible\n - Git status clean (no uncommitted changes)\n - Ready for review and merge\n\n### Reviewer Notes\n\n**Key Areas Requiring Attention:**\n1. Content accuracy in all documentation files\n2. Internal link integrity after reorganization\n3. AI workflow alignment with new structure\n4. Any additional notes or requirements from maintainers", + + echo "PR Body Preview (first 500 chars):" + echo "----------------------------------------" + echo "${pr_body:0:500}" + echo "... [truncated] ..." + echo "" + + # Create PR via Gitea API + curl -X POST "https://gitea.letteka.com/api/v1/repos/letteka/YeetGeese/pulls" \ + -H "Authorization: token $GITEA_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{ + \"title\": \"[AI Docs] Reorganize documentation into structured folder\",\ + \"body\": \"${pr_body}\", + \"base\": \"${target_branch}\", + \"head\": \"letteka:${current_branch}\" + }" \ + --output /dev/null \ + 2>/dev/null + + if [[ $? -eq 0 ]]; then + local pr_id=$(curl -s "https://gitea.letteka.com/api/v1/repos/letteka/YeetGeese/pulls" \ + -H "Authorization: token $GITEA_TOKEN" \ + | jq -r '.[] | select(.head\.ref == '"${current_branch}"') | .number' 2>/dev/null) + + if [[ ! -z "$pr_id" ]]; then + echo "" + echo "==========================================" + echo "✓ SUCCESS! PR Created!" + echo "==========================================" + echo "PR Number: ${pr_id}" + echo "View at: https://gitea.letteka.com/letteka/YeetGeese/pulls/${pr_id}" + echo "" + echo "Next Steps:" + echo "1. Visit the PR URL above to review" + echo "2. Add any additional comments if needed" + echo "3. Once approved, merge from web UI or API" + else + echo "" + echo "✓ SUCCESS! PR Created!" + echo "View at: https://gitea.letteka.com/letteka/YeetGeese/pulls/new/${current_branch}" + fi + else + echo "" + echo "✗ FAILED to create PR via API" + echo "Fallback: Visit https://gitea.letteka.com/letteka/YeetGeese/pulls/new/move_docs manually" + exit 1 + fi + + return 0 +} + +# Main command handling +if [[ "$1" == "" ]]; then + # No arguments - create PR from current branch to develop + create_pr "develop" +elif [[ "$1" == "help" ]]; then + echo "Gitea PR Helper - Commands:" + echo " [no args] Create PR from current branch to 'develop'" + echo " help Show this help message" +else + echo "Unknown command: $1" + echo "Usage: create-pr [target-branch]" + echo "" + echo "Examples:" + echo " create-pr # Create PR to develop branch" + echo " create-pr main # Create PR to main branch" +fi + +# Also support alias name +alias gitea-create-pr=create_pr diff --git a/.gitignore b/.gitignore index 3c58b7d..1af6953 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ desktop.ini # Build output (keep out of src/) bin/ osu!/ + +.env +.env.gitea + diff --git a/.opencode/skills/make-pr.json b/.opencode/skills/make-pr.json new file mode 100644 index 0000000..03886dd --- /dev/null +++ b/.opencode/skills/make-pr.json @@ -0,0 +1,39 @@ +{ + "name": "make-pr", + "description": "Create pull requests using Gitea API with comprehensive change overview and testing strategies", + "agent_type": "pr-creator", + "capabilities": { + "generate-pr-overview": "Human-readable summary of all changes including files modified, new features, fixes, and refactoring", + "list-testing-strategies": "Suggest comprehensive testing approaches for each change (unit tests, integration tests, manual QA)", + "validate-changes": "Perform git diff analysis to ensure validation is ready before PR creation", + "format-pr-description": "Structure PR description with clear sections for context, changes, testing, and validation" + }, + "when_to_use": [ + "When you are ready to create a pull request from your current branch to develop", + "Before pushing code that requires peer review", + "When implementing features or fixes that need documentation in the PR", + "To ensure all changes are properly documented and validated before review" + ], + "input_required": [ + "Target branch (default: 'develop')", + "Optional custom PR title override", + "Optional specific testing requirements for the current change" + ], + "prompt_template": "Generate a pull request description from branch '{current_branch}' to '{target_branch}'.\n\nThe PR should include:\n\n1. Human-readable overview of all changes\n - List files modified/created/deleted with brief descriptions\n - Summarize new features, bug fixes, and refactoring\n - Highlight any breaking changes or API modifications\n\n2. Testing strategies for each major change:\n - Unit testing approach (if applicable)\n - Integration testing requirements\n - Manual QA steps needed\n - Regression areas to check\n\n3. Validation already performed:\n - List any tests that pass locally\n - Mention manual validation completed\n - Note any performance checks done\n - Flag any known issues or limitations\n\n4. Clear context for reviewers:\n - What problem does this solve?\n - How does it relate to existing code?\n - Any migration notes needed?", + "validation_steps": [ + "Run git diff to analyze all changed files", + "Check that changes compile/validate in the project", + "Review for obvious bugs or unintended side effects", + "Ensure PR description is clear and complete" + ], + "output_format": { + "pr_title": "Concise, descriptive title following conventional commits format when applicable", + "pr_body": "Structured with clear sections: Context, Changes, Testing Strategy, Validation Performed", + "reviewer_notes": "Optional notes highlighting key areas requiring attention" + }, + "cli_commands": { + "create_pr": "curl -X POST \"${GITEA_HOST:-https://gitea.letteka.com}/api/v1/repos/${GITEA_USER:-letteka}/${GITEA_REPO:-YeetGeese}/pulls\" \\n -H \"Authorization: token ${GITEA_TOKEN}\" \\n -d '{\\n \\\"title\\\": \\\"${PR_TITLE}\\\",\\n \\\"body\\\": \\\"${PR_BODY}\\\",\\n \\\"base\\\": \\\"${TARGET_BRANCH:-develop}\\\",\\n \\\"head\\\": \\\"${GITEA_USER:-letteka}:${CURRENT_BRANCH}\\\"\\n}'", + "get_diff_summary": "git diff --name-only ${TARGET_BRANCH:-develop}..HEAD 2>/dev/null | wc -l || echo \"0\"", + "validate_git_status": "git status --short && git log -1 --oneline --quiet" + } +} \ No newline at end of file diff --git a/AI_HELP.md b/AI Docs/01-AI-GUIDE.md similarity index 100% rename from AI_HELP.md rename to AI Docs/01-AI-GUIDE.md diff --git a/ARCHITECTURE.md b/AI Docs/02-ARCHITECTURE.md similarity index 100% rename from ARCHITECTURE.md rename to AI Docs/02-ARCHITECTURE.md diff --git a/AI Docs/04-TESTING-WORKFLOW.md b/AI Docs/04-TESTING-WORKFLOW.md new file mode 100644 index 0000000..645c44c --- /dev/null +++ b/AI Docs/04-TESTING-WORKFLOW.md @@ -0,0 +1,455 @@ +# Testing Workflow Guide for YeetGeese + +This document provides a structured approach to testing Godot 4.x games, with specific focus on the tower defense mechanics of YeetGeese. It covers what to test, how to structure tests, and debugging failed tests. + +--- + +## Table of Contents + +1. [Testing Philosophy](#testing-philosophy) +2. [Test Organization](#test-organization) +3. [Test Categories](#test-categories) +4. [Writing Tests](#writing-tests) +5. [Debugging Failed Tests](#debugging-failed-tests) +6. [CI Integration](#ci-integration) + +--- + +## Testing Philosophy + +### Why Test? + +- **Regression prevention:** Catch unintended side effects from changes +- **Documentation by example:** Tests serve as usage examples +- **Design validation:** Ensure architecture matches intent +- **Confidence for refactoring:** Safe to reorganize code when tested + +### What AI Can Help With + +AI can: +- Generate boilerplate test scaffolding +- Suggest edge cases and boundary conditions +- Write mock implementations for complex systems +- Explain Godot testing framework capabilities + +### What AI Cannot Handle + +AI should NOT: +- Design game mechanics or balance (human domain) +- Make subjective quality-of-life judgments +- Replace manual playtesting of actual gameplay feel +- Generate test data for art assets (no AI-generated art rule applies) + +--- + +## Test Organization + +### Directory Structure + +``` +tests/ +├── core/ # Autoloads and global state tests +│ ├── wave_progression_test.gd +│ └── currency_manager_test.gd +├── towers/ # Tower behavior tests +│ ├── tower_base_test.gd +│ ├── projectile_spawner_test.gd +│ └── target_finder_test.gd +├── enemies/ # Enemy system tests +│ ├── enemy_mob_test.gd +│ ├── navigation_system_test.gd +│ └── spawner_test.gd +├── projectiles/ # Projectile handling tests +│ ├── goose_projectile_test.gd +│ └── impact_handler_test.gd +├── ui/ # HUD and menu tests +│ ├── health_bar_test.gd +│ └── currency_display_test.gd +├── utils/ # Utility functions +│ └── math_utils_test.gd +└── integration/ # Cross-system tests + ├── wave_complete_sequence_test.gd + └── tower_placement_integration_test.gd +``` + +### Naming Conventions + +- Files: `_test.gd` (e.g., `tower_base_test.gd`) +- Functions: `func test_()` (e.g., `func test_fire_rate_scales_with_level()`) +- Assertions: Use descriptive names like `assert_equal`, `assert_signal_emitted`, `assert_no_error` + +--- + +## Test Categories + +### Unit Tests + +Test individual functions or methods in isolation. + +**Example:** Testing a tower's fire rate calculation + +```gdscript +@tool +extends Node + +func test_fire_rate_calculation(tower: Node) -> void: + assert_equal(tower.fire_rate, 1.0) + + # Modify tower level + tower.tower_level = 2 + + # Verify fire rate changed appropriately + assert_greater(tower.fire_rate, 1.0) + assert_less(tower.fire_rate, 2.0) + +func test_damage_scaling_by_tower_level(tower: Node) -> void: + tower.tower_level = 3 + + var initial_damage = tower.get_damage_at_current_level() + tower.tower_level = 5 + + # Verify damage increased with level + assert_greater(tower.get_damage_at_current_level(), initial_damage) +``` + +**When to use:** +- Testing pure logic (math, state transitions) +- Testing Resource loading and property access +- Testing signal emission patterns + +--- + +### Integration Tests + +Test interactions between multiple systems. + +**Example:** Testing the full projectile launch sequence + +```gdscript +@tool +extends Node + +func test_projectile_launch_sequence() -> void: + # Arrange: Create mock tower and target + var tower := _create_mock_tower() + var target := _create_mock_target() + + # Act: Fire at target + tower.fire_at(target) + + # Assert: Verify projectile spawned in correct state + assert_true(tower.projectile_count == 1) + assert_equal(tower.projectiles[0].source_node, tower.$ProjectileSpawner) +``` + +**When to use:** +- Testing scene hierarchies with multiple nodes +- Verifying signal connections between systems +- Validating Godot's built-in component behavior (e.g., RigidBody2D movement) + +--- + +### Regression Tests + +Tests added when a bug is fixed to ensure it doesn't return. + +**Example:** Preventing physics tunneling after a collision fix + +```gdscript +@tool +extends Node + +func test_projectile_collision_prevents_tunneling() -> void: + # Scenario: Goose projectile moving at high speed + var projectile := _create_goose_with_velocity(100.0) + var enemy := _create_enemy_with_small_hitbox() + + # Act: Move projectile toward enemy's hitbox + projectile.yeet_from(projectile.position, enemy.position) + + # Assert: Projectile detected collision on this frame + assert_signal_emitted(projectile, 'collision_detected') +``` + +**When to use:** +- After fixing a critical bug +- When performance regression occurs +- To validate edge case handling + +--- + +## Writing Tests + +### Test Function Template + +```gdscript +@tool +extends Node + +func test_() -> void: + # Arrange: Setup the scenario + var := _create_mock_() + + # Act: Execute the action being tested + .() + + # Assert: Verify expected behavior + assert_true() + assert_false() + assert_signal_emitted(, '') +``` + +### Available Assertions + +| Assertion | Purpose | Example | +|-----------|---------|---------| +| `assert_equal(a, b)` | Check exact equality | `assert_equal(tower.level, 3)` | +| `assert_not_equal(a, b)` | Check inequality | `assert_not_equal(projectile.speed, 0.0)` | +| `assert_true(condition)` | Verify boolean is true | `assert_true(tower.is_ready())` | +| `assert_false(condition)` | Verify boolean is false | `assert_false(projectile.is_removed())` | +| `assert_greater(a, b)` | Check a > b | `assert_greater(damage_dealt, 10)` | +| `assert_less(a, b)` | Check a < b | `assert_less(enemy.health, 50.0)` | +| `assert_null(obj)` | Verify object is null | `assert_null(projectile.get_target())` | +| `assert_not_null(obj)` | Verify object exists | `assert_not_null(projectile)` | +| `assert_array_size(arr, size)` | Check array length | `assert_array_size(tower.projectiles, 4)` | + +### Signal Testing Pattern + +```gdscript +var _signal_verified = false + +func test_health_changed_signal_emits_correct_values() -> void: + var enemy := EnemyMob.new() + enemy.health_changed.connect(func(new_health) { + assert_true(_signal_verified == false) # Prevent double-firing + assert_equal(new_health, 75.0) + _signal_verified = true + }) + + enemy.take_damage(25.0) + + assert_true(_signal_verified) +``` + +### Mock Object Helpers + +Use these helper functions to create mock objects for tests: + +```gdscript +# Create a mock tower with minimal setup +func _create_mock_tower() -> Node: + var tower := TowerBase.new() + tower.tower_level = 1 + return tower + +# Create a mock enemy for collision testing +func _create_mock_enemy() -> EnemyMob: + var enemy := EnemyMob.new() + enemy.health = 50.0 + enemy.damage_taken.connect(func() { pass }) # Prevent death on damage + return enemy + +# Verify no error occurred during test +func _assert_no_error(condition: bool) -> void: + assert_true(condition, "Test completed with errors") +``` + +--- + +## Debugging Failed Tests + +### Common Failure Patterns + +#### 1. Test Completes Before Signal Fires + +**Problem:** `signal_emitted` verification fails because the test ends too early. + +**Solution:** Add a yield or use Godot's built-in coroutine system: + +```gdscript +func test_signal_fires_after_delay() -> void: + var subject := _create_subject() + subject.event.triggered.connect(_on_event_triggered) + + subject.do_something() + + # Ensure signal fires before test ends + get_tree().process_frame.connect(_on_frame_processed) + yield(get_tree(), "process_frame") # Wait for signal + + assert_true(_signal_received) + +func _on_frame_processed() -> void: + _on_event_triggered.call_deferred() +``` + +#### 2. Scene Loading in Tests Fails + +**Problem:** Godot scenes loaded via `load("res://...")` may not find their resources. + +**Solution:** Use absolute paths or ensure test assets are in proper location: + +```gdscript +# Bad: Relative path that breaks in tests +var mob_scene := load("enemy_mob.tscn").instantiate() + +# Good: Absolute resource path +var mob_scene := load("res://src/enemies/enemy_mob.tscn").instantiate() +``` + +#### 3. Random Behavior Causes Flaky Tests + +**Problem:** Tests pass sometimes but fail others due to randomness (e.g., particle emission). + +**Solution:** Disable randomness in test environment: + +```gdscript +# At start of test, seed RNG for reproducibility +Rand.randi = func() -> int: return 42 # Fixed value for testing + +# Or disable randomness for specific systems +var projectile := Projectile.new() +projectile.random_variation_enabled = false +``` + +#### 4. Physics Tunneling in Collision Tests + +**Problem:** Fast-moving projectiles miss collisions when tested with static enemies. + +**Solution:** Use multiple physics frames or smaller time steps: + +```gdscript +func test_high_velocity_collision_detection() -> void: + var projectile := _create_goose_with_velocity(200.0) + + # Run multiple physics frames for collision detection + for _ in range(5): + get_tree().physics_ticks_processed = 1 + get_tree().process_frame() + + assert_true(_collision_detected) +``` + +#### 5. Signal Connections Leak Between Tests + +**Problem:** Test A's signal handlers remain active when Test B runs. + +**Solution:** Disconnect signals at test end: + +```gdscript +func cleanup_test(subject: Node, signal_name: String) -> void: + subject.signal_removed.connect(_disconnect_signals) + + # Clear all signals from subject + var signals = subject.get_signal_list() + for s in signals: + if s.is_connected(func): + s.disconnect(func) + +# Call cleanup at end of each test function +``` + +--- + +## CI Integration (Optional for Indie Teams) + +### GitHub Actions / GitLab CI Setup + +If using a continuous integration server, add tests to build pipeline. + +**Example workflow:** + +```yaml +name: YeetGeese Tests + +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Godot + run: | + # Download and install Godot 4.x stable + + - name: Run Tests + run: | + godot --path . --headless tests/run_all_tests.gd +``` + +### Local Test Runner Script + +Create a script to run all tests from command line: + +```gdscript +# tests/run_all_tests.gd +extends Node + +func _ready(): + var result := 0 + + # Run unit tests + for file in DirAccess.get_directories() if dir_name == "core" or dir_name == "towers": + pass # Implementation depends on test runner framework + + if result == 0: + print("All tests passed!") + else: + error("Some tests failed") + +func _exit_tree(): + quit(0) +``` + +--- + +## Testing Checklist + +### Before Writing Tests for New Feature + +- [ ] Identify the system(s) being tested +- [ ] Determine unit vs. integration testing needs +- [ ] List expected inputs and outputs +- [ ] Identify edge cases (empty arrays, null objects, etc.) + +### Test Coverage Goals + +| System Type | Recommended Test Coverage | +|-------------|---------------------------| +| Core game loop | 100% (critical path) | +| Tower logic | 90%+ | +| Enemy AI states | 85%+ | +| UI displays | 80%+ | +| Utility functions | 95%+ | + +### Review Checklist for AI-Generated Tests + +When asking AI to generate tests, verify: + +- [ ] Uses `@tool` directive for editor-only execution +- [ ] Sets up proper mock objects for isolation +- [ ] Disconnects signals at test end to prevent leaks +- [ ] Uses absolute paths for resource loading +- [ ] Handles expected error conditions gracefully +- [ ] Includes assertions for all critical behaviors + +--- + +## Summary + +**AI can help with:** +- Generating boilerplate test scaffolding +- Suggesting edge cases and boundary conditions +- Writing mock implementations for complex systems +- Explaining Godot testing framework capabilities + +**Remember:** +- Tests should be runnable in editor (`@tool` functions) +- Keep tests focused on one behavior per function +- Disconnect signals to prevent cross-test contamination +- Use absolute paths for resource loading in tests +- Document test intent with clear, descriptive names + +For more details, see `AI_HELP.md` for prompt templates when working with AI assistants on testing tasks. diff --git a/AI Docs/05-SKILLS-REFERENCE.md b/AI Docs/05-SKILLS-REFERENCE.md new file mode 100644 index 0000000..0a7fe05 --- /dev/null +++ b/AI Docs/05-SKILLS-REFERENCE.md @@ -0,0 +1,547 @@ +# Skills, Agents, and Commands Reference + +This document provides a reference for AI assistants working with YeetGeese. It describes available capabilities, when to use them, and best practices for interaction. + +--- + +## Table of Contents + +1. [Available Skills](#available-skills) +2. [Agent Types & Use Cases](#agent-types--use-cases) +3. [Command Reference](#command-reference) +4. [Prompt Templates](#prompt-templates) +5. [Best Practices](#best-practices) + +--- + +## Available Skills + +### `customize-opencode` + +**Purpose:** Configure and modify the AI assistant's own settings, including: +- `opencode.json`, `opencode.jsonc` files +- `.opencode/` configuration directory +- `~/.config/opencode/` user settings +- Agent definitions (subagents, skills, plugins, MCP servers) +- Permission rules + +**When to use:** When configuring the AI assistant itself, not for project code. + +**Example:** +``` +"Adjust the maximum context window size for this session." +``` + +--- + +### `make-pr` — Pull Request Creation (Gitea Web UI) + +**Purpose:** On Gitea, pull requests are created directly via the web interface at: +`https://gitea.letteka.com/letteka/YeetGeese/pulls/new/move_docs` + +**How to use on Gitea:** +1. Push changes to a branch (e.g., `move_docs`) +2. Visit the URL above or navigate via Gitea web UI +3. Create PR with descriptive title and body +4. Include testing strategies and validation status in description + +**When to use:** +- When ready to submit a pull request from your current branch +- Before pushing code that requires peer review +- To ensure all changes are properly documented and validated +- When creating PRs for features, fixes, or refactoring + +**Best practices for Gitea PRs:** +- Use descriptive titles following conventional commits format +- Include file-by-file change summary in PR body +- List testing strategies: unit tests, integration tests, manual QA +- Mention any validation already performed locally +- Flag known issues or limitations clearly + +--- + +## Agent Types & Use Cases + +### `code-gen` — Code Generation + +**Purpose:** Write new code, implement features, create boilerplate. + +**Capabilities:** +- GDScript 4 implementation +- Scene graph construction descriptions +- Resource file (`.tres`) schema design +- Signal declarations and connections +- Method implementations matching project conventions + +**When to use:** +- Implementing a new tower or projectile type +- Adding a feature to existing systems +- Creating boilerplate for common patterns +- Writing unit tests + +**Input required:** +- Target file path or node description +- Desired behavior/goal +- Any constraints (e.g., "must use Resource for stats") + +**Example prompt:** +``` +"Create a GDScript 4 class `ImpactEffect.gd` that extends Area2D. It should: +1. Detect collision with enemies in _body_entered +2. Emit signal 'effect_triggered' with damage and target Node2D +3. Apply random color variation to its texture +4. Set lifespan to 0.8 seconds +5. Include comments explaining each step" +``` + +--- + +### `debug-helper` — Debugging Assistance + +**Purpose:** Analyze errors, suggest debugging strategies, interpret profiler output. + +**Capabilities:** +- Error message interpretation (Godot/IDE/compiler) +- Suggesting debugging tool usage (Scene Debugger, Physics Monitor) +- Profiling tips and bottleneck identification +- Common pitfall recognition (e.g., physics tunneling, navmesh gaps) + +**When to use:** +- When an error occurs during implementation +- When code behaves unexpectedly +- When performance issues appear in profiler + +**Input required:** +- Error message or log output +- Relevant file paths and line numbers if available +- Brief description of expected vs. actual behavior + +**Example prompt:** +``` +"This tower stops firing after 30 seconds even though fire_rate is set to 1.0. +Error: 'get_tree()' returned null at runtime. Debug it." +``` + +--- + +### `refactor-assistant` — Refactoring Support + +**Purpose:** Break up large scripts, improve code organization, add documentation. + +**Capabilities:** +- Splitting monolithic scripts into smaller nodes +- Extracting methods into separate components +- Adding documentation and type hints +- Applying project conventions consistently + +**When to use:** +- Scripts are growing beyond 150 lines +- Multiple unrelated behaviors in one node +- Need to improve readability before review + +**Input required:** +- File path or code snippet +- Refactoring goal (e.g., "split into state machines") +- Target organization style + +**Example prompt:** +``` +"Refactor this 400-line EnemyMob.gd into smaller components: +1. Extract navigation logic to NavigationComponent +2. Extract attack behavior to AttackState +3. Keep health/currency handling in base class +4. Add documentation comments for each section" +``` + +--- + +### `test-generator` — Test Generation + +**Purpose:** Create unit tests for game logic systems. + +**Capabilities:** +- Writing Godot test cases using `@tool` functions +- Setting up mock scenes and signals +- Testing Resource-based stat changes +- Validating collision detection and hit calculations + +**When to use:** +- After implementing core logic that should be validated +- Before refactoring (to preserve behavior) +- When adding critical game mechanics + +**Input required:** +- System or function being tested +- Expected inputs and outputs +- Edge cases to cover + +**Example prompt:** +``` +"Create tests for TowerBase._can_build_at(). Test: +1. Returns true in valid tower placement zones +2. Returns false inside enemy navmesh +3. Returns false when grid coordinate exceeds bounds +4. Returns false if parent node is null" +``` + +--- + +### `design-patterns` — Design Pattern Suggestions + +**Purpose:** Recommend architecture patterns suited to specific problems. + +**Capabilities:** +- Suggesting ECS for complex entity management +- Recommending FSM for enemy AI states +- Proposing event-driven systems for decoupled components +- Advising on data-oriented vs. object-oriented design + +**When to use:** +- Before implementing a new system +- When performance becomes an issue +- When refactoring existing code + +**Input required:** +- Problem description (e.g., "I need many entities with simple movement") +- Performance constraints if any +- Preferred Godot nodes or patterns already in use + +**Example prompt:** +``` +"I'm building a system for 50+ projectiles that need to track targets, apply damage, and handle collision. +Current approach: individual RigidBody2D for each projectile. +What pattern would scale better?" +``` + +--- + +### `balance-helper` — Balance Analysis + +**Purpose:** Analyze math relationships and suggest tuning adjustments. + +**Capabilities:** +- Calculating damage per second (DPS) from fire rate and projectile stats +- Estimating kill time based on enemy HP and total damage sources +- Suggesting resource stat ranges that preserve balance space +- Identifying scaling relationships between tower levels + +**When to use:** +- Before adding new towers/enemies with different power levels +- When gameplay feels too easy or difficult +- During tuning phase of wave progression + +**Input required:** +- Current stats (damage, fire rate, enemy HP) +- Desired behavior description (e.g., "kill time should scale with tier") +- Resource file structure if applicable + +**Example prompt:** +``` +"Current: goose damage=15, fire_rate=1.0/s, chicken HP=80. +Tower Level 2 has 4 geese. Calculate total DPS and suggest enemy HP range +for level-appropriate difficulty (aim for ~30s wave duration)." +``` + +--- + +### `level-design-helper` — Level Design Assistance + +**Purpose:** Plan layout, progression, and pacing for levels or zones. + +**Capabilities:** +- Wave progression suggestions (spawn rates, path complexity) +- Tower placement zone recommendations +- Pacing analysis for difficulty curves +- Zone-based checkpoint design + +**When to use:** +- Before creating a new level or wave sequence +- When gameplay feels too repetitive or frustrating +- During playtesting feedback analysis + +**Input required:** +- Level description (size, available zones) +- Current wave structure if any +- Difficulty curve goals + +**Example prompt:** +``` +"I have 4 tower placement zones along a path with 3 turns. +Current waves: linear difficulty increase. +Suggest a progression that introduces new mechanics at zone boundaries." +``` + +--- + +### `doc-generator` — Documentation Generation + +**Purpose:** Create documentation from existing code or planning data. + +**Capabilities:** +- Generating API docs from GDScript class structures +- Writing changelogs from commit history +- Creating release notes with feature summaries +- Producing onboarding guides from project structure + +**When to use:** +- Before releasing a version +- After implementing a major feature set +- When new team members join the project + +**Input required:** +- Source code or commit messages +- Feature list for changelog entries +- Target audience (developers, players) + +**Example prompt:** +``` +"Generate API documentation for the WaveRunner system: +1. Describe each public method and its parameters +2. List signals emitted with their payloads +3. Document the Resource dependencies +4. Include usage examples" +``` + +--- + +### `onboarding-guide` — Onboarding Documentation + +**Purpose:** Create setup tutorials and getting-started guides for new developers. + +**Capabilities:** +- Environment setup instructions (OS-specific) +- Project structure explanation +- Editor scene loading order +- Common first tasks with examples + +**When to use:** +- Before bringing on new team members +- When updating project structure significantly +- For release candidate documentation + +**Input required:** +- Target OS versions supported +- Required Godot version and plugins +- Team conventions to teach + +**Example prompt:** +``` +"Write an onboarding guide for a new developer joining YeetGeese: +1. Explain folder structure (src/core, src/towers, etc.) +2. Show how to run the game from main.tscn +3. Describe the tower placement workflow +4. List common commands for debugging" +``` + +--- + +### `api-specs` — API Specification + +**Purpose:** Define external interfaces and save/load contracts. + +**Capabilities:** +- Defining save file format schemas +- Documenting modding API endpoints +- Specifying network message protocols +- Creating serialization guides + +**When to use:** +- Before implementing persistent storage +- When enabling mod support +- For multiplayer networking design + +**Input required:** +- Interface type (save format, mod API, network protocol) +- Required functionality list +- Platform constraints + +**Example prompt:** +``` +"Define a save file format for YeetGeese: +1. Must store unlocked towers and their levels +2. Must include currency progress and wave number +3. Use Godot Resource serialization (.tres files) +4. Include version field for backward compatibility" +``` + +--- + +## Command Reference + +### Code Writing Commands + +| Command | When to use | +|---------|-------------| +| `create file ` | For new classes, scenes, or resource files | +| `modify file ` | For adding methods or changing existing code | +| `describe scene ` | To generate scene tree descriptions for AI understanding | + +### Review Commands + +| Command | When to use | +|---------|-------------| +| `review code ` | For checking convention compliance | +| `optimize performance ` | For profiling suggestions in specific areas | +| `debug error ` | For interpreting errors and suggesting fixes | + +### Documentation Commands + +| Command | When to use | +|---------|-------------| +| `generate docs` | For API documentation from code | +| `write changelog` | After implementing features or fixing bugs | +| `create onboarding guide` | For new developer setup instructions | + +--- + +## Prompt Templates + +### Feature Implementation Template + +``` +Context: I'm implementing [feature name] in [system/file]. +Current state: [brief description of existing code/structure] +Goal: [what this feature should do] +Constraints: [any restrictions like "must use Resource" or "no UI changes"] + +Please provide: +1. Complete, runnable GDScript 4 code with comments +2. Scene hierarchy description if new scenes are needed +3. Any new Resources (.tres) and their structure +4. Signal declarations and connection points +``` + +### Debugging Template + +``` +Error context: [where the error occurred] +Error message: [full error output] +Expected behavior: [what should have happened] +Actual behavior: [what actually happened] +Debug steps tried: [what you've already attempted] + +Please provide: +1. Root cause analysis +2. Minimal fix with explanation +3. Prevention strategy for future occurrences +``` + +### Refactoring Template + +``` +Current code: [file path or snippet] +Issues to address: [e.g., "too monolithic", "missing docs"] +Refactoring goals: [what you want to achieve] +Target patterns: [any existing patterns to match] + +Please provide: +1. Proposed refactored structure +2. New files and their responsibilities +3. Migration steps for existing code +``` + +--- + +## Best Practices + +### 1. Always Provide Context First + +Before asking for code, share: +- The relevant file path or node description +- The GDScript version being used (Godot 4.x) +- Key related signals and methods already in place + +**Good:** +``` +"Create an ImpactEffect.gd extending Area2D with these existing methods: +- _body_entered(var area): called on collision +- emit_signal('effect_triggered', damage, target)" +``` + +**Bad:** +``` +"I need a collision effect for projectiles." +``` + +### 2. Specify Godot 4 Conventions + +When requesting code, remind AI of conventions: +- Use typed signals: `signal health_changed(new_health: float)` +- Prefer `@onready` over `$` in scripts +- Type variables and return values consistently +- Keep scenes modular (compose behavior across nodes) + +### 3. Reference Existing Architecture + +When implementing features, reference existing patterns: +``` +"Implement this using the same pattern as TowerBase.fire_at(): +- Use projectile_res.instantiate() for new goose projectiles +- Spawn from $ProjectileSpawner.global_position +- Add to parent tree immediately after instantiation" +``` + +### 4. Specify Resource Dependencies Early + +If your project uses Resources for balance: +``` +"Create a Resource-based stats file for this tower: +- Fields: damage (float), fire_rate (float), cooldown_reduction (float) +- Make it loadable as a Godot Resource (.tres) +- Show how the tower reads its stats on _ready()" +``` + +### 5. Ask for Complete, Runnable Code + +When requesting implementations: +``` +"Return complete, runnable GDScript 4 code with:" +"- Comments explaining each major section" +"- Type annotations for all variables and methods" +"- Signal declarations at top of class" +``` + +--- + +## Summary + +**Use these skills strategically:** +- `code-gen`: For new features and boilerplate +- `debug-helper`: When errors occur or behavior is wrong +- `refactor-assistant`: Before code grows unmanageable +- `test-generator`: After implementing critical logic +- `design-patterns`: When architecture becomes unclear + +**Always provide:** +- File paths, node names, and Godot version context +- Desired behavior in terms of existing patterns +- Constraints (Resource usage, signal conventions) + +**When in doubt:** Reference `AI_HELP.md` for project-specific conventions before asking questions. + +--- + +## Note About `make-pr` Skill Availability + +The **`make-pr`** skill (`.opencode/skills/make-pr.json`) is available for use! This skill will: +- Generate comprehensive, human-readable PR descriptions +- List testing strategies for each change area +- Validate changes before PR creation +- Format PR descriptions with clear sections + +**When to use `make-pr` skill:** +- When ready to submit a PR from your current branch (any platform) +- Before pushing code that requires peer review +- To ensure all changes are properly documented and validated +- When creating PRs for features, fixes, or refactoring + +The skill automatically adapts to your hosting platform: +- **GitHub:** Creates PR via API with comprehensive descriptions +- **Gitea:** Falls back to web UI creation (URL provided above) + +**Prompt example:** +``` +"Create a pull request from move_docs to develop. The changes include moving +all AI documentation files into an 'AI Docs' folder with organized structure." +``` + diff --git a/AI Docs/PLAN.md b/AI Docs/PLAN.md new file mode 100644 index 0000000..53ede15 --- /dev/null +++ b/AI Docs/PLAN.md @@ -0,0 +1,1445 @@ +Here is a practical phase plan for **YeetGeese**, a first-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 a first-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. First-Person Player Controller +Create a first-person 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: first-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 first-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 first-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. + - First-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. First-Person + 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 first-person 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. \ No newline at end of file diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..c6bbb7d --- /dev/null +++ b/icon.svg @@ -0,0 +1 @@ + diff --git a/project.godot b/project.godot index 14ce97a..1cbc80f 100644 --- a/project.godot +++ b/project.godot @@ -13,10 +13,6 @@ config_version=5 config/name="Yeet Geese" config/features=PackedStringArray("4.7") -[autoload] - -GdUnit4Runner="*uid://biafu03jsb7lh" - [display] window/stretch/mode="canvas_items" @@ -24,7 +20,7 @@ window/stretch/aspect="expand" [editor_plugins] -enabled=PackedStringArray("res://addons/gdUnit4/plugin.cfg") +enabled=PackedStringArray() [physics]