Dodges in RLBot in C#

26 Feb 2020

"Dodges? Never heard of 'em!"
~ Not NomBot

Dodges are essential in Rocket League. Learning how to code a dodge also teaches you how to create a sequenced action in code. That knowledge is incredibly useful for all sorts of things, like wavedashes, walldashes, and halfflips.

Before we get to the code, I strongly recommend you watch the first 5 minutes of Eastvillage's excellent dodge tutorial video. Although the video is part of the Java RLBot series, the first 5 minutes are language agnostic. Eastvillage does a great job of explaining how bots communicate with the game and clears up some common misconceptions beginners make about dodging. I can assure you that after watching the video you'll be slightly more enlightened.

Done watching? Great! Now let's get on with the code.

Dodge class

Let's take a look at the structure of the Dodge class.

/// <summary>
/// Responsible for executing dodges.
/// </summary>
public class Dodge
{
    // The bot's index
    private readonly int index;

    // -1 dodges forwards, 1 dodges backwards
    private readonly float pitch;

    // -1 dodges left, 1 dodges right
    private readonly float yaw;

    // How long to hold the jumps
    private readonly float jumpDuration;

    // How long to wait after holding the first jump
    private readonly float waitAfterJump;

    // The in-game time at which the dodge started
    private float startTime;

    // Tracks whether the dodge can continue to run.
    public bool HasFinished { get; private set; }

    public Dodge(
        int index,
        float pitch = -1, float yaw = 0,
        float jumpDuration = 0.1f, float waitAfterJump = 0.1f
    )
    {
        this.index = index;
        this.pitch = pitch;
        this.yaw = yaw;
        this.jumpDuration = jumpDuration;
        this.waitAfterJump = waitAfterJump;
    }

    public Controller GetOutput(Packet packet) {...}
}

The HasFinished property needs to be used by whatever state is implementing the dodge so that the state knows when to resume from the dodge.

Now let's see how the GetOutput works.

public Controller GetOutput(Packet packet)
{ 
    if (startTime == default)
        startTime = packet.GameInfo.SecondsElapsed;

    float timeSinceStart = packet.GameInfo.SecondsElapsed - startTime;

    // First jump
    if (timeSinceStart < jumpDuration)
        return new Controller {Jump = true};

    // Waiting after the first jump
    if (timeSinceStart < jumpDuration + waitAfterJump)
        return new Controller {Pitch = pitch, Yaw = yaw};

    // Second jump
    if (timeSinceStart < jumpDuration * 2 + waitAfterJump)
        return new Controller {Jump = true, Pitch = pitch, Yaw = yaw};

    // Waiting after the second jump

    // We haven't finished the dodge until all our wheels touch the ground
    if (packet.Players[index].HasWheelContact)
        HasFinished = true;

    // We output Throttle = 1 in case we don't land properly. This helps us
    // recover as the car will automatically orient itself if upside-down.
    return new Controller {Throttle = 1};
}

Putting it in the agent class

We can easily put this in the agent class or in a state. This is a modified version of the example bot that includes the Dodge class we just implemented.

public class Bot : RLBotDotNet.Bot
{
    private Dodge dodge;

    public Bot(string name, int team, int index) : base(name, team, index) { }

    public override Controller GetOutput(rlbot.flat.GameTickPacket gameTickPacket)
    {
        Packet packet = new Packet(gameTickPacket);

        // Leave this at the start of the bot so that the agent can dodge
        // whenever a dodge is required.
        if (dodge != null)
        {
            Controller output = dodge.GetOutput(packet);
            // Output the dodge's controls until it finishes.
            if (!dodge.HasFinished)
                return output;
            dodge = null;
        }

        // Dodge every 5 seconds.
        if ((int) packet.GameInfo.SecondsElapsed % 5 == 0)
            dodge = new Dodge(index);

        return new Controller();
    }
}

You've just added dodges to your bot! Now you can use this knowledge to create cool actions like halfflips and wavedashes! ✨