Lab 8: AI

In today's lab we'll work on extending our sprites example to include some basic AI pursuit capabilities and some related bells and whistles.

Specifically, we'll carry out the following modifications:

As usual, begin by creating the lab8 directory:


   cd  games
   mkdir lab8
   cd lab8
Then copy/save today's lab files: ship.gif, star.gif, backdrop.gif, game8.py.

Make the python files executable and open the game8.py


   chmod  u+x  *.py
   gedit game8.py &

Step 1: scaling factor

This first part is just a maintenance simplification: instead of having numeric values scattered throughout the code for scaling up/down the size and speed of the ship we will use a single variable within the game objects.

First, this involves adding the definition in the game object class, e.g.

Second, in the routines changeSpeed and changeScale we replace the old numeric resizing of self.velocity and self.scale:

Step 2: ship ids

Next, we'll let each game object have an integer id value associated with it, and allow the game to assign id's when the object is first created.

This requires an update to the ship constructor (__init__ routine):

It also means the main routine needs to pass along values when the constructors are first called, e.g. 10001, 10002, 10003 in the calls below:

Having done this, the various output routines can now name which specific ship is being manipulated (helps in debugging and reporting), e.g.:

Step 3: ship health

In addition to the ship id, we'll also add a ship health stat, that starts off at 100 and ultimately gets reduced during collisions.

This involves adding one more line of code to the game object constructor (__init__ routine):

Step 4: tracking player ship

The various AI ships will need to know which ship currently belongs to the player, so they can chase it appropriately.

We used to use the field selected in the game objects to keep track of whether the current ship was player controlled or not, now we'll simply use that to keep track of specifically which ship the player controls.

This means a minor change to the __init__ routine:

The changeSelected routine also needs to change:

Next, the event handler needs to change to tell all ships whenever the player picks a new ship to control, e.g.

Finally, the main handling routine needs to change to tell all ships which one the player initially controls, e.g.

Step 5: collision detection

Within the game object update routine, if the current object is AI controlled then we'll have it check to see if it is currently colliding with the player ship.

If there is a collision, then have the player's ship lose some health, and end the game if the player's health drops below 0, e.g.

Step 6: random repositioning

We can add another snippet to the code from step 5, having the AI ship jump to a random location after the collision:

Of course, this means that we need to specify that the update routine uses globals scrWidth and scrHeight, e.g.

This also means that we need to import the random module along with the others at the beginning of the program, e.g.

Finally, this requires that, during the gameSetup routine, we initialize the random number generator. This is done with a built-in seed routine:

Step 7: ai pursuit

The interesting bit is getting the AI to chase the player around the map. To do so, we'll add (in GameObject) a routine called chasePlayer that tries to match the player's zoom level and speed, and figures out roughly which direction the AI should be facing to be pointed "at" the player's current ship.

Next, we need to decide how often the AI will update it's pursuit path.

In the grand scheme of things, the relative positioning of the AI and player ship won't change hugely from update to update, since those are only 40 or 50 milliseconds apart.

As a result, it might be more efficient to give the AI a chance of updating its chase routine each time the update routine is called, e.g. in the update routine just after it figures out this is an AI ship...

It might also be advisable for the AI ships to re-think their pursuit plotting whenever the player switches ships, e.g.

Step 8: wrap-around

This might be a bit easier to keep track of if we have the ships 'wrap-around' when they go off screen edges, which is a basic modification to the game object update routine:

Final version