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! ✨