Feature/expansionpack 2d unity game dev (#332)
* Added 1.0 files * Converted agents, and templates to new format. Updated filenames to include extensions like in unity-2d-game-team.yaml, Updated some wordage in workflow, config, and increased minor version number * Forgot to remove unused startup section in game-sm since it's moved to activation-instructions, now fixed. * Updated verbosity for development workflow in development-guidenlines.md * built the web-dist files for the expansion pack * Synched with main repo and rebuilt dist * Added enforcement of game-design-checklist to designer persona * Updated with new changes to phaser epack that seem relevant to discussion we had on discord for summarizing documentation updates * updated dist build for our epack
This commit is contained in:
251
expansion-packs/bmad-2d-unity-game-dev/data/bmad-kb.md
Normal file
251
expansion-packs/bmad-2d-unity-game-dev/data/bmad-kb.md
Normal file
@@ -0,0 +1,251 @@
|
||||
# Game Development BMad Knowledge Base
|
||||
|
||||
## Overview
|
||||
|
||||
This game development expansion of BMad-Method specializes in creating 2D games using Unity and C#. It extends the core BMad framework with game-specific agents, workflows, and best practices for professional game development.
|
||||
|
||||
### Game Development Focus
|
||||
|
||||
- **Target Engine**: Unity 2022 LTS or newer with C# 10+
|
||||
- **Platform Strategy**: Cross-platform (PC, Console, Mobile) with a focus on 2D
|
||||
- **Development Approach**: Agile story-driven development
|
||||
- **Performance Target**: Stable frame rate on target devices
|
||||
- **Architecture**: Component-based architecture using Unity's best practices
|
||||
|
||||
## Core Game Development Philosophy
|
||||
|
||||
### Player-First Development
|
||||
|
||||
You are developing games as a "Player Experience CEO" - thinking like a game director with unlimited creative resources and a singular vision for player enjoyment. Your AI agents are your specialized game development team:
|
||||
|
||||
- **Direct**: Provide clear game design vision and player experience goals
|
||||
- **Refine**: Iterate on gameplay mechanics until they're compelling
|
||||
- **Oversee**: Maintain creative alignment across all development disciplines
|
||||
- **Playfocus**: Every decision serves the player experience
|
||||
|
||||
### Game Development Principles
|
||||
|
||||
1. **PLAYER_EXPERIENCE_FIRST**: Every mechanic must serve player engagement and fun
|
||||
2. **ITERATIVE_DESIGN**: Prototype, test, refine - games are discovered through iteration
|
||||
3. **TECHNICAL_EXCELLENCE**: Stable performance and cross-platform compatibility are non-negotiable
|
||||
4. **STORY_DRIVEN_DEV**: Game features are implemented through detailed development stories
|
||||
5. **BALANCE_THROUGH_DATA**: Use metrics and playtesting to validate game balance
|
||||
6. **DOCUMENT_EVERYTHING**: Clear specifications enable proper game implementation
|
||||
7. **START_SMALL_ITERATE_FAST**: Core mechanics first, then expand and polish
|
||||
8. **EMBRACE_CREATIVE_CHAOS**: Games evolve - adapt design based on what's fun
|
||||
|
||||
## Game Development Workflow
|
||||
|
||||
### Phase 1: Game Concept and Design
|
||||
|
||||
1. **Game Designer**: Start with brainstorming and concept development
|
||||
|
||||
- Use \*brainstorm to explore game concepts and mechanics
|
||||
- Create Game Brief using game-brief-tmpl
|
||||
- Develop core game pillars and player experience goals
|
||||
|
||||
2. **Game Designer**: Create comprehensive Game Design Document
|
||||
|
||||
- Use game-design-doc-tmpl to create detailed GDD
|
||||
- Define all game mechanics, progression, and balance
|
||||
- Specify technical requirements and platform targets
|
||||
|
||||
3. **Game Designer**: Develop Level Design Framework
|
||||
- Create level-design-doc-tmpl for content guidelines
|
||||
- Define level types, difficulty progression, and content structure
|
||||
- Establish performance and technical constraints for levels
|
||||
|
||||
### Phase 2: Technical Architecture
|
||||
|
||||
4. **Solution Architect** (or Game Designer): Create Technical Architecture
|
||||
- Use game-architecture-tmpl to design technical implementation
|
||||
- Define Unity systems, performance optimization, and C# code structure
|
||||
- Align technical architecture with game design requirements
|
||||
|
||||
### Phase 3: Story-Driven Development
|
||||
|
||||
5. **Game Scrum Master**: Break down design into development stories
|
||||
|
||||
- Use create-game-story task to create detailed implementation stories
|
||||
- Each story should be immediately actionable by game developers
|
||||
- Apply game-story-dod-checklist to ensure story quality
|
||||
|
||||
6. **Game Developer**: Implement game features story by story
|
||||
|
||||
- Follow C# best practices and Unity's component-based architecture
|
||||
- Maintain stable frame rate on target devices
|
||||
- Use Unity Test Framework for game logic components
|
||||
|
||||
7. **Iterative Refinement**: Continuous playtesting and improvement
|
||||
- Test core mechanics early and often in the Unity Editor
|
||||
- Validate game balance through metrics and player feedback
|
||||
- Iterate on design based on implementation discoveries
|
||||
|
||||
## Game-Specific Development Guidelines
|
||||
|
||||
### Unity + C# Standards
|
||||
|
||||
**Project Structure:**
|
||||
|
||||
```text
|
||||
UnityProject/
|
||||
├── Assets/
|
||||
│ ├── Scenes/ # Game scenes (Boot, Menu, Game, etc.)
|
||||
│ ├── Scripts/ # C# scripts
|
||||
│ │ ├── Editor/ # Editor-specific scripts
|
||||
│ │ └── Runtime/ # Runtime scripts
|
||||
│ ├── Prefabs/ # Reusable game objects
|
||||
│ ├── Art/ # Art assets (sprites, models, etc.)
|
||||
│ ├── Audio/ # Audio assets
|
||||
│ ├── Data/ # ScriptableObjects and other data
|
||||
│ └── Tests/ # Unity Test Framework tests
|
||||
│ ├── EditMode/
|
||||
│ └── PlayMode/
|
||||
├── Packages/ # Package Manager manifest
|
||||
└── ProjectSettings/ # Unity project settings
|
||||
```
|
||||
|
||||
**Performance Requirements:**
|
||||
|
||||
- Maintain stable frame rate on target devices
|
||||
- Memory usage under specified limits per level
|
||||
- Loading times under 3 seconds for levels
|
||||
- Smooth animation and responsive controls
|
||||
|
||||
**Code Quality:**
|
||||
|
||||
- C# best practices compliance
|
||||
- Component-based architecture (SOLID principles)
|
||||
- Efficient use of the MonoBehaviour lifecycle
|
||||
- Error handling and graceful degradation
|
||||
|
||||
### Game Development Story Structure
|
||||
|
||||
**Story Requirements:**
|
||||
|
||||
- Clear reference to Game Design Document section
|
||||
- Specific acceptance criteria for game functionality
|
||||
- Technical implementation details for Unity and C#
|
||||
- Performance requirements and optimization considerations
|
||||
- Testing requirements including gameplay validation
|
||||
|
||||
**Story Categories:**
|
||||
|
||||
- **Core Mechanics**: Fundamental gameplay systems
|
||||
- **Level Content**: Individual levels and content implementation
|
||||
- **UI/UX**: User interface and player experience features
|
||||
- **Performance**: Optimization and technical improvements
|
||||
- **Polish**: Visual effects, audio, and game feel enhancements
|
||||
|
||||
### Quality Assurance for Games
|
||||
|
||||
**Testing Approach:**
|
||||
|
||||
- Unit tests for C# logic (EditMode tests)
|
||||
- Integration tests for game systems (PlayMode tests)
|
||||
- Performance benchmarking and profiling with Unity Profiler
|
||||
- Gameplay testing and balance validation
|
||||
- Cross-platform compatibility testing
|
||||
|
||||
**Performance Monitoring:**
|
||||
|
||||
- Frame rate consistency tracking
|
||||
- Memory usage monitoring
|
||||
- Asset loading performance
|
||||
- Input responsiveness validation
|
||||
- Battery usage optimization (mobile)
|
||||
|
||||
## Game Development Team Roles
|
||||
|
||||
### Game Designer (Alex)
|
||||
|
||||
- **Primary Focus**: Game mechanics, player experience, design documentation
|
||||
- **Key Outputs**: Game Brief, Game Design Document, Level Design Framework
|
||||
- **Specialties**: Brainstorming, game balance, player psychology, creative direction
|
||||
|
||||
### Game Developer (Maya)
|
||||
|
||||
- **Primary Focus**: Unity implementation, C# excellence, performance
|
||||
- **Key Outputs**: Working game features, optimized code, technical architecture
|
||||
- **Specialties**: C#/Unity, performance optimization, cross-platform development
|
||||
|
||||
### Game Scrum Master (Jordan)
|
||||
|
||||
- **Primary Focus**: Story creation, development planning, agile process
|
||||
- **Key Outputs**: Detailed implementation stories, sprint planning, quality assurance
|
||||
- **Specialties**: Story breakdown, developer handoffs, process optimization
|
||||
|
||||
## Platform-Specific Considerations
|
||||
|
||||
### Cross-Platform Development
|
||||
|
||||
- Abstract input using the new Input System
|
||||
- Use platform-dependent compilation for specific logic
|
||||
- Test on all target platforms regularly
|
||||
- Optimize for different screen resolutions and aspect ratios
|
||||
|
||||
### Mobile Optimization
|
||||
|
||||
- Touch gesture support and responsive controls
|
||||
- Battery usage optimization
|
||||
- Performance scaling for different device capabilities
|
||||
- App store compliance and packaging
|
||||
|
||||
### Performance Targets
|
||||
|
||||
- **PC/Console**: 60+ FPS at target resolution
|
||||
- **Mobile**: 60 FPS on mid-range devices, 30 FPS minimum on low-end
|
||||
- **Loading**: Initial load under 5 seconds, scene transitions under 2 seconds
|
||||
- **Memory**: Within platform-specific memory budgets
|
||||
|
||||
## Success Metrics for Game Development
|
||||
|
||||
### Technical Metrics
|
||||
|
||||
- Frame rate consistency (>90% of time at target FPS)
|
||||
- Memory usage within budgets
|
||||
- Loading time targets met
|
||||
- Zero critical bugs in core gameplay systems
|
||||
|
||||
### Player Experience Metrics
|
||||
|
||||
- Tutorial completion rate >80%
|
||||
- Level completion rates appropriate for difficulty curve
|
||||
- Average session length meets design targets
|
||||
- Player retention and engagement metrics
|
||||
|
||||
### Development Process Metrics
|
||||
|
||||
- Story completion within estimated timeframes
|
||||
- Code quality metrics (test coverage, code analysis)
|
||||
- Documentation completeness and accuracy
|
||||
- Team velocity and delivery consistency
|
||||
|
||||
## Common Unity Development Patterns
|
||||
|
||||
### Scene Management
|
||||
|
||||
- Use a loading scene for asynchronous loading of game scenes
|
||||
- Use additive scene loading for large levels or streaming
|
||||
- Manage scenes with a dedicated SceneManager class
|
||||
|
||||
### Game State Management
|
||||
|
||||
- Use ScriptableObjects to store shared game state
|
||||
- Implement a finite state machine (FSM) for complex behaviors
|
||||
- Use a GameManager singleton for global state management
|
||||
|
||||
### Input Handling
|
||||
|
||||
- Use the new Input System for robust, cross-platform input
|
||||
- Create Action Maps for different input contexts (e.g., menu, gameplay)
|
||||
- Use PlayerInput component for easy player input handling
|
||||
|
||||
### Performance Optimization
|
||||
|
||||
- Object pooling for frequently instantiated objects (e.g., bullets, enemies)
|
||||
- Use the Unity Profiler to identify performance bottlenecks
|
||||
- Optimize physics settings and collision detection
|
||||
- Use LOD (Level of Detail) for complex models
|
||||
|
||||
This knowledge base provides the foundation for effective game development using the BMad-Method framework with specialized focus on 2D game creation using Unity and C#.
|
||||
@@ -0,0 +1,568 @@
|
||||
# Game Development Guidelines (Unity & C#)
|
||||
|
||||
## Overview
|
||||
|
||||
This document establishes coding standards, architectural patterns, and development practices for 2D game development using Unity and C#. These guidelines ensure consistency, performance, and maintainability across all game development stories.
|
||||
|
||||
## C# Standards
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
**Classes, Structs, Enums, and Interfaces:**
|
||||
- PascalCase for types: `PlayerController`, `GameData`, `IInteractable`
|
||||
- Prefix interfaces with 'I': `IDamageable`, `IControllable`
|
||||
- Descriptive names that indicate purpose: `GameStateManager` not `GSM`
|
||||
|
||||
**Methods and Properties:**
|
||||
- PascalCase for methods and properties: `CalculateScore()`, `CurrentHealth`
|
||||
- Descriptive verb phrases for methods: `ActivateShield()` not `shield()`
|
||||
|
||||
**Fields and Variables:**
|
||||
- `private` or `protected` fields: camelCase with an underscore prefix: `_playerHealth`, `_movementSpeed`
|
||||
- `public` fields (use sparingly, prefer properties): PascalCase: `PlayerName`
|
||||
- `static` fields: PascalCase: `Instance`, `GameVersion`
|
||||
- `const` fields: PascalCase: `MaxHitPoints`
|
||||
- `local` variables: camelCase: `damageAmount`, `isJumping`
|
||||
- Boolean variables with is/has/can prefix: `_isAlive`, `_hasKey`, `_canJump`
|
||||
|
||||
**Files and Directories:**
|
||||
- PascalCase for C# script files, matching the primary class name: `PlayerController.cs`
|
||||
- PascalCase for Scene files: `MainMenu.unity`, `Level01.unity`
|
||||
|
||||
### Style and Formatting
|
||||
|
||||
- **Braces**: Use Allman style (braces on a new line).
|
||||
- **Spacing**: Use 4 spaces for indentation (no tabs).
|
||||
- **`using` directives**: Place all `using` directives at the top of the file, outside the namespace.
|
||||
- **`this` keyword**: Only use `this` when necessary to distinguish between a field and a local variable/parameter.
|
||||
|
||||
## Unity Architecture Patterns
|
||||
|
||||
### Scene Lifecycle Management
|
||||
**Loading and Transitioning Between Scenes:**
|
||||
```csharp
|
||||
// SceneLoader.cs - A singleton for managing scene transitions.
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using System.Collections;
|
||||
|
||||
public class SceneLoader : MonoBehaviour
|
||||
{
|
||||
public static SceneLoader Instance { get; private set; }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
|
||||
public void LoadGameScene()
|
||||
{
|
||||
// Example of loading the main game scene, perhaps with a loading screen first.
|
||||
StartCoroutine(LoadSceneAsync("Level01"));
|
||||
}
|
||||
|
||||
private IEnumerator LoadSceneAsync(string sceneName)
|
||||
{
|
||||
// Load a loading screen first (optional)
|
||||
SceneManager.LoadScene("LoadingScreen");
|
||||
|
||||
// Wait a frame for the loading screen to appear
|
||||
yield return null;
|
||||
|
||||
// Begin loading the target scene in the background
|
||||
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName);
|
||||
|
||||
// Don't activate the scene until it's fully loaded
|
||||
asyncLoad.allowSceneActivation = false;
|
||||
|
||||
// Wait until the asynchronous scene fully loads
|
||||
while (!asyncLoad.isDone)
|
||||
{
|
||||
// Here you could update a progress bar with asyncLoad.progress
|
||||
if (asyncLoad.progress >= 0.9f)
|
||||
{
|
||||
// Scene is loaded, allow activation
|
||||
asyncLoad.allowSceneActivation = true;
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### MonoBehaviour Lifecycle
|
||||
**Understanding Core MonoBehaviour Events:**
|
||||
```csharp
|
||||
// Example of a standard MonoBehaviour lifecycle
|
||||
using UnityEngine;
|
||||
|
||||
public class PlayerController : MonoBehaviour
|
||||
{
|
||||
// AWAKE: Called when the script instance is being loaded.
|
||||
// Use for initialization before the game starts. Good for caching component references.
|
||||
private void Awake()
|
||||
{
|
||||
Debug.Log("PlayerController Awake!");
|
||||
}
|
||||
|
||||
// ONENABLE: Called when the object becomes enabled and active.
|
||||
// Good for subscribing to events.
|
||||
private void OnEnable()
|
||||
{
|
||||
// Example: UIManager.OnGamePaused += HandleGamePaused;
|
||||
}
|
||||
|
||||
// START: Called on the frame when a script is enabled just before any of the Update methods are called the first time.
|
||||
// Good for logic that depends on other objects being initialized.
|
||||
private void Start()
|
||||
{
|
||||
Debug.Log("PlayerController Start!");
|
||||
}
|
||||
|
||||
// FIXEDUPDATE: Called every fixed framerate frame.
|
||||
// Use for physics calculations (e.g., applying forces to a Rigidbody).
|
||||
private void FixedUpdate()
|
||||
{
|
||||
// Handle Rigidbody movement here.
|
||||
}
|
||||
|
||||
// UPDATE: Called every frame.
|
||||
// Use for most game logic, like handling input and non-physics movement.
|
||||
private void Update()
|
||||
{
|
||||
// Handle input and non-physics movement here.
|
||||
}
|
||||
|
||||
// LATEUPDATE: Called every frame, after all Update functions have been called.
|
||||
// Good for camera logic that needs to track a target that moves in Update.
|
||||
private void LateUpdate()
|
||||
{
|
||||
// Camera follow logic here.
|
||||
}
|
||||
|
||||
// ONDISABLE: Called when the behaviour becomes disabled or inactive.
|
||||
// Good for unsubscribing from events to prevent memory leaks.
|
||||
private void OnDisable()
|
||||
{
|
||||
// Example: UIManager.OnGamePaused -= HandleGamePaused;
|
||||
}
|
||||
|
||||
// ONDESTROY: Called when the MonoBehaviour will be destroyed.
|
||||
// Good for any final cleanup.
|
||||
private void OnDestroy()
|
||||
{
|
||||
Debug.Log("PlayerController Destroyed!");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Game Object Patterns
|
||||
|
||||
**Component-Based Architecture:**
|
||||
```csharp
|
||||
// Player.cs - The main GameObject class, acts as a container for components.
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(PlayerMovement), typeof(PlayerHealth))]
|
||||
public class Player : MonoBehaviour
|
||||
{
|
||||
public PlayerMovement Movement { get; private set; }
|
||||
public PlayerHealth Health { get; private set; }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Movement = GetComponent<PlayerMovement>();
|
||||
Health = GetComponent<PlayerHealth>();
|
||||
}
|
||||
}
|
||||
|
||||
// PlayerHealth.cs - A component responsible only for health logic.
|
||||
public class PlayerHealth : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private int _maxHealth = 100;
|
||||
private int _currentHealth;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_currentHealth = _maxHealth;
|
||||
}
|
||||
|
||||
public void TakeDamage(int amount)
|
||||
{
|
||||
_currentHealth -= amount;
|
||||
if (_currentHealth <= 0)
|
||||
{
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
private void Die()
|
||||
{
|
||||
// Death logic
|
||||
Debug.Log("Player has died.");
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Data-Driven Design with ScriptableObjects
|
||||
|
||||
**Define Data Containers:**
|
||||
```csharp
|
||||
// EnemyData.cs - A ScriptableObject to hold data for an enemy type.
|
||||
using UnityEngine;
|
||||
|
||||
[CreateAssetMenu(fileName = "NewEnemyData", menuName = "Game/Enemy Data")]
|
||||
public class EnemyData : ScriptableObject
|
||||
{
|
||||
public string enemyName;
|
||||
public int maxHealth;
|
||||
public float moveSpeed;
|
||||
public int damage;
|
||||
public Sprite sprite;
|
||||
}
|
||||
|
||||
// Enemy.cs - A MonoBehaviour that uses the EnemyData.
|
||||
public class Enemy : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private EnemyData _enemyData;
|
||||
private int _currentHealth;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_currentHealth = _enemyData.maxHealth;
|
||||
GetComponent<SpriteRenderer>().sprite = _enemyData.sprite;
|
||||
}
|
||||
|
||||
// ... other enemy logic
|
||||
}
|
||||
```
|
||||
|
||||
### System Management
|
||||
|
||||
**Singleton Managers:**
|
||||
```csharp
|
||||
// GameManager.cs - A singleton to manage the overall game state.
|
||||
using UnityEngine;
|
||||
|
||||
public class GameManager : MonoBehaviour
|
||||
{
|
||||
public static GameManager Instance { get; private set; }
|
||||
|
||||
public int Score { get; private set; }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
DontDestroyOnLoad(gameObject); // Persist across scenes
|
||||
}
|
||||
|
||||
public void AddScore(int amount)
|
||||
{
|
||||
Score += amount;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Object Pooling
|
||||
|
||||
**Required for High-Frequency Objects (e.g., bullets, effects):**
|
||||
```csharp
|
||||
// ObjectPool.cs - A generic object pooling system.
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class ObjectPool : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private GameObject _prefabToPool;
|
||||
[SerializeField] private int _initialPoolSize = 20;
|
||||
|
||||
private Queue<GameObject> _pool = new Queue<GameObject>();
|
||||
|
||||
private void Start()
|
||||
{
|
||||
for (int i = 0; i < _initialPoolSize; i++)
|
||||
{
|
||||
GameObject obj = Instantiate(_prefabToPool);
|
||||
obj.SetActive(false);
|
||||
_pool.Enqueue(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public GameObject GetObjectFromPool()
|
||||
{
|
||||
if (_pool.Count > 0)
|
||||
{
|
||||
GameObject obj = _pool.Dequeue();
|
||||
obj.SetActive(true);
|
||||
return obj;
|
||||
}
|
||||
// Optionally, expand the pool if it's empty.
|
||||
return Instantiate(_prefabToPool);
|
||||
}
|
||||
|
||||
public void ReturnObjectToPool(GameObject obj)
|
||||
{
|
||||
obj.SetActive(false);
|
||||
_pool.Enqueue(obj);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Frame Rate Optimization
|
||||
|
||||
**Update Loop Optimization:**
|
||||
- Avoid expensive calls like `GetComponent`, `FindObjectOfType`, or `Instantiate` inside `Update()` or `FixedUpdate()`. Cache references in `Awake()` or `Start()`.
|
||||
- Use Coroutines or simple timers for logic that doesn't need to run every single frame.
|
||||
|
||||
**Physics Optimization:**
|
||||
- Adjust the "Physics 2D Settings" in Project Settings, especially the "Layer Collision Matrix", to prevent unnecessary collision checks.
|
||||
- Use `Rigidbody2D.Sleep()` for objects that are not moving to save CPU cycles.
|
||||
|
||||
## Input Handling
|
||||
|
||||
### Cross-Platform Input (New Input System)
|
||||
|
||||
**Input Action Asset:** Create an Input Action Asset (`.inputactions`) to define controls.
|
||||
|
||||
**PlayerInput Component:**
|
||||
- Add the `PlayerInput` component to the player GameObject.
|
||||
- Set its "Actions" to the created Input Action Asset.
|
||||
- Set "Behavior" to "Invoke Unity Events" to easily hook up methods in the Inspector, or "Send Messages" to use methods like `OnMove`, `OnFire`.
|
||||
|
||||
```csharp
|
||||
// PlayerInputHandler.cs - Example of handling input via messages.
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
public class PlayerInputHandler : MonoBehaviour
|
||||
{
|
||||
private Vector2 _moveInput;
|
||||
|
||||
// This method is called by the PlayerInput component via "Send Messages".
|
||||
// The action must be named "Move" in the Input Action Asset.
|
||||
public void OnMove(InputValue value)
|
||||
{
|
||||
_moveInput = value.Get<Vector2>();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// Use _moveInput to control the player
|
||||
transform.Translate(new Vector3(_moveInput.x, _moveInput.y, 0) * Time.deltaTime * 5f);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Graceful Degradation
|
||||
|
||||
**Asset Loading Error Handling:**
|
||||
- When using Addressables or `Resources.Load`, always check if the loaded asset is null before using it.
|
||||
```csharp
|
||||
// Load a sprite and use a fallback if it fails
|
||||
Sprite playerSprite = Resources.Load<Sprite>("Sprites/Player");
|
||||
if (playerSprite == null)
|
||||
{
|
||||
Debug.LogError("Player sprite not found! Using default.");
|
||||
playerSprite = Resources.Load<Sprite>("Sprites/Default");
|
||||
}
|
||||
```
|
||||
|
||||
### Runtime Error Recovery
|
||||
|
||||
**Assertions and Logging:**
|
||||
- Use `Debug.Assert(condition, "Message")` to check for critical conditions that must be true.
|
||||
- Use `Debug.LogError("Message")` for fatal errors and `Debug.LogWarning("Message")` for non-critical issues.
|
||||
```csharp
|
||||
// Example of using an assertion to ensure a component exists.
|
||||
private Rigidbody2D _rb;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_rb = GetComponent<Rigidbody2D>();
|
||||
Debug.Assert(_rb != null, "Rigidbody2D component not found on player!");
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Standards
|
||||
|
||||
### Unit Testing (Edit Mode)
|
||||
|
||||
**Game Logic Testing:**
|
||||
```csharp
|
||||
// HealthSystemTests.cs - Example test for a simple health system.
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
public class HealthSystemTests
|
||||
{
|
||||
[Test]
|
||||
public void TakeDamage_ReducesHealth()
|
||||
{
|
||||
// Arrange
|
||||
var gameObject = new GameObject();
|
||||
var healthSystem = gameObject.AddComponent<PlayerHealth>();
|
||||
// Note: This is a simplified example. You might need to mock dependencies.
|
||||
|
||||
// Act
|
||||
healthSystem.TakeDamage(20);
|
||||
|
||||
// Assert
|
||||
// This requires making health accessible for testing, e.g., via a public property or method.
|
||||
// Assert.AreEqual(80, healthSystem.CurrentHealth);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Integration Testing (Play Mode)
|
||||
|
||||
**Scene Testing:**
|
||||
- Play Mode tests run in a live scene, allowing you to test interactions between multiple components and systems.
|
||||
- Use `yield return null;` to wait for the next frame.
|
||||
```csharp
|
||||
// PlayerJumpTest.cs
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
public class PlayerJumpTest
|
||||
{
|
||||
[UnityTest]
|
||||
public IEnumerator PlayerJumps_WhenSpaceIsPressed()
|
||||
{
|
||||
// Arrange
|
||||
var player = new GameObject().AddComponent<PlayerController>();
|
||||
var initialY = player.transform.position.y;
|
||||
|
||||
// Act
|
||||
// Simulate pressing the jump button (requires setting up the input system for tests)
|
||||
// For simplicity, we'll call a public method here.
|
||||
// player.Jump();
|
||||
|
||||
// Wait for a few physics frames
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
|
||||
// Assert
|
||||
Assert.Greater(player.transform.position.y, initialY);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## File Organization
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
Assets/
|
||||
├── Scenes/
|
||||
│ ├── MainMenu.unity
|
||||
│ └── Level01.unity
|
||||
├── Scripts/
|
||||
│ ├── Core/
|
||||
│ │ ├── GameManager.cs
|
||||
│ │ └── AudioManager.cs
|
||||
│ ├── Player/
|
||||
│ │ ├── PlayerController.cs
|
||||
│ │ └── PlayerHealth.cs
|
||||
│ ├── Editor/
|
||||
│ │ └── CustomInspectors.cs
|
||||
│ └── Data/
|
||||
│ └── EnemyData.cs
|
||||
├── Prefabs/
|
||||
│ ├── Player.prefab
|
||||
│ └── Enemies/
|
||||
│ └── Slime.prefab
|
||||
├── Art/
|
||||
│ ├── Sprites/
|
||||
│ └── Animations/
|
||||
├── Audio/
|
||||
│ ├── Music/
|
||||
│ └── SFX/
|
||||
├── Data/
|
||||
│ └── ScriptableObjects/
|
||||
│ └── EnemyData/
|
||||
└── Tests/
|
||||
├── EditMode/
|
||||
│ └── HealthSystemTests.cs
|
||||
└── PlayMode/
|
||||
└── PlayerJumpTest.cs
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Story Implementation Process
|
||||
|
||||
1. **Read Story Requirements:**
|
||||
|
||||
- Understand acceptance criteria
|
||||
- Identify technical requirements
|
||||
- Review performance constraints
|
||||
|
||||
2. **Plan Implementation:**
|
||||
|
||||
- Identify files to create/modify
|
||||
- Consider Unity's component-based architecture
|
||||
- Plan testing approach
|
||||
|
||||
3. **Implement Feature:**
|
||||
|
||||
- Write clean C# code following all guidelines
|
||||
- Use established patterns
|
||||
- Maintain stable FPS performance
|
||||
|
||||
4. **Test Implementation:**
|
||||
|
||||
- Write edit mode tests for game logic
|
||||
- Write play mode tests for integration testing
|
||||
- Test cross-platform functionality
|
||||
- Validate performance targets
|
||||
|
||||
5. **Update Documentation:**
|
||||
- Mark story checkboxes complete
|
||||
- Document any deviations
|
||||
- Update architecture if needed
|
||||
|
||||
### Code Review Checklist
|
||||
|
||||
- [ ] C# code compiles without errors or warnings.
|
||||
- [ ] All automated tests pass.
|
||||
- [ ] Code follows naming conventions and architectural patterns.
|
||||
- [ ] No expensive operations in `Update()` loops.
|
||||
- [ ] Public fields/methods are documented with comments.
|
||||
- [ ] New assets are organized into the correct folders.
|
||||
|
||||
## Performance Targets
|
||||
|
||||
### Frame Rate Requirements
|
||||
|
||||
- **PC/Console**: Maintain a stable 60+ FPS.
|
||||
- **Mobile**: Maintain 60 FPS on mid-range devices, minimum 30 FPS on low-end.
|
||||
- **Optimization**: Use the Unity Profiler to identify and fix performance drops.
|
||||
|
||||
### Memory Management
|
||||
|
||||
- **Total Memory**: Keep builds under platform-specific limits (e.g., 200MB for a simple mobile game).
|
||||
- **Garbage Collection**: Minimize GC spikes by avoiding string concatenation, `new` keyword usage in loops, and by pooling objects.
|
||||
|
||||
### Loading Performance
|
||||
|
||||
- **Initial Load**: Under 5 seconds for game start.
|
||||
- **Scene Transitions**: Under 2 seconds between scenes. Use asynchronous scene loading.
|
||||
|
||||
These guidelines ensure consistent, high-quality game development that meets performance targets and maintains code quality across all implementation stories.
|
||||
Reference in New Issue
Block a user