Tuesday, June 26, 2012

Unity3D + C#: Zero Waypoints AI Movement for 2D Games

The context is this: I wanna make a simple enemy AI which would move in two directions (left and right), along a floor tiles on air... like those mushroom men in Super Mario.

For most beginners, such as myself when I first started using Unity to make 2D games, my method would be placing two waypoints on each ends of the floor tiles, and then make my AI move towards one of them. When the AI is closed to a waypoint on one side, it would switch and move towards the waypoint on the other side... over and over again.

As simple as this method is, it can be a pain in the ass to place waypoints at every single AI-movement-area you have in your game, assuming if you like to do last minute level design

Thus, I've decided to make an AI which doesn't need to depends on the waypoints to move around, and the solution is actually pretty simple. All I have to do, is to shoot 4 rays out of two different positions (left and right) around the AI, and check whether it detects any obstacle (wall, floor tiles). If they did, the AI would turn and change its direction.

Now I'm gonna explain how to actually do it, code-wise.

https://dl.dropbox.com/u/40305586/ZeroWaypointAi/ZeroWaypointAi.unitypackage

1. To start, I'll first create a few white coloured cubes as the "floor tiles", while a red coloured cube as the AI, and then change the camera to orthographic mode

2. Next, I'll create a new C# Behaviour Script, name it as "ZeroWaypointAi", and start making a few variables:

// length of raycast
public float rayLength = 1;

// number of units the ray's position will be away from player
public int rayPosUnit = 1;

// movement speed of the AI
public int speed = 2;

// something to move the AI later on
private Vector3 moveDirection;

3. Then, I'll create an enum called "WalkDirection", which contains two states: "WalkLeft" and "WalkRight", and then a private variable called "walkDir" for the enum.

private WalkDirection walkDir;

4. In the Start function, I'll randomly select a direction for the AI to walk to when the game start.

protected void Start()
{
int rand = Random.Range(0, 2);
if (rand == 0)
{
walkDir = WalkDirection.WalkLeft;
}
else
{
walkDir = WalkDirection.WalkRight;
}
}

5. In the Update function, I'll create a few new variables for the ray's shooting position.

protected void Update()
{
// need this to start shooting ray
RaycastHit hit;

// left pos is one "rayPosUnit" away from the AI's pos
Vector3 leftPos = transform.position;
leftPos.x -= rayPosUnit;

// right pos is one "rayPosUnit" away from the AI's pos
Vector3 rightPos = transform.position;
rightPos.x += rayPosUnit;
}

6. Under these variables, I'll start doing some if and else statement to check a few things:
- shoot a ray from the side which the AI is headed (left or right), to see whether there's any obstacle on that side. If the ray detected any obstacle, switch direction~!
- shoot a downwards ray from the side which the AI is headed (left or tight), to see whether there's still a floor for this AI to move towards. If there's no floor (means if it continue moving in that direction, it'll fall if you add gravity to it), switch direction~!

if (walkDir == WalkDirection.WalkLeft)
{
if (!Physics.Raycast(leftPos, -transform.up, out hit, rayLength))
{
// if it didn't hit anything, change direction
walkDir = WalkDirection.WalkRight;
}Debug.DrawRay(leftPos, -transform.up * rayLength, Color.green);
if (Physics.Raycast(transform.position, -transform.right, out hit, rayLength))
{
walkDir = WalkDirection.WalkRight;
}Debug.DrawRay(transform.position, -transform.right * rayLength, Color.green);

moveDirection.x = -speed * Time.deltaTime;
}
else if (walkDir == WalkDirection.WalkRight)
{
if (!Physics.Raycast(rightPos, -transform.up, out hit, rayLength))
{
// if it didn't hit anything, change direction
walkDir = WalkDirection.WalkLeft;
}Debug.DrawRay(rightPos, -transform.up * rayLength, Color.green);
if (Physics.Raycast(transform.position, transform.right, out hit, rayLength))
{
walkDir = WalkDirection.WalkLeft;
}Debug.DrawRay(transform.position, transform.right * rayLength, Color.green);

moveDirection.x = speed * Time.deltaTime;
}

*Note that I also added a line after the if and else statement:

moveDirection.x = speed * Time.deltaTime;

It's purpose it to move the AI along the X-axis by that amount of "speed".

7. Lastly, the AI won't be able to move itself without a proper function to move it. Thus, add one last line below the if and else statement:

// move the AI
transform.Translate(moveDirection);

The completed AI should look something like this:

If you tested out the ZeroWaypointAi package on Unity and clicked Play, you should be able to see in the "Scene", that two green rays (forward and downwards) are coming from the direction the AI is headed.

online courses said...

It gives corporate-wide information coordination, for the most part from at least one operational frameworks or outer data suppliers, and is cross-useful in extension. artificial intelligence course

Cho co said...

me up with some sort of fake birth certificate because as we know robots are not born. An artificial intelligence system could indeed have a better chance of winning elections by merely surfing the news, finding out what was on artificial intelligence certification

Anonymous said...

The image of the completed AI is missing

Data Science said...

You actually make it look so easy with your performance but I find this matter to be actually something which I think I would never comprehend. It seems too complicated and extremely broad for me.
I'm looking forward for your next post, I’ll try to get the hang of it!