Ghost Movement and A.I.
First create a single Sprite, and name it "Ghost". This one sprite object will be used for all the ghosts (this is a free-version workaround for the "Families" plugin). In the Animation frames window, import the sprite strip as before; delete all the non-ghost squares, set the animation Speed to 6 and Loop to Yes. Next, duplicate this animation 18 times for a total of 19 animations. (Yes, you read that correctly, nineteen animations total for the Ghost sprite.) Traditionally, the ghost names are Blinky (Red ghost), Pinky (Pink ghost), Inky (Blue ghost), and Clyde (Orange ghost). So rename the first 16 animations to Blinky0, Blinky90, Blinky180, Blinky270, Pinky0, Pinky90, Pinky180, Pinky270, Inky0, etc., up to Clyde270. Also rename one animation to Vulnerable, another to VulnerableBlink, and the final animation to Eaten. For the ghost-name specific animations, delete all the frames except the ones corresponding to the ghost name and direction reference in the animation name. For example, in Clyde90, delete all animation frames except the two containing an orange ghost looking down. (If this explanation is unclear, please view the animations in the capx file available for download at the Scirra Arcada.) In the Vulnerable animation, just keep the two frames with the wide-eyed blue ghost image; in the VulnerableBlink animation, keep the two frames with the wide-eyed blue ghost and the two frames with the wide-eyed white ghost; in the Eaten animation, just keep the one frame image consisting of only eyes.
Now the really fun part begins!
Next, we need two features: a way to keep track of the directions available to a ghost at any time, and a way to select among those directions (this will be the Artificial Intelligence (A.I.) part of the program).
The movement of the ghost sprite from tile square to tile square will be handled in much the same way that the PacMan movement was handled in the previous part of this tutorial, so add the Bullet behavior to the Ghost object.
Add the following instance variables to the Ghost sprite:
Direction, MoveDuration, TargetX, TargetY (all numbers). These will serve the same purposes as they did for the PacMan sprite.
Also add to the ghost an instance variable called "GhostName" (text) and VulnerableTimer (number).
Create four instances of the Ghost sprite on the main layout in four separate locations (not overlapping walls), and for each of these ghosts, click on them and in the Properties panel, under the Instance Variables section, change the name of one to Blinky, another to Pinky, another to Inky, and the final one to Clyde.
To store the list directions available to a ghost, there are multiple options (such as a string containing options separated by commas), but I find the Array object to be the easiest to work with because of all the built-in functionality. Right-click on the layout, select "Insert new object", and click on Array. Rename it to "AvailableDirections" or something similar. We are going to use it as a list, so it will be an N by 1 by 1 array; N will be between 0 and 4, depending on how many directions are available to a ghost at a given position.
In the event sheet, create a new Group called "Ghost Movement"; this is where we will include all of the following code (again, for organizational purposes).
Next, set up the following events, which we be explained below. (The comments are optional, but in general are a really good idea to include.)
We will be using some loops (these events are located under System) to keep the total number of events manageable. First is a for-each loop - we want each Ghost to follow the same set of events. Beneath this is the subevent to check if Bullet Speed = 0. If it isn't zero, then the ghost is in the middle of moving and no actions need to be taken at this time. Everything that follows is a subevent of this.
First, we set set the AvailableDirections array size to (0,1,1). This basically "clears" the list.
Next is a System for loop (not to be confused with a for-each loop). The purpose of this is to check each of the four directions (0 degrees, 90 degrees, 180 degrees, 270 degrees) to see if there is a wall in the way.
Create a global variable named "n" (a number). This, again, is just for convenience. We will reuse this variable frequently. (If variable declarations did not count as events, or if we weren't worried about keeping the number of events low, we could instead create local variables as necessary.)
We set the for loop to start at 0 and end at 3, and at each step set:
n = 90 * (value of loop index)
The value of the loop index is obtained by the expression loopindex(name_of_loop). Therefore, in this loop the variable n will take on the values 0, 90, 180, and 270. Then, using a little bit of trigonometry, we set the position of the CollisionDetector sprite to the square adjacent to the position of the ghost; we set
CollisionDetector.X = Ghost.X + cos(n) * TileSize
CollisionDetector.Y = Ghost.Y + sin(n) * TileSize
and check to see if the CollisionDetector sprite is overlapping a Wall sprite. If this is not the case, then the adjacent tile in the direction of the angle n is available for the ghost to travel on the next movement. This information is added to the list of possible directions by using the Array command "push". We push it onto the "X axis" because we using the array as a list, not a grid. Also, using "push front" or "push back" is irrelevant for our purposes, either will do. Once this information is calculated, our next step is to select the direction in which a ghost will travel.
...to be continued...
In the meantime, feel free to check out the finished capx file, available for download at the Scirra Arcade: