435 lines
11 KiB
Markdown
435 lines
11 KiB
Markdown
# GECS Troubleshooting Guide
|
|
|
|
> **Quickly solve common GECS issues**
|
|
|
|
This guide helps you diagnose and fix the most common problems when working with GECS. Find your issue, apply the solution, and learn how to prevent it.
|
|
|
|
## 📋 Quick Diagnosis
|
|
|
|
### My Game Isn't Working At All
|
|
|
|
**Symptoms**: No entities moving, systems not running, nothing happening
|
|
|
|
**Quick Check**:
|
|
|
|
```gdscript
|
|
# In your _process() method, ensure you have:
|
|
func _process(delta):
|
|
if ECS.world:
|
|
ECS.world.process(delta) # This line is critical!
|
|
```
|
|
|
|
**Missing this?** → [Systems Not Running](#systems-not-running)
|
|
|
|
### Entities Aren't Moving/Updating
|
|
|
|
**Symptoms**: Entities exist but don't respond to systems
|
|
|
|
**Quick Check**:
|
|
|
|
1. Are your entities added to the world? `ECS.world.add_entity(entity)`
|
|
2. Do your entities have the right components? Check system queries
|
|
3. Are your systems properly organized in scene hierarchy? Check default_systems.tscn
|
|
|
|
**Still broken?** → [Entity Issues](#entity-issues)
|
|
|
|
### Performance Is Terrible
|
|
|
|
**Symptoms**: Low FPS, stuttering, slow response
|
|
|
|
**Quick Check**:
|
|
|
|
1. Enable profiling: `ECS.world.enable_profiling = true`
|
|
2. Check entity count: `print(ECS.world.entity_count)`
|
|
3. Look for expensive queries in your systems
|
|
|
|
**Need optimization?** → [Performance Issues](#performance-issues)
|
|
|
|
## 🚫 Systems Not Running
|
|
|
|
### Problem: Systems Never Execute
|
|
|
|
**Error Messages**:
|
|
|
|
- No error, but `process()` method never called
|
|
- Entities exist but don't change
|
|
|
|
**Solution**:
|
|
|
|
```gdscript
|
|
# ✅ Ensure this exists in your main scene
|
|
func _process(delta):
|
|
ECS.process(delta) # This processes all systems
|
|
|
|
# OR if using system groups:
|
|
func _process(delta):
|
|
ECS.process(delta, "physics")
|
|
ECS.process(delta, "render")
|
|
```
|
|
|
|
**Prevention**: Always call `ECS.process()` in your main game loop.
|
|
|
|
### Problem: System Query Returns Empty
|
|
|
|
**Symptoms**: System exists but `process()` never called
|
|
|
|
**Diagnosis**:
|
|
|
|
```gdscript
|
|
# Add this to your system for debugging
|
|
class_name MySystem extends System
|
|
|
|
func _ready():
|
|
print("MySystem query result: ", query().execute().size())
|
|
|
|
func query():
|
|
return q.with_all([C_ComponentA, C_ComponentB])
|
|
```
|
|
|
|
**Common Causes**:
|
|
|
|
1. **Missing Components**:
|
|
|
|
```gdscript
|
|
# ❌ Problem - Entity missing required component
|
|
var entity = Entity.new()
|
|
entity.add_component(C_ComponentA.new())
|
|
# Missing C_ComponentB!
|
|
|
|
# ✅ Solution - Add all required components
|
|
entity.add_component(C_ComponentA.new())
|
|
entity.add_component(C_ComponentB.new())
|
|
```
|
|
|
|
2. **Wrong Component Types**:
|
|
|
|
```gdscript
|
|
# ❌ Problem - Using instance instead of class
|
|
func query():
|
|
return q.with_all([C_ComponentA.new()]) # Wrong!
|
|
|
|
# ✅ Solution - Use class reference
|
|
func query():
|
|
return q.with_all([C_ComponentA]) # Correct!
|
|
```
|
|
|
|
3. **Component Not Added to World**:
|
|
|
|
```gdscript
|
|
# ❌ Problem - Entity not in world
|
|
var entity = Entity.new()
|
|
entity.add_component(C_ComponentA.new())
|
|
# Entity never added to world!
|
|
|
|
# ✅ Solution - Add entity to world
|
|
ECS.world.add_entity(entity)
|
|
```
|
|
|
|
## 🎭 Entity Issues
|
|
|
|
### Problem: Entity Components Not Found
|
|
|
|
**Error Messages**:
|
|
|
|
- `get_component() returned null`
|
|
- `Entity does not have component of type...`
|
|
|
|
**Diagnosis**:
|
|
|
|
```gdscript
|
|
# Debug what components an entity actually has
|
|
func debug_entity_components(entity: Entity):
|
|
print("Entity components:")
|
|
for component_path in entity.components.keys():
|
|
print(" ", component_path)
|
|
```
|
|
|
|
**Solution**: Ensure components are added correctly:
|
|
|
|
```gdscript
|
|
# ✅ Correct component addition
|
|
var entity = Entity.new()
|
|
entity.add_component(C_Health.new(100))
|
|
entity.add_component(C_Position.new(Vector2(50, 50)))
|
|
|
|
# Verify component exists before using
|
|
if entity.has_component(C_Health):
|
|
var health = entity.get_component(C_Health)
|
|
health.current -= 10
|
|
```
|
|
|
|
### Problem: Component Properties Not Updating
|
|
|
|
**Symptoms**: Setting component properties has no effect
|
|
|
|
**Common Causes**:
|
|
|
|
1. **Getting Component Reference Once**:
|
|
|
|
```gdscript
|
|
# ❌ Problem - Stale component reference
|
|
var health = entity.get_component(C_Health)
|
|
# ... later in code, component gets replaced ...
|
|
health.current = 50 # Updates old component!
|
|
|
|
# ✅ Solution - Get fresh reference each time
|
|
entity.get_component(C_Health).current = 50
|
|
```
|
|
|
|
2. **Modifying Wrong Entity**:
|
|
|
|
```gdscript
|
|
# ❌ Problem - Variable confusion
|
|
var player = get_player_entity()
|
|
var enemy = get_enemy_entity()
|
|
|
|
# Accidentally modify wrong entity
|
|
player.get_component(C_Health).current = 0 # Meant to be enemy!
|
|
|
|
# ✅ Solution - Use clear variable names
|
|
var player_health = player.get_component(C_Health)
|
|
var enemy_health = enemy.get_component(C_Health)
|
|
enemy_health.current = 0
|
|
```
|
|
|
|
## 💥 Common Errors
|
|
|
|
### Error: "Cannot access property/method on null instance"
|
|
|
|
**Full Error**:
|
|
|
|
```
|
|
Invalid get index 'current' (on base: 'null instance')
|
|
```
|
|
|
|
**Cause**: Component doesn't exist on entity
|
|
|
|
**Solution**:
|
|
|
|
```gdscript
|
|
# ❌ Causes null error
|
|
var health = entity.get_component(C_Health)
|
|
health.current -= 10 # health is null!
|
|
|
|
# ✅ Safe component access
|
|
if entity.has_component(C_Health):
|
|
var health = entity.get_component(C_Health)
|
|
health.current -= 10
|
|
else:
|
|
print("Entity doesn't have C_Health!")
|
|
```
|
|
|
|
### Error: "Class not found"
|
|
|
|
**Full Error**:
|
|
|
|
```
|
|
Identifier 'ComponentName' not found in current scope
|
|
```
|
|
|
|
**Causes & Solutions**:
|
|
|
|
1. **Missing class_name**:
|
|
|
|
```gdscript
|
|
# ❌ Problem - No class_name declaration
|
|
extends Component
|
|
# Script exists but can't be referenced by name
|
|
|
|
# ✅ Solution - Add class_name
|
|
class_name C_Health
|
|
extends Component
|
|
```
|
|
|
|
2. **File not saved or loaded**:
|
|
|
|
- Save your component script files
|
|
- Restart Godot if classes still not found
|
|
- Check for syntax errors in the component file
|
|
|
|
3. **Wrong inheritance**:
|
|
|
|
```gdscript
|
|
# ❌ Problem - Wrong base class
|
|
class_name C_Health
|
|
extends Node # Should be Component!
|
|
|
|
# ✅ Solution - Correct inheritance
|
|
class_name C_Health
|
|
extends Component
|
|
```
|
|
|
|
## 🐌 Performance Issues
|
|
|
|
### Problem: Low FPS / Stuttering
|
|
|
|
**Diagnosis Steps**:
|
|
|
|
1. **Enable profiling**:
|
|
|
|
```gdscript
|
|
ECS.world.enable_profiling = true
|
|
|
|
# Check processing times
|
|
func _process(delta):
|
|
ECS.process(delta)
|
|
print("Frame time: ", get_process_delta_time() * 1000, "ms")
|
|
```
|
|
|
|
2. **Check entity count**:
|
|
```gdscript
|
|
print("Total entities: ", ECS.world.entity_count)
|
|
print("System count: ", ECS.world.get_system_count())
|
|
```
|
|
|
|
**Common Fixes**:
|
|
|
|
1. **Too Many Entities in Broad Queries**:
|
|
|
|
```gdscript
|
|
# ❌ Problem - Overly broad query
|
|
func query():
|
|
return q.with_all([C_Position]) # Matches everything!
|
|
|
|
# ✅ Solution - More specific query
|
|
func query():
|
|
return q.with_all([C_Position, C_Movable])
|
|
```
|
|
|
|
2. **Expensive Queries Rebuilt Every Frame**:
|
|
|
|
```gdscript
|
|
# ❌ Problem - Rebuilding queries in process
|
|
func process(entities: Array[Entity], components: Array, delta: float):
|
|
var custom_entities = ECS.world.query.with_all([C_ComponentA]).execute()
|
|
|
|
# ✅ Solution - Use the system's query() method (automatically cached)
|
|
func query():
|
|
return q.with_all([C_ComponentA]) # Automatically cached by GECS
|
|
|
|
func process(entities: Array[Entity], components: Array, delta: float):
|
|
# Just process the entities passed in - already filtered by query
|
|
for entity in entities:
|
|
# Process entity...
|
|
```
|
|
|
|
## 🔧 Integration Issues
|
|
|
|
### Problem: GECS Conflicts with Godot Features
|
|
|
|
**Issue**: Using GECS entities with Godot nodes causes problems
|
|
|
|
**Solution**: Choose your approach consistently:
|
|
|
|
```gdscript
|
|
# ✅ Approach 1 - Pure ECS (recommended for complex games)
|
|
# Entities are not nodes, use ECS for everything
|
|
var entity = Entity.new() # Not added to scene tree
|
|
entity.add_component(C_Position.new())
|
|
ECS.world.add_entity(entity)
|
|
|
|
# ✅ Approach 2 - Hybrid (good for simpler games)
|
|
# Entities are nodes, use ECS for specific systems
|
|
var entity = Entity.new()
|
|
add_child(entity) # Entity is in scene tree
|
|
entity.add_component(C_Health.new())
|
|
ECS.world.add_entity(entity)
|
|
```
|
|
|
|
**Avoid**: Mixing approaches inconsistently in the same project.
|
|
|
|
### Problem: GECS Not Working After Scene Changes
|
|
|
|
**Symptoms**: Systems stop working when changing scenes
|
|
|
|
**Solution**: Properly reinitialize ECS in new scenes:
|
|
|
|
```gdscript
|
|
# In each main scene script
|
|
func _ready():
|
|
# Create new world for this scene
|
|
var world = World.new()
|
|
add_child(world)
|
|
ECS.world = world
|
|
|
|
# Systems are usually managed via scene composition
|
|
# See default_systems.tscn for organization
|
|
|
|
# Create your entities
|
|
setup_entities()
|
|
```
|
|
|
|
**Prevention**: Always initialize ECS properly in each scene that uses it.
|
|
|
|
## 🛠️ Debugging Tools
|
|
|
|
### Enable Debug Logging
|
|
|
|
Add to your project settings or main script:
|
|
|
|
```gdscript
|
|
# Enable GECS debug output
|
|
ECS.set_debug_level(ECS.DEBUG_VERBOSE)
|
|
|
|
# This will show:
|
|
# - Entity creation/destruction
|
|
# - Component additions/removals
|
|
# - System processing information
|
|
# - Query execution details
|
|
```
|
|
|
|
### Entity Inspector Tool
|
|
|
|
Create a debug tool to inspect entities at runtime:
|
|
|
|
```gdscript
|
|
# DebugPanel.gd
|
|
extends Control
|
|
|
|
func _on_inspect_button_pressed():
|
|
var entities = ECS.world.get_all_entities()
|
|
print("=== ENTITY INSPECTOR ===")
|
|
|
|
for i in range(min(10, entities.size())): # Show first 10
|
|
var entity = entities[i]
|
|
print("Entity ", i, ":")
|
|
print(" Components: ", entity.components.keys())
|
|
print(" Groups: ", entity.get_groups())
|
|
|
|
# Show component values
|
|
for comp_path in entity.components.keys():
|
|
var comp = entity.components[comp_path]
|
|
print(" ", comp_path, ": ", comp)
|
|
```
|
|
|
|
## 📚 Getting More Help
|
|
|
|
### Community Resources
|
|
|
|
- **Discord**: [Join our community](https://discord.gg/eB43XU2tmn) for help and discussions
|
|
- **GitHub Issues**: [Report bugs](https://github.com/csprance/gecs/issues)
|
|
- **Documentation**: [Complete Guide](../DOCUMENTATION.md)
|
|
|
|
### Before Asking for Help
|
|
|
|
Include this information in your question:
|
|
|
|
1. **GECS version** you're using
|
|
2. **Godot version** you're using
|
|
3. **Minimal code example** that reproduces the issue
|
|
4. **Error messages** (full text, not paraphrased)
|
|
5. **Expected vs actual behavior**
|
|
|
|
### Still Stuck?
|
|
|
|
If this guide doesn't solve your problem:
|
|
|
|
1. **Check the examples** in [Getting Started](GETTING_STARTED.md)
|
|
2. **Review best practices** in [Best Practices](BEST_PRACTICES.md)
|
|
3. **Search GitHub issues** for similar problems
|
|
4. **Create a minimal reproduction** and ask for help
|
|
|
|
---
|
|
|
|
_"Every bug is a learning opportunity. The key is knowing where to look and what questions to ask."_
|