Skip to content

Conversation

Coelancanth
Copy link
Owner

@Coelancanth Coelancanth commented Sep 17, 2025

Summary

Complete movement animation foundation (TD_060) with A* pathfinding integration, plus comprehensive technical analysis of animation-related issues (TD_061, TD_062). This PR establishes the foundation for smooth, visually-correct movement with proper fog of war updates.

Changes Included

TD_060: Movement Animation Foundation ✅ COMPLETE

  • Implemented non-blocking AnimateMovementAsync using CallDeferred pattern
  • Cell-by-cell animation along exact A* pathfinding routes
  • Perfect synchronization between preview dots and actual movement
  • Path calculated BEFORE domain state changes to avoid self-blocking
  • VERIFIED: All files exist, build clean (0 warnings/errors), 688/692 tests passing

TD_062: Sprite Clipping Fix (Approved for Implementation)

  • Problem Identified: Linear interpolation causes sprites to cut through walls at corners
  • Solution Designed: Sub-cell waypoint system with 30% offset at direction changes
  • Architecture: Uses ADR-006 Animation Event Bridge pattern for callback control
  • Complexity: Reduced to 2.5h by following established patterns

TD_061: Progressive FOV Updates (Correctly Diagnosed)

  • CRITICAL CORRECTION: Issue is FOV updates, NOT camera smoothing
  • Real Problem: Field of View updates instantly at destination, revealing areas before actor arrives
  • Expected Behavior: FOV should update cell-by-cell during movement animation
  • Solution: Reuse TD_062's callback pattern for progressive fog of war revelation

Technical Implementation

Files Modified (TD_060)

  • Views/ActorView.cs - Non-blocking AnimateMovementAsync with CallDeferred
  • src/Darklands.Presentation/Views/IActorView.cs - Added interface method
  • src/Darklands.Presentation/Presenters/ActorPresenter.cs - HandleActorMovedWithPathAsync
  • src/Darklands.Presentation/Presenters/GridPresenter.cs - Pre-calculates A* path
  • src/Darklands.Presentation/Presenters/IActorPresenter.cs - Updated interface

Architecture Alignment

  • ADR-006: Direct Godot usage in View layer (no unnecessary abstraction)
  • ADR-010: UIEventBus integration for movement completion events
  • Clean separation: Logic provides paths, rendering handles visual details

Key Technical Insights

Animation System Patterns

  1. Callback-Driven Animation: IMovementAnimationEvents enables precise control
  2. Sub-Cell Waypoints: Elegant solution for corner navigation without complex math
  3. Progressive FOV Updates: Game mechanic correctness over visual polish

Godot Integration Lessons

  • Tween + async/await deadlock: Use CallDeferred for thread-safe operations
  • Path timing critical: Calculate BEFORE domain state changes
  • Animation callbacks essential: Enable cross-layer coordination without coupling

Future Work Enabled

This foundation enables:

  • VS_012: Vision-Based Movement System (unblocked)
  • TD_061: Progressive FOV implementation using callback pattern
  • TD_062: Corner-aware sprite movement using waypoint system

Testing Results

  • Build: 0 warnings, 0 errors (verified twice)
  • Tests: 688/692 passing (4 skipped, 0 failed)
  • Manual: Movement animation works smoothly with A* paths
  • Integration: Animation matches preview dots perfectly

🤖 Generated with Claude Code

Dev Engineer and others added 2 commits September 17, 2025 19:19
…A* integration

## Summary
Implemented smooth cell-by-cell movement animation that follows exact A* pathfinding routes.
Animation now perfectly matches the hover preview path, with non-blocking execution.

## Key Changes
- Added AnimateMovementAsync to ActorView with CallDeferred queue pattern
- Integrated A* pathfinding calculation BEFORE move execution
- Created non-blocking animation system to prevent game freezes
- Ensured animation path matches preview path exactly

## Technical Details
- Fixed deadlock issue with Godot Tween + async/await
- Path calculated in GridPresenter before domain state changes
- Uses fire-and-forget pattern with CallDeferred for thread safety
- Created MovementPresenter for future event-driven coordination

## Files Modified
- Views/ActorView.cs - Non-blocking animation with path queue
- src/Darklands.Presentation/Presenters/GridPresenter.cs - Pre-calculates A* path
- src/Darklands.Presentation/Presenters/ActorPresenter.cs - HandleActorMovedWithPathAsync
- src/Darklands.Presentation/Presenters/IActorPresenter.cs - Interface updates
- src/Darklands.Presentation/Views/IActorView.cs - Animation method signature
- src/Darklands.Presentation/Presenters/MovementPresenter.cs - NEW (future use)

## Also Created
- TD_061: Camera Follow During Movement Animation (new backlog item)

Fixes: Animation now follows A* path, no more freezing
Tests: 688/692 passing

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Technical decisions completed:
- TD_060 Movement Animation: Verified complete and archived
- TD_062 Sprite Clipping Fix: Approved with elegant sub-cell waypoint approach

TD_062 Solution highlights:
- Uses sub-cell waypoints at corners (30% offset from center)
- Implements ADR-006 Animation Event Bridge pattern
- Maintains perfect logic/rendering decoupling
- Complexity reduced to 2.5h by following existing patterns

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Copy link

claude bot commented Sep 17, 2025

🔍 Code Review for PR #66: Movement Animation Foundation

Summary

This PR successfully implements smooth movement animation for actors in the grid-based game, integrating with the existing A* pathfinding system. The implementation demonstrates good architectural separation between domain and presentation layers.

✅ Strengths

1. Architecture Alignment

  • Excellent adherence to ADR-006 (direct Godot usage in View layer)
  • Clean separation of concerns between domain state and visual representation
  • Proper use of the presenter pattern to coordinate between layers

2. Non-blocking Animation Solution

  • Smart use of CallDeferred to prevent main thread deadlocks
  • Queue-based approach ensures thread safety
  • Avoids the common Godot pitfall of await ToSignal causing freezes

3. Path Pre-calculation Strategy

  • Calculating A* path BEFORE domain state changes prevents self-blocking issues
  • Ensures preview dots and actual movement use identical paths
  • Good fallback to straight-line movement when pathfinding fails

⚠️ Areas for Improvement

1. Magic Numbers

// In ProcessPendingPathAnimations
var segmentDuration = 1.0f / animData.Speed;  // Consider extracting to const

Consider defining animation constants at the class level for easier tuning.

2. Logging Verbosity

The implementation has extensive logging at Info level which might flood production logs:

_logger.Log(LogLevel.Information, LogCategory.Gameplay,
    "[CREATING TWEENS] Starting from index {StartIndex}...");

Consider using Debug level for detailed animation logs, reserving Info for key events only.

3. Error Recovery

While there's good try-catch handling, consider what happens if an animation fails mid-sequence. The actor's visual position might become desynced from domain state.

🐛 Potential Issues

1. Concurrent Animation Race Condition

If multiple move commands arrive quickly for the same actor, the queue processing might create overlapping tweens. Consider canceling existing tweens before starting new ones:

// Suggestion: Store and cancel previous tween
if (_activeTweens.TryGetValue(actorId, out var existingTween))
{
    existingTween.Kill();
}

2. Memory Management

The Queue<PendingPathAnimation> could theoretically grow unbounded if animations are queued faster than processed. Consider adding a maximum queue size check.

3. Path Validation

The path animation assumes all positions in the path are valid. Consider adding bounds checking:

if (gridPos.X < 0 || gridPos.Y < 0 || gridPos.X >= GridWidth || gridPos.Y >= GridHeight)
{
    _logger.LogWarning("Invalid path position: {0}", gridPos);
    continue;
}

🎯 Performance Considerations

  1. Tween Creation Overhead: Creating multiple tween properties in a loop is fine for small paths, but might cause frame drops with very long paths (>20 tiles). Consider batching or limiting visible animation segments.

  2. Lock Contention: The lock (_pendingPathAnimations) could become a bottleneck under heavy load. The current implementation is fine for typical gameplay, but consider lock-free structures if performance becomes an issue.

🔒 Security Review

No security concerns identified. The implementation properly validates actor IDs and handles missing actors gracefully.

📈 Test Coverage

With 688/692 tests passing and only 4 skipped (no failures), the test coverage appears solid. The manual testing confirms the animation works smoothly.

💡 Suggestions for Future Improvements

  1. Animation Easing: Consider adding easing curves to make movement feel more natural:

    tween.SetTrans(Tween.TransitionType.Sine);
    tween.SetEase(Tween.EaseType.InOut);
  2. Animation Events: The groundwork for IMovementAnimationEvents mentioned in TD_062 would be valuable for coordinating with other systems (sound, particles, etc.)

  3. Performance Metrics: Consider adding timing metrics to track animation performance and detect when animations are falling behind.

✅ Verdict: APPROVED WITH SUGGESTIONS

This is a solid implementation that correctly solves the movement animation problem while maintaining clean architecture. The non-blocking approach using CallDeferred is particularly clever and avoids common Godot pitfalls. The suggested improvements are mostly for edge cases and future robustness rather than critical issues.

The PR successfully completes TD_060 and provides a strong foundation for the sprite clipping fix (TD_062) and camera follow feature (TD_061).

Great work on navigating the threading complexities and maintaining architectural integrity! 🎉


Review generated by Claude Code

…othing

TD_061 Analysis Update:
- REAL ISSUE: FOV updates instantly at destination (game mechanic bug)
- NOT ISSUE: Camera smoothing (trivial visual polish)
- SOLUTION: Progressive FOV updates using TD_062 callback pattern

Problem clarified:
- Current: FOV reveals destination before actor arrives
- Expected: FOV updates cell-by-cell during movement animation
- Architecture: Reuse IMovementAnimationEvents from TD_062

Complexity revised: S (1-2h) → M (3-4h) due to cross-layer coordination

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@Coelancanth Coelancanth enabled auto-merge (squash) September 17, 2025 11:53
@Coelancanth Coelancanth merged commit 7641b7a into main Sep 17, 2025
5 checks passed
@Coelancanth Coelancanth deleted the feat/td-060-movement-animation branch September 17, 2025 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant