Swarm Defender: Godot Multiplayer and Advanced AI

After working with GameMaker for years, I wanted to try something different. Enter Godot Engine 4.6—a modern, open-source engine with powerful built-in features. The result is Swarm Defender, a 3D multiplayer co-op tower defense game where players work together to defend a central core against waves of intelligent enemies.

Why Godot?

Making the switch from GameMaker to Godot was motivated by several factors:

Steam Integration

One of the first major challenges was integrating Steam multiplayer. Using the GodotSteam addon and custom Steam Multiplayer Peer implementation, the game features:

# Example: Setting up Steam multiplayer
func create_lobby():
    Steam.createLobby(Steam.LOBBY_TYPE_PUBLIC, 4)
    
func _on_lobby_created(connect_result, lobby_id):
    if connect_result == 1:
        current_lobby_id = lobby_id
        multiplayer.multiplayer_peer = steam_peer

Advanced Enemy AI System

The most technically interesting aspect of Swarm Defender is the enemy AI. After several refactoring passes, I've built a sophisticated system that includes:

Navigation and Pathfinding

State Machine Architecture

Each enemy operates on a three-state system:

Vision and Detection System

Enemies don't just magically know where players are. They have realistic vision:

# Example: Vision cone detection
func can_see_target(target_position: Vector3) -> bool:
    var to_target = target_position - global_position
    var angle = rad_to_deg(forward_vector.angle_to(to_target))
    
    if angle > vision_angle / 2.0:
        return false
    
    # Perform raycast for line-of-sight
    var space_state = get_world_3d().direct_space_state
    var result = space_state.intersect_ray(query)
    
    return result and result.collider == target

Patrol Path System

One of my favorite features is the automatic patrol path system:

Enemy Variants

Using inheritance, I created multiple enemy types from a base NPC class:

Performance Optimization

With 75+ enemies potentially active at once, performance was critical. Key optimizations include:

Staggered Updates

Instead of all enemies updating every frame, they're distributed across frames:

# Assign each NPC to a different update frame
var update_offset = randi() % performance_update_distribute_frames

func _physics_process(delta):
    if Engine.get_process_frames() % performance_update_distribute_frames != update_offset:
        return
    
    # Only this subset of enemies updates this frame
    update_ai(delta * performance_update_distribute_frames)

Distance-Based Updates

Cached References

Code Organization

One thing I'm proud of is the code structure. All NPC scripts use #region blocks for organization:

This makes navigating 500+ line files much easier and helps other developers understand the codebase.

Server-Authoritative Multiplayer

The game uses a server-authoritative model where the host manages:

Clients handle:

What's Next?

Swarm Defender is still in active development. Upcoming features include:

Lessons from the Switch

Moving from GameMaker to Godot has been enlightening:

If you're considering learning Godot, I highly recommend it—especially for 3D projects.