Intro

This post will be focused on aimbots and specifically, the method of using Bézier curves to smooth out the path between source and destination to emulate human-like aim. I will share my research in aimbots and computerized mouse movements.

As always, the purpose of this post is for educational purposes only.

What’s an aimbot?

An aimbot is simply a ‘cheat’ or ‘hack’, typically used in first person shooter video games, in which a program is used to aim for the player.

How are aimbots built?

The actual aim process is usually done in one of two ways.

Writing to view angles: The memory locations that contain the player’s view angles (commonly known as the view matrix) are exposed, in addition to a target’s 3D coordinates. Functions such as World2Screen are used to convert these 3D coordinates to a location on the screen relative to the aimbotting player. These World2Screen’d values can then be written directly into the player’s view angles. I absolutely loathe vector mathematics, so I will defer to external documentation as to how world coordinates are converted to camera coordinates. More info on WorldToScreen, and the viewmatrix below in the resources section.

worldtoscreen

TLDR: World2Screen the enemy, get location of enemy relative to player’s screen, write values to player’s viewangles.

mouse_event: Same theory, different execution. Instead of writing to the viewmatrix, the mouse is controlled externally using something like mouse_event. Most programming languages will have some sort of class/API that can be used to achieve this.

Resources - the math behind coordinate conversion

Check these out for more info on matrices, and the concept of the view matrix: http://www.songho.ca/opengl/gl_anglestoaxes.html , http://www.codinglabs.net/article_world_view_projection_matrix.aspx.

Check this out for more info on how World to Screen works: https://docs.unity3d.com/ScriptReference/Camera.WorldToScreenPoint.html

Can someone tell the difference between human aim and computerized aim?

Yes. Let’s look at an example. In the image below, the blue X represents the starting location of the player’s crosshair, the red X represents the target location:

aimbot01

Now this is what happens if we write directly to the player’s view angles (or in this case, cursor position). Black represents the path the aimbot takes:

aimbot011

There is no path! The cursor will ‘jump’ from source to destination. Obviously, no human is capable of doing this.

finesse

Linear Interpolation

One way of generating a path is to use Linear Interpolation (lerp).

LERP works by taking an initial position and a destination, and generating a straight line between the two points.

aimbot04

Point Lerp(const Point& a, const Point& b, const float t) {
	Point result;
	result.x = a.x + (b.x - a.x)*t;
	result.y = a.y + (b.y - a.y)*t;
	return result;
}

Using the previous example, we will get a result similar to:

aimbot02

Is this good? Is it human-like? Well, try moving your mouse along the same path. Are you able to mimic the line generated by the linear interpolation? Unlikely. You are likely moving in a subtle curve like the image below:

aimbot03

Now in a video game, it’s a lot harder to look at crosshair movement and know it’s a perfectly straight line, so for most purposes, this is fine.

Using a Bézier Curve

While a slow-moving lerp aimbot will work fine, we can do better. We can calculate a path between source and target using a Bézier curve. A Bézier curve is a parametric curve frequently used in computer graphics.

The images below depict the path generated by a quadratic, and cubic Bézier curve respectively.

Quadratic (hyperbola):

qbezier

Cubic:

cbezier

In theory, the higher order we use, the more ‘humanized’ the aim will look. We can construct a Bézier curve of order n as follows:

  • P0 will represent the starting location (current viewAngle).
  • Pn will represent the target location.
  • P1, P2 … Pn-1 are points scattered around Pn (the target).
Point n3Bezier(const Point& a, const Point& b, const Point& c, const Point& d, const float t) {
	Point ab, bc, cd, abbc, bccd;
	Point result;
 
	ab = Lerp(a, b, t);
	bc = Lerp(b, c, t);
	cd = Lerp(c, d, t);
	abbc = Lerp(ab, bc, t);
	bccd = Lerp(bc, cd, t);
 
	result = Lerp(abbc, bccd, t);
	return result;
}

This is all really cool in theory, but does it work in practice?

aimbot05

Well, does anyone really move their mouse like this?

nod

Other pitfalls

Because we are using these curves to create an aimbot, we have to consider the target moving. Specifically, the target can move during calculations. This will, without a doubt, completely screw with the curve.

Possible solutions include:

  • Using a separate algorithm to track moving targets.
  • Recalculate the curve on each frame (prone to lag).

Conclusion

It’s a neat idea in theory, but would require some significant tweaking to make it actually look human. Notably, depending on the control points selected, the mouse movement can range between passable and ridiculous. Furthermore, the addition of movement complicates things significantly. I’d guess that there are probably much more effective methods than using a Bézier Curve.

facepalm