返回 Skill 列表
extension
分类: 开发与工程无需 API Key

godot-refactor

当Godot项目中有代码创建的对象、通过直接引用紧密耦合的组件、超过150行的单体脚本,或者需要以场景为主的架构(包括信号和组合)时使用。协调所有5个代码质量小技巧:提取到场景、拆分脚本、添加信号、提取资源以及清理冲突。每个操作都独立运行,并伴有git提交和验证。

person作者: jakexiaohubgithub

Godot Refactor Orchestrator

This orchestrator runs 5 code quality mini-skills in sequence. For individual operations, invoke mini-skills directly.

Core Principle: Scene-First, Signal-Based, Component Composition

Iron Law: NO functional or visual changes during refactoring. Period.

This skill automatically refactors Godot projects to cleaner, more modular architecture while preserving exact behavior. Every operation creates a git commit. Rollback is always available.


UPON INVOCATION - START HERE

When this skill is invoked, IMMEDIATELY execute the following sequence:

1. Verify Godot Project (5 seconds)

# Check if this is a Godot project
ls project.godot 2>/dev/null && echo "✓ Godot project detected" || echo "✗ Not a Godot project"

If NOT a Godot project:

  • Inform user this skill only works on Godot projects
  • Ask if they want to navigate to the correct directory
  • STOP here

If IS a Godot project:

  • Proceed to step 2

2. Begin Phase 1: Analysis & Baseline (AUTOMATIC)

Do NOT ask "What would you like me to do?" - Start analyzing immediately.

Execute these commands in parallel:

# Detect code-created objects
grep -rn "\.new()" --include="*.gd" . | grep -E "(Node|Timer|Area|Sprite|Control|Collision)" | wc -l

# Detect monolithic scripts
find . -name "*.gd" -exec wc -l {} + | awk '$1 > 150' | wc -l

# Detect tight coupling
grep -rn "get_node\|has_method" --include="*.gd" . | wc -l

# Detect inline data
grep -rn "^[[:space:]]*const.*\[" --include="*.gd" . | wc -l

3. Present Findings (30 seconds)

Show the user:

=== Godot Refactoring Analysis ===

Project: [project name from project.godot]

Anti-patterns detected:
- Code-created objects: X
- Monolithic scripts: X
- Tight coupling: X
- Inline data: X
- Conflicting operations: (will be detected after refactoring)

Total: X anti-patterns found

Refactoring includes:
✓ Automatic testing after each operation
✓ Auto-rollback on test failure
✓ Git commit per operation
✓ Push to remote on demand

Would you like me to:
1. Proceed with automatic refactoring (recommended)
2. Show detailed breakdown first
3. Cancel

4. Wait for User Choice

  • If 1 (Proceed): Start Phase 2 immediately
  • If 2 (Details): Show detailed file-by-file breakdown, then offer to proceed
  • If 3 (Cancel): Exit skill

CRITICAL: Do NOT stop after loading the skill. Do NOT ask "What would you like me to do?" Start with step 1 immediately.


When to Use This Skill

Use this skill when you detect ANY of these symptoms:

Code-Created Objects:

  • .new() calls in _ready(), _process(), or other lifecycle methods
  • add_child() with programmatically created nodes
  • Timers, Areas, Sprites created in code

Monolithic Scripts:

  • Scripts >150 lines
  • Multiple unrelated responsibilities in one file
  • God objects that do everything

Tight Coupling:

  • get_node() chains to access other nodes
  • has_method() checks before calling
  • Direct property access across nodes
  • Parent-child dependencies for behavior

Inline Data:

  • const arrays with game data
  • Hardcoded configuration in scripts
  • Data that should be resources

Deep Inheritance:

  • More than 2 levels of script inheritance
  • Inheritance used for code reuse instead of composition

Decision Flowchart

User mentions Godot project
    ↓
Does it have ANY of the above symptoms?
    ↓ YES                    ↓ NO
Use this skill              Regular development
    ↓
Run Phase 1: Analysis
    ↓
Anti-patterns found?
    ↓ YES                    ↓ NO
Run Phases 2-4              Document clean state

The Four Phases

Phase 1: Analysis & Baseline (Automatic)

Purpose: Detect all anti-patterns and create safety baseline.

Steps:

  1. Scan Project Files
# Find all Godot script files
find . -name "*.gd" -type f

# Find all scene files
find . -name "*.tscn" -type f
  1. Detect Anti-Patterns

Use detection patterns from anti-patterns-detection.md:

# Code-created objects
grep -rn "\.new()" --include="*.gd" .

# Monolithic scripts (>150 lines)
find . -name "*.gd" -exec wc -l {} + | awk '$1 > 150 {print $2 " (" $1 " lines)"}'

# Tight coupling
grep -rn "get_node\|get_parent\|has_method" --include="*.gd" .

# Inline data
grep -rn "^[[:space:]]*const.*\[" --include="*.gd" .
  1. Create Git Baseline
# Save current branch
current_branch=$(git branch --show-current)

# Create baseline tag
git tag baseline-$(date +%Y%m%d-%H%M%S)

# Initial commit if there are uncommitted changes
git add .
git commit -m "Baseline: Pre-refactoring state (on $current_branch)"
  1. Generate Refactoring Manifest

Create a priority-ordered list:

| Priority | Anti-Pattern | File | Lines | Operation | |----------|-------------|------|-------|-----------| | 1 | Inline data | enemy_data.gd | 45-78 | Extract to .tres | | 2 | Code-created Timer | laser_beam.gd | 38-45 | Extract to .tscn | | 3 | Tight coupling | base_station.gd | 92 | Signal decoupling | | 4 | Monolithic script | player_movement.gd | 287 lines | Split script |

Phase 1 Output:

  • ✓ Baseline git commit/tag created
  • ✓ Anti-patterns detected and prioritized
  • ✓ Manifest table generated
  • ✓ Ready for automatic refactoring

Phase 2: Automatic Refactoring (Five Operations)

Process anti-patterns in priority order: Data → Scenes → Signals → Scripts → Conflicts

CRITICAL - After Each Operation:

  1. Git commit the changes
  2. Run automatic validation test
  3. If test fails: Auto-revert and report error
  4. If test passes: Continue automatically to next operation
  5. No user prompt unless test fails or user confirmation needed

Automatic Testing Procedure:

# Quick validation test (runs after each git commit)
echo "Running validation test..."
godot --headless --quit-after 5 project.godot 2>&1 | tee test_output.log

# Check for errors
if grep -q "ERROR\|SCRIPT ERROR\|Parse Error" test_output.log; then
    echo "⚠️  Tests failed - reverting operation"
    git reset --hard HEAD~1
    echo "❌ Operation reverted. Error details:"
    grep "ERROR\|SCRIPT ERROR\|Parse Error" test_output.log
    # STOP and report to user
else
    echo "✓ Tests passed - continuing"
    rm test_output.log
    # CONTINUE to next operation automatically
fi

Note: If test fails, STOP workflow and report to user. Otherwise, continue automatically through all operations.

Operation A: Extract Code-Created Objects to Modular Components

Target: Any .new() calls that create nodes

Enhanced Process:

  1. Detect and Analyze

    • Find .new() calls for node types
    • Extract 30 lines of context (properties, methods, signals)
    • Analyze variable names, properties, methods
    • Consult node-selection-guide.md decision trees
    • Calculate confidence score for node type
    • Select optimal node from godot-node-reference.md
  2. Check Component Library

    • Does components/{category}/ exist? (e.g., components/timers/)
    • If YES: Reuse base component, skip to Step 4
    • If NO: Generate full component structure (Steps 2-3)
  3. Generate Component (First Time Only)

    • Create {type}_config.gd (Resource class with @export properties)
    • Create configurable_{type}.gd (Script that extends node, applies config)
    • Create configurable_{type}.tscn (Base scene with script)
    • Creates modular, reusable foundation
  4. Generate Preset Resource

    • Extract properties from analyzed code
    • Create presets/{preset_name}.tres (specific configuration)
    • Each detected instance gets unique preset
    • Presets reference the base component
  5. Update Parent Scene

    • Add ext_resource entries for base scene and preset
    • Instance base component with preset resource
    • Same scene reused, different presets = ZERO duplication
  6. Update Parent Script

    • Add @onready reference to component instance
    • Keep signal connections
    • Remove .new(), add_child(), static property assignments
    • Configuration now comes from preset resource
  7. Git Commit & Validate

    • Commit all component files and parent changes
    • Run validation test
    • Ensure behavior unchanged

Example Transformation:

Before (Code-Created):

func _ready():
    _damage_timer = Timer.new()
    _damage_timer.wait_time = 0.5
    _damage_timer.one_shot = false
    add_child(_damage_timer)
    _damage_timer.timeout.connect(_on_damage)

    _cooldown_timer = Timer.new()
    _cooldown_timer.wait_time = 2.0
    _cooldown_timer.one_shot = true
    add_child(_cooldown_timer)
    _cooldown_timer.timeout.connect(_on_cooldown)

After (First Timer - Full Component Created):

Files created:
✓ components/timers/timer_config.gd (resource class)
✓ components/timers/configurable_timer.gd (reusable script)
✓ components/timers/configurable_timer.tscn (reusable base scene)
✓ components/timers/presets/damage_timer.tres (configuration preset)

parent.gd:
@onready var _damage_timer: ConfigurableTimer = $DamageTimer

func _ready():
    _damage_timer.timeout.connect(_on_damage)

After (Second Timer - Reuses Base):

Files created:
✓ components/timers/presets/cooldown_timer.tres (NEW preset only!)

parent.gd:
@onready var _damage_timer: ConfigurableTimer = $DamageTimer
@onready var _cooldown_timer: ConfigurableTimer = $CooldownTimer

func _ready():
    _damage_timer.timeout.connect(_on_damage)
    _cooldown_timer.timeout.connect(_on_cooldown)

Key Benefits:

  • ✅ Intelligent node selection (no arbitrary choices)
  • ✅ Modular components (reusable across project)
  • ✅ Zero duplication (same base, different presets)
  • ✅ Inspector-configurable (edit presets in editor)
  • ✅ Automatic library building (grows organically)
  • ✅ Signal connections preserved
  • ✅ Behavior unchanged (Iron Law maintained)

Success Criteria:

  • Component structure created (if first of type)
  • Preset resource created with extracted values
  • Parent scene instances component with preset
  • Parent script has @onready reference
  • Signal connections work
  • Old code removed
  • Behavior unchanged

Operation B: Split Monolithic Scripts

Target: Scripts >150 lines with multiple responsibilities

Detection:

find . -name "*.gd" -exec wc -l {} + | awk '$1 > 150'

For each detected script:

  1. Analyze script structure

    • Identify logical sections (look for comment headers, function groups)
    • Find responsibilities (input, physics, abilities, UI, etc.)
    • Determine dependencies between sections
  2. Plan split

    • Main script keeps core responsibility
    • Extract secondary responsibilities to components
    • Define signal interface between components
  3. Create component scripts

    Example: Split player_movement.gd (287 lines)

    Extract to player_abilities.gd:

    extends Node
    class_name PlayerAbilities
    
    signal ability_used(ability_name: String)
    signal cooldown_started(duration: float)
    
    # Ability-related functions moved here
    
  4. Update main script

    @onready var abilities: PlayerAbilities = $Abilities
    
    func _ready():
        abilities.ability_used.connect(_on_ability_used)
    
  5. Implement signal communication

    • Replace direct function calls with signals
    • Connect signals in _ready()
    • Remove tight coupling
  6. Git commit

    git add player_movement.gd player_abilities.gd
    git commit -m "Refactor: Split abilities from player_movement.gd"
    
  7. Run automatic test (see Phase 2 header for test procedure)

Success criteria:

  • Main script <150 lines
  • Component scripts focused (80-120 lines optimal)
  • Signal-based communication
  • No direct dependencies
  • Behavior unchanged

Operation C: Implement Signal-Based Decoupling

Target: Direct coupling via get_node(), has_method(), direct calls

Detection:

grep -rn "get_node\|has_method" --include="*.gd" .

For each detected coupling:

  1. Identify the relationship

    • What is being accessed?
    • What information is being exchanged?
    • Is this event-based or state query?
  2. Create/use Events autoload

    If not exists, create events.gd:

    extends Node
    # Global event bus
    
    signal player_entered_safe_zone(zone: Node2D)
    signal enemy_spawned(enemy: Node2D)
    signal score_changed(new_score: int)
    

    Add to project settings: Project → Project Settings → Autoload

  3. Replace direct coupling with signals

    Before:

    func _on_body_entered(body):
        if body.has_method("set_beam_enabled"):
            body.set_beam_enabled(false)
    

    After (emitter):

    func _on_body_entered(body):
        if body.is_in_group("player"):
            Events.player_entered_safe_zone.emit(self)
    

    After (receiver):

    func _ready():
        Events.player_entered_safe_zone.connect(_on_safe_zone)
    
    func _on_safe_zone(zone):
        set_beam_enabled(false)
    
  4. Remove coupling code

    • Delete get_node() calls
    • Delete has_method() checks
    • Delete direct property access
  5. Git commit

    git add events.gd base_station.gd player_movement.gd
    git commit -m "Refactor: Decouple base_station from player via signals"
    
  6. Run automatic test (see Phase 2 header for test procedure)

Success criteria:

  • No get_node() for behavior access
  • No has_method() checks
  • Events.gd exists and is used
  • Signal connections established
  • Behavior unchanged

Operation D: Extract Data to .tres Resources

Target: const declarations with game data

Detection:

grep -rn "^[[:space:]]*const.*\[" --include="*.gd" .

For each detected data constant:

  1. Analyze data structure

    const ENEMY_TYPES = [
        {"type": "basic", "health": 100, "speed": 200},
        {"type": "fast", "health": 50, "speed": 400}
    ]
    
  2. Create Resource class

    Create enemy_type_data.gd:

    extends Resource
    class_name EnemyTypeData
    
    @export var type_name: String
    @export var health: int
    @export var speed: float
    
  3. Generate .tres files

    Create enemy_types/basic.tres:

    [gd_resource type="EnemyTypeData" load_steps=2 format=3]
    
    [ext_resource type="Script" path="res://enemy_type_data.gd" id="1"]
    
    [resource]
    script = ExtResource("1")
    type_name = "basic"
    health = 100
    speed = 200.0
    
  4. Update script to use resources

    @export var enemy_types: Array[EnemyTypeData]
    
    # In scene, assign resources via inspector
    
  5. Remove const declaration

  6. Git commit

    git add enemy_type_data.gd enemy_types/*.tres enemy_spawner.gd
    git commit -m "Refactor: Extract enemy data to .tres resources"
    
  7. Run automatic test (see Phase 2 header for test procedure)

Success criteria:

  • Resource class created
  • .tres files generated with correct data
  • Script updated to use resources
  • Const declaration removed
  • Behavior unchanged

Operation E: Clean Conflicting/Ineffective Operations

Target: Code that runs without errors but has no effect or conflicts with other code

IMPORTANT: This operation runs after Operations A-D are complete, as refactoring may introduce or remove conflicts.

Detection:

# Run comprehensive conflict detection
bash << 'EOF'
echo "=== Detecting Conflicting Operations ==="

# Self-assignments
echo "Self-assignments:"
grep -rn "position\s*=\s*position\|scale\s*=\s*scale\|rotation\s*=\s*rotation" --include="*.gd" .

# Redundant defaults
echo "Redundant defaults:"
grep -rn "modulate\s*=\s*Color\.WHITE\|scale\s*=\s*Vector2\.ONE" --include="*.gd" .

# Duplicate property assignments (common properties)
echo "Checking for duplicate assignments..."
for prop in "scale" "position" "rotation" "modulate" "visible"; do
    grep -rn "\.$prop\s*=" --include="*.gd" . | \
    awk -F: -v prop="$prop" '{
        file=$1; line=$2;
        if (file==prev_file && line-prev_line<20) {
            print file":"prev_line" and "line" - Duplicate "prop
        }
        prev_file=file; prev_line=line
    }'
done

# Conflicting tweens
echo "Conflicting tweens:"
grep -n "tween_property" --include="*.gd" -r . | \
awk -F: '{
    file=$1; line=$2;
    if (match($0, /tween_property.*"([^"]+)"/, arr)) {
        prop=arr[1];
        key=file":"prop;
        if (key in seen && line-seen[key]<15) {
            print file":"seen[key]" and "line" - Conflicting tweens on "prop
        }
        seen[key]=line
    }
}'

# Code after queue_free
echo "Code after queue_free:"
grep -A2 "queue_free()" --include="*.gd" . | grep -v "^--$"

EOF

For each detected conflict:

  1. Auto-fix (no user input):

    • Self-assignments: Remove entirely
    • Code after queue_free(): Move code before queue_free
    • Obvious redundant defaults: Remove
  2. User confirmation (ask user):

    • Duplicate assignments: Which value to keep?
    • Conflicting tweens: Which to keep or chain?
    • Multiple process calls: Final intended state?
  3. Example fixes:

    Self-assignment:

    # Before
    position = position
    
    # After (remove line)
    

    Duplicate assignment:

    # Before
    sprite.scale = Vector2(2, 2)  # Line 45
    sprite.scale = Vector2(1, 1)  # Line 52
    
    # After (keep last)
    sprite.scale = Vector2(1, 1)  # Line 52
    

    Conflicting tweens (user chose "chain"):

    # Before
    var tween1 = create_tween()
    tween1.tween_property(self, "scale", Vector2(2,2), 1.0)
    var tween2 = create_tween()
    tween2.tween_property(self, "scale", Vector2(0.5,0.5), 1.0)
    
    # After
    var tween = create_tween()
    tween.tween_property(self, "scale", Vector2(2,2), 1.0)
    tween.tween_property(self, "scale", Vector2(0.5,0.5), 1.0)
    
  4. Git commit

    git add <modified files>
    git commit -m "Refactor: Clean conflicting/ineffective operations
    
    - Removed self-assignments
    - Fixed duplicate property assignments
    - Resolved conflicting tweens
    - Cleaned up redundant operations
    
    No functional changes - code cleanup only"
    
  5. Run automatic test (see Phase 2 header for test procedure)

Success criteria:

  • No self-assignments remain
  • No obvious duplicate assignments
  • Conflicting tweens resolved
  • Code after queue_free() moved
  • Behavior unchanged

Note: See conflicting-operations-detection.md for comprehensive detection patterns and refactoring-operations.md Operation E for detailed procedures.


Phase 3: Git Commits (Automatic)

After each operation, commit with clear message:

# Template
git add <files>
git commit -m "Refactor: <Operation> in <file> - <specific change>"

# Examples
git commit -m "Refactor: Extract Timer to scene in laser_beam.gd"
git commit -m "Refactor: Split abilities from player_movement.gd (287→142 lines)"
git commit -m "Refactor: Decouple base_station from player via signals"
git commit -m "Refactor: Extract enemy data to .tres resources"
git commit -m "Refactor: Clean conflicting/ineffective operations"

After all operations:

git tag refactor-complete-$(date +%Y%m%d)

Commit history should show:

  • Baseline commit
  • One commit per refactoring operation (A, B, C, D, E)
  • Clear, descriptive messages
  • Easy to review
  • Easy to rollback individual changes

Push on Demand:

After all operations complete, ask user:

=== Refactoring Complete ===

All operations completed successfully!
5 operations performed, X commits created on current branch.

Would you like to push to remote?
1. Yes, push now
2. No, I'll push manually later
3. Show me the commit log first

Choice [1-3]:

If user chooses 1 (push now):

# Push to current branch's remote
git push origin $(git branch --show-current)

If user chooses 3 (show log first):

git log --oneline --graph baseline-*..HEAD
# Then ask again: Push now? [y/n]

If user says "push" or "push et" at ANY time during the workflow:

# Immediately push current branch
git push origin $(git branch --show-current)
echo "✓ Pushed to remote"

Phase 4: Final Verification (Minimal, Automatic)

Purpose: Ensure no functional or visual regressions.

Steps:

  1. Open project in Godot

    godot --editor path/to/project.godot
    
  2. Check for errors

    • No red errors in console
    • No yellow warnings about missing nodes
    • All scenes load successfully
  3. Visual verification

    • Run main scene
    • Quick visual check (30 seconds)
    • Compare against expected behavior
  4. Play test checklist (from verification-checklist.md):

    • [ ] Player movement works
    • [ ] Abilities trigger correctly
    • [ ] Enemies spawn and behave normally
    • [ ] UI updates properly
    • [ ] No crashes or errors
  5. Performance baseline (optional):

    # Compare FPS before/after
    # Should be identical ±2 FPS
    

If verification fails:

# Rollback procedure
git reset --hard baseline-YYYYMMDD-HHMMSS
git tag refactor-failed-$(date +%Y%m%d-%H%M%S)

# Report what broke
# Debug with systematic-debugging skill

If verification succeeds:

Report summary:

✓ Refactoring complete
✓ 8 operations performed
✓ 287 lines reduced to 142 across 3 files
✓ 4 .tscn scenes created
✓ 2 .tres resources created
✓ Signal-based architecture established
✓ No functional changes
✓ All tests passing

Supporting Files

This skill uses modular reference files:

  • anti-patterns-detection.md: All grep/find patterns for detection
  • refactoring-operations.md: Detailed step-by-step procedures
  • godot-best-practices.md: Clean patterns reference
  • tscn-generation-guide.md: .tscn file format templates
  • verification-checklist.md: Testing procedures

Read these files for detailed implementation guidance.


Red Flags - STOP

These thoughts mean you're rationalizing away discipline:

| Rationalization | Reality | Fix | |----------------|---------|-----| | "While I'm here, let me add this feature" | Feature creep breaks Iron Law | Refactor only, no features | | "This behavior is wrong, I'll fix it now" | Bug fixes are separate work | Note bug, refactor only | | "I don't need to test this change" | Untested = broken | Always verify | | "I'll commit after a few more changes" | Loses granularity | Commit per operation | | "This .tscn format looks close enough" | Invalid scenes crash | Use exact format | | "The user won't notice this visual change" | Iron Law has no exceptions | Revert and fix | | "Signals are overkill for this" | Coupling creeps back | Use signals anyway | | "I'll manually test later" | Later never comes | Test now | | "This script is fine at 160 lines" | Arbitrary exceptions grow | Split at 150 | | "I understand the pattern, no need to read" | Assumptions create bugs | Read the guide |


Quick Reference: Anti-Pattern → Clean Pattern

| Anti-Pattern | Clean Pattern | Tool | |-------------|---------------|------| | Timer.new() in code | .tscn scene with Timer | Operation A | | get_node("../Player") | Signal via Events | Operation C | | if has_method("take_damage"): | Signal listener | Operation C | | 287-line script | Split to 3 focused scripts | Operation B | | const WEAPONS = [...] | .tres resources | Operation D | | add_child(sprite) | Scene composition | Operation A | | Direct method calls | Signal emit/connect | Operation C | | Deep inheritance | Component composition | Operations A+B |


File Operation Flow

1. Data Extraction
   .gd with const → Resource class .gd + .tres files

2. Scene Extraction
   .gd with .new() → .gd with @onready + new .tscn

3. Signal Decoupling
   .gd with get_node() → events.gd + updated .gd files

4. Script Splitting
   Large .gd → Multiple focused .gd files with signals

Godot Naming Conventions

Scenes (.tscn):

  • PascalCase for node names: DamageTimer, AbilitySystem
  • snake_case for file names: damage_timer.tscn, ability_system.tscn

Scripts (.gd):

  • snake_case for files: player_movement.gd, enemy_spawner.gd
  • PascalCase for class_name: class_name PlayerMovement

Resources (.tres):

  • snake_case for files: enemy_types/basic.tres
  • PascalCase for Resource class: class_name EnemyTypeData

Signals:

  • snake_case: signal ability_used, signal player_entered_safe_zone
  • Past tense for events: signal enemy_spawned (not enemy_spawn)

@onready variables:

  • snake_case with type hint: @onready var _damage_timer: Timer = $DamageTimer
  • Private with underscore: _damage_timer, _ability_system

Common Mistakes

| Mistake | Consequence | Fix | |---------|-------------|-----| | Invalid .tscn format | Scene won't load in Godot | Use exact template format | | Missing node type in .tscn | Godot can't parse scene | Always specify type="Timer" | | Forgetting @onready | Null reference at runtime | Add @onready for all node refs | | Wrong signal signature | Connection fails silently | Match parameter types exactly | | Removing necessary .new() | Some objects SHOULD be created | Only refactor scene nodes | | Not testing after each op | Compounding errors | Test after every commit | | Coupling through globals | Different coupling, same problem | Use Events for decoupling only | | Over-splitting scripts | Too many tiny files | 80-120 lines is optimal | | Async signals without checks | Race conditions | Verify node existence | | Changing behavior "slightly" | Iron Law violation | Revert immediately |


Signal Architecture Patterns

Event Bus (Events.gd):

# Use for global events
signal player_died
signal level_completed(level_num: int)
signal score_changed(new_score: int)

Direct Node Signals:

# Use for parent-child communication
signal health_depleted
signal ability_activated(ability_name: String)

When to use which:

  • Events.gd: Cross-tree communication, global state changes
  • Node signals: Parent-child, local behavior

Real-World Impact

Expected improvements after refactoring:

Code Quality:

  • 30-50% reduction in total lines of code
  • Scripts average 80-120 lines (down from 150-300)
  • Zero direct node dependencies
  • Signal-based architecture throughout

Maintainability:

  • Changes isolated to single files
  • Components reusable across scenes
  • Testing individual components possible
  • New developers onboard faster

Performance:

  • Identical to baseline (±2 FPS)
  • Scene loading slightly faster
  • Memory usage unchanged

Execution Strategy

This skill runs fully automatically:

  1. User invokes skill on Godot project
  2. Phase 1: Scan and report findings
  3. User approves refactoring
  4. Phases 2-3: Execute all operations with commits on current branch
  5. Phase 4: Verify and report results

User input required:

  • Initial invocation
  • Approval after Phase 1 analysis
  • Final verification check (30 seconds)

Everything else is automatic:

  • Anti-pattern detection
  • .tscn file generation
  • Script modifications
  • Git commits on current branch
  • Testing

Success Criteria

Refactoring is complete when:

  • ✓ Zero .new() calls for scene nodes
  • ✓ All scripts <150 lines
  • ✓ Signal-based architecture established
  • ✓ No get_node() for behavior access
  • ✓ Data in .tres resources
  • ✓ Clean git history with descriptive commits on current branch
  • ✓ All scenes load without errors
  • ✓ Behavior identical to baseline
  • ✓ Visual appearance unchanged
  • ✓ Performance within ±2 FPS

Post-Refactoring

After successful refactoring:

  1. Continue development

    • Changes are already on current branch
    • Push to remote if not already pushed
    • Continue normal development workflow
  2. Document architecture

    • Create architecture diagram
    • Document signal flows
    • List component responsibilities
  3. Establish standards

    • Use this clean architecture as template
    • Apply patterns to new code
    • Prevent anti-pattern regression
  4. Consider further improvements (separate tasks):

    • Add unit tests (use TDD skill)
    • Optimize performance (profile first)
    • Add new features (use brainstorming skill)

Remember: Refactoring changes HOW code works internally, not WHAT it does externally. The Iron Law is absolute.