0% found this document useful (0 votes)
86 views

Aitutorial

Uploaded by

api-221565865
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
86 views

Aitutorial

Uploaded by

api-221565865
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 12

Patrol Sight Follow

Introduction
In this Tutorial we will be building Enemy Ai for a 2D platformer using Game Maker. Our Enemy will Patrol an area, Follow the player and return to his patrol Area when he loses sight of the player. We will then learn how to use this enemy object as a parent for different types of enemy. This is an intermediate level tutorial, it will be assumed that you are already familiar with Game Maker's interface ,that you know how to create objects, events and that you have used GML (Game Maker Language) before. If you get stuck check out http://wiki.yoyogames.com/index.php/My_First_ Game for help with the basics and don't forget the help files.

Platformer Ai in Game Maker Getting ready


Use the links below to download the required files. The following projects are set up so that you can follow along. If you would like to learn how to set up the player character you can follow the following Tutorial.
www.youtube.com/watch?v=9w4wOCNEa1c

GM:Studio GM8.1

www.dropbox.com/s/lfzf1vpdvgg8cmf/aiTutStudio.zip

www.dropbox.com/s/4bckqyh086za80z/aiTut8.1.zip

Movement
Before we can get any of our planned behaviours working we need movement. Open up parEnemy and add a Create event. In the drag and drop menu click the control tab and drag in an execute code node. These variables will control the player movement. The boolean eneDir will be used to control the enemy's direction. eneSpeed will control the speed. Failing to initialize variables may result in an error when running the game.

Create

eneDir = 1; eneSpeed = 1;

image_xscale is a variable that will set the scale of an images width. Using a negative value will flip the image on its origin. If you are using your own sprites make sure the origin is set in the center along x.

Add a step event. Drag in an execute code node and add the following code. To go left we subtract player's horizontal speed (hsp) to a negative value

AI Tutorial

Sara Galea - J9108411

When eneDir is set to 0, hsp will be set to -eneSpeed. The Values are reversed when eneDir is 1. hsp is then used to set the enemies x value which will cause it to move. eneDir = 0

Step
//left if eneDir = 0 { hsp = -eneSpeed ; image_xscale = -1 ; } //right if eneDir = 1 { hsp = eneSpeed ; image_xscale = 1 ; } //input movement x += hsp ;

hsp = -eneSpeed ; image_xscale = -1 ; eneDir = 1

hsp = eneSpeed ; image_xscale = 1 ;

If you place the enemy in the test room and run the game you can see it move to right. If you set the variable eneDir to 0 it will move to the left instead. We got the enemy to move but he will go straight through the walls, off the screen and does not fall down if he's placed off the ground. In order to create gravity Go back to the Create Event and add the following variables. vsp will represent the Vertical speed, grav is gravity and grounded will be used to check if the player is currently touching the ground or not.

Create

vsp = 0; grav= 0.5; grounded = true;

place_meeting(x,y, obj) Checks for a collision between two instances at the coordinate x,y.

In the step event, the value for gravity will be added to the vsp every step causing the enemy to move down. Without collision the enemy would fall forever. The Vertical Collision statement will cause the enemy to collide with objSolid. The while statement moves the enemy a pixel down every step until the two objects are touching. This will avoid problems where the enemy gets stuck in the floor. As you add more code make sure that the code under //input movement is at the very bottom.

AI Tutorial

Sara Galea - J9108411

Step

//gravity vsp += grav; //vertical Collision / landing if place_meeting(x,y+vsp,objSolid) { while !place_meeting(x,y+1,objSolid) y += 1 ; vsp = 0 ; grounded = true ; } else { grounded = false } //input movement y += vsp ;

place_meeting(x,y+vsp,objSolid)

!place_meeting(x,y+1,objSolid)
pixel

vsp

vsp = 0 grounded = true

y += 1

The next step is to get the enemy to jump over small obstacles and turning a round at obstacles that are too high. These statements will check what is in front of the enemy allowing us to code in reactions. Now you'll be able to see how using eneDir allows us to change the enemies direction. The variable grid is used to represent the grid size just in case it has to be changed later on.

Create

grid = 32; eneJump = 0; leap = 9;

sign checks if a number if positive of negative, returning 1 for positive numbers and -1 for negative numbers.

AI Tutorial

Sara Galea - J9108411

Step

// jump if eneJump && grounded { vsp = -leap }

//low obstacle if place_meeting(x+hsp,y,objSolid) { eneJump = true; alarm[0] = 5; while !place_meeting(x+sign(hsp),y,objSolid) x += sign(hsp); hsp = 0 ; } // turn around at tall object if eneDir = 0 && place_meeting(x-8,y,objSolid) && place_meeting(x-8,y-grid,objSolid) { eneDir = 1 ; } if eneDir = 1 && place_meeting(x+8,y,objSolid) && place_meeting(x+8,y-grid,objSolid) { eneDir = 0 ; }

place_meeting(x+hsp,y,objSolid)

!place_meeting(x+sign(hsp),y,objSolid)

hsp

hsp

eneJump = true alarm[0] = 5

hsp = 0 x += sign(hsp)

hsp = eneSpeed eneJump = false

If you run the game now you will notice the player will not stop jumping after leaping over the first obstacle. This is because we have not yet created the alarm event called in our low obstacle statement. Add an alarm event to parEnemy and enter the following line of code.

Alarm 0

enejump = false;

Our alarm will be executed 5 steps after it is triggered allowing for the enemy to jump onto the obstacle before eneJump is set to false again. Now that our movement system is complete we can start working towards the behaviours we discussed in the beginning of the tutorial.

AI Tutorial

Sara Galea - J9108411

Patrol
Patrol is the easiest part. We will be setting boundaries around the enemys spawn point and restricting the enemy to walk between those 2 points. The Create code sets up the patrol area. To make the area bigger just increase the values of lB and rB.

Create

lB = grid*2; rB = grid*1.5; //Distance from spawn point leftBound = x - lB; rightBound = x + rB; patrol = true;

Step

if patrol { if x < leftBound { eneDir = 1 } if x > rightBound { eneDir = 0 } }

Patrol area

x > rightBound x < leftBound Patrol area

x 0 leftBound x + grid *2 x rightBound x + grid *1.5

x 0 eneDir = 1 eneDir = 0

That is it for the patrol code, if you run the game you'll see the enemy going back and forth around his spawn point.

AI Tutorial

Sara Galea - J9108411

Sight
To get the enemy to sight the player.

Step
// if if if if

blocked = collision_line(x,y,objPlayer.x,objPlayer.y,objSolid,0,1) movement in eneDir == 0 eneDir == 0 eneDir == 1 eneDir == 1 relation to the player && objPlayer.x < x { towards && objPlayer.x > x { towards && objPlayer.x > x { towards && objPlayer.x < x { towards = = = = true } false} true } false}

//is player visible if blocked < 0 && towards { patrol = false ; follow = true ; } if blocked > 0 { follow = false; patrol = true ; }

The collision line drawn between the player and the enemy will determine if there are any objects between them. By comparing which way the enemy is walking against the Player's position in relation to the enemy we can determine if the enemy is facing the player on not. This will allow the player to walk behind the enemy without being spotted. x2,y2 x1,y1

collision_line(x1,y1,x2,y2,obj ,prec,notMe) creates a line between the coordinates given and returns the id of any instance of obj intersecting the line. Returns -1 when there are no collisions.

blocked = collision_line(x1,y1,x2,y2,objWall,0,1) x2,y2 x1,y1

blocked = -1 towards = true follow = true patrol = false


AI Tutorial

blocked = idWall towards = true follow = false patrol = true


Sara Galea - J9108411 6

eneDir == 1 and objPlayer.x < x

eneDir == 0 and objPlayer.x < x

x 0 towards = false; eneDir == 1 and objPlayer.x > x

x 0 towards = true; eneDir == 0 and objPlayer.x > x

x 0 towards = true;

x 0 towards = false;

If you run the game and hop in front of the enemy you'll see he'll leave his patrol state and resume his patrol state when the player is hidden again. The enemy will walk the whole length of the room.

Follow
The following code will have the enemy set his direction based on were the player is every 20 to 30 steps (30 steps = 1 second). I used random_range as opposed to putting in one value so that the enemy would not always take the same amount of time to turn around. Making these values higher means the enemy will take longer to change direction when the player changes direction. objPlayer.x < x

Create

checkPos = true; //Reaction Time rL = 25; //range low rH = 30; //range high

objPlayer.x > x

x 0 eneDir = 0

x 0 eneDir = 1

AI Tutorial

Sara Galea - J9108411

Step

//Follow if follow { //reaction time if checkPos { if objPlayer.x < x + grid { eneDir = 0 } if objPlayer.x > x - grid { eneDir = 1 } checkPos = false; alarm[1] = random_range(rL,rH); } }

Alarm 1

checkPos = true;

random_range(x1,x2) will pick a random float value between the values x1, and x2.

Speed
This pretty much completes the parent object for our enemy AI but first I would like to have the enemy change his speed when in different states.

Create

dSpeed = 1.5;

Step

if follow { eneSpeed = dSpeed * 2; if patrol { eneSpeed = dSpeed;

We will use this new variable to alter the player speed. Place the new code within the existing statements for Follow and Patrol.

AI Tutorial

Sara Galea - J9108411

Attack
Now that our Parent enemy is set up we'll look at how we can build on or alter this code using child objects. First however we will go back to the Create event in parEnemy and organize our variables. I put the variables that can be changed to simulate different enemy types at the top. Duplicate parEnemy (Alt + Insert). We will use this new object to set up an enemy with a ranged attack so I renamed it objEnemyRng. Delete all the events in this new object except the Create event. We are keeping this event as we'll need to add more variables to this object. Set parEnemy as the parent. Next we added a Begin Step event. We didn't use a step event like we did in parEnemy because that would completely replace the code as opposed to adding to it.

Create
grid= 32; /// Customize /// //distance from spawn point in Patrol lB = grid*2 ; rB = grid*1.5; //Speed dSpeed = 1.5; //jump speed leap = 9; //weight grav = 0.5; //Reaction Time when following player rL = 25; //range low rH = 30; //range high //Initial Direction eneDir = 1; 0 = left; 1 = right

////////////////////////// //movement hsp = 0; vsp = 0; grounded = true; eneJump = false ; eneSpeed = defaultSpeed; //Distance from spawn point spawnPoint = x ; leftBound = x - lB; rightBound = x + rB; //States patrol = true; follow = false; checkPos = true;

AI Tutorial

Sara Galea - J9108411

Create
/// Customize /// //time between shots t1 = 20; t2 = 30; //Max distance to attack from triggerDis = grid*5; //States shoot = true;

Alarm 2

shoot = true;

instance_create( x,y,obj) creates an instance of the specified object at the coordinate x,y.

Begin Step
if distance_to_object(objPlayer) < triggerDis && follow && shoot { instance_create(x,y,parPro); // space out shots shoot = false; alarm[2] = random_range(t1,t2);

distance_to_object(objPlayer) < triggerDis && follow && shoot

triggerDis instance_create(x,y,parPro) shoot = false alarm[2] = 5

shoot = true

Open the test room and replace parEnemy with our newly created enemy. If you test the game now you should see the enemy will now start creating projectiles when the Follow state is triggered.

AI Tutorial

Sara Galea - J9108411

10

Open parPro and add the following code. This code will set the projectile's direction based on the eneDir variable of the enemy that fired it.

Create

//hp removed damage = 1;

enemy = instance_place(x,y,objEnemyRng) //Direction if enemy.eneDir = 1 { hspeed = 10; gravity = 0.02} if enemy.eneDir = 0 { hspeed = -10; gravity = 0.02}

eneDir = 1

eneDir = 0 instance_place(x ,y,obj) Returns the instance id of the instance of obj at x,y.

hspeed = 10; gravity = 0.02

hspeed = -10; gravity = 0.02

hspeed Variable built in all objects, Controls horizontal speed. Its value is added to the objects x value every step.

gravity Variable built in all objects, Its value is added to the objects vspeed every step.

If you would like your projectile to work on different types of objects you can create a new object, objPawn and set it as the parent of objPlayer and any other objects youd like to effect. This will allow you to check for all objects at once instead of having to create separate statements.

place_meeting(x,y,objPawn)

pawnHit = instance_place(x,y,objPawn) pawnHit .hp - = 1 instance_destroy()

AI Tutorial

Sara Galea - J9108411

11

Step
//remove when pawn is hit if place_meeting(x,y,objPawn) { pawnHit = instance_place(x,y,objPawn); instance_destroy(); pawnHit.hp -= damage;

//remove when wall is hit / outside the room if place_meeting(x,y,objSolid) or x > room_width or x < 0 { instance_destroy();

Challenges
Use child objects to create your own projectiles with different damage amounts and speeds. Change the range of your projectile to simulate melee attacks. Set up an attack for the player.

AI Tutorial

Sara Galea - J9108411

12

You might also like