Skip to main content

Feature · 2023

Octodrone

Project info

Role
Gameplay Programmer
Team
2 devs
Duration
12 weeks
Engine
Unity
Language
C#

The first ground-based enemy in Operation Starfall.

Octodrone

Tags

  • Gameplay
  • AI
  • C#

Overview

Octodrone was the first ground-based enemy developed for Operation Starfall. Its behavior combines state-driven AI, patrol and detection logic, and a custom jump attack.

I worked on this feature together with my co-worker Jason Siegersma.

Octodrone detecting and attacking the player

State Machine & Animation

Octo’s behavior is driven by the existing enemy state machine. We extended it with the states required for its behavior:

  • Patrol
  • Detect
  • Jump / Attack
  • Fuzzy

The Animator was connected to these states using triggers and Unity Events. This synchronized gameplay states with animation transitions, particularly during the jump attack.

Visuals & animations: Alex Kentie, Creative Director at Neon Origins.

Octodrone animation states

Patrol & Detection

The existing patrol and detection systems had originally been built around flying enemies. We adapted this logic for Octo’s grounded movement and directional behavior.

Directional Movement

A small but important part of the implementation was keeping Octo facing the direction of its current waypoint.

private void UpdateWalkDirection()
{
    var distance = _currentWayPoint.transform.positon - transform.position;

    var walkForceDirection = walkForce.Direction;
    walkForceDirection.x = Mathf.Abs(walkForceDirection.x) * Mathf.Sign(distance.x);

    walkForce.Direction = walkForceDirection;

    var transformLocalScale = transform.localScale;
    transformLocalScale.x = Mathf.Sign(distance.x);
    transform.localScale = transformLocalScale;
}

UpdateWalkDirection adjusts the walk force and local scale based on the waypoint’s position, allowing Octo to turn around correctly while patrolling.

Octodrone patrolling

Jump Attack

Octo’s attack uses a two-stage jump.

The initial attack disables gravity and applies an upward force. At the peak of the jump, gravity is restored and a second force moves Octo toward the player’s position. The attack state inherits from the existing AttackState and coordinates the animation events, state transitions, and forces.

protected override void Attack()
{
    base.Attack();
    EnemyAI.TargetLookAt(stepToPlayer);
    EnemyAI.forceBody.onCollisionEvent.AddListener(OnLand);
    var moveDirection = movementForce.Direction;
    moveDirection.x = stepToPlayer.x;
    movementForce.Duration = attackForce.Duration * 2;
    movmentForce.Direction = moveDirection;

    EnemyAI.forceBody.Add(attackForce, new CallbackConfig()
    {
        OnFinish = OnJumpPeak,
        OnCancel = AttackFinished
    });

    EnemyAI.forceBody.Add(movementForce, new CallbackConfig()
    {
        OnFinish = OnJumpFinish,
        OnCancel = AttackFinished
    });
}
Octodrone performing its jump attack

The attack state ties the animation timing and Force System together, allowing the jump to transition into the forward strike.

The most interesting part was learning how Octo’s states interacted with the existing Force System.

Collaboration

The other dev took the stronger role in the underlying gameplay code, while I focused more heavily on the Animator. We regularly switched between implementation and debugging as the feature came together. This overlap was especially useful when debugging the interaction between the AI, animation-, and Force Systems.

Takeaway

The main challenge was understanding how the existing Force System interacted with the enemy state machine. Working through that architecture gave me a stronger understanding of state machines, Unity Events, Refactoring, and integrating animation with gameplay logic.