using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; namespace PacMan { /// /// The template for an AI controlled ghost /// public class Ghost : Creature { private const int EATEN_SPEED = 6; private const int EATEN_DURATION = 121; private const int FRIGHTENED_SPEED = 3; private const int FRIGHTENED_DURATION = 121; private const int ANIMATION_FRAMES = 2; private const int START_LOCATION_X = 300; private const int START_LOCATION_Y = 270; private Bitmap[][][] image; private GhostMode behaviourType; private Point location_cellIndex; private int frightenedDurationCountdown; private int eatenDurationCountdown; public Ghost(string colour) : base(START_LOCATION_X, START_LOCATION_Y) { initialiseImageArray(colour); behaviourType = GhostMode.Aggressive; speed = BASE_SPEED; imageToggle = 0; location = new Point(START_LOCATION_X, START_LOCATION_Y); } /// /// Fills up the ghosts image array /// /// private void initialiseImageArray(string colour) { int nPossibleDirections = Enum.GetNames(typeof(Direction)).Length; int nPossibleStates = Enum.GetNames(typeof(GhostMode)).Length; //jagged array of brain bleeding //------------------------------ //This declares that the image jagged-array begins with an outer layer/array of a size equal to the number of different states a ghost can be in. image = new Bitmap[nPossibleStates][][]; //AGGRESSIVE MODE //This declares the size of the middle layer/array for the aggressive state. image[(int)GhostMode.Aggressive] = new Bitmap[nPossibleDirections][]; //for each slot in the middle array (which represents directions) for (int directionSlot = 0; directionSlot < nPossibleDirections; directionSlot++) { //Declares the size of the innermost array (which represents number of animation frames) image[(int)GhostMode.Aggressive][directionSlot] = new Bitmap[ANIMATION_FRAMES]; string[] directionName = Enum.GetNames(typeof(Direction)); //Puts the image in! for (int frameSlot = 0; frameSlot < image[(int)GhostMode.Aggressive][directionSlot].Length; frameSlot++) { string imageLocation = "PacManSprites/ghost" + colour + directionName[directionSlot] + (frameSlot + 1) + ".png"; image[(int)GhostMode.Aggressive][directionSlot][frameSlot] = new Bitmap(imageLocation); } } //RANDOM MODE //This declares the size of the middle layer/array for the aggressive state. image[(int)GhostMode.Random] = new Bitmap[nPossibleDirections][]; //for each slot in the middle array (which represents directions) for (int directionSlot = 0; directionSlot < nPossibleDirections; directionSlot++) { //Declares the size of the innermost array (which represents number of animation frames) image[(int)GhostMode.Random][directionSlot] = new Bitmap[ANIMATION_FRAMES]; string[] directionName = Enum.GetNames(typeof(Direction)); //Puts the image in! for (int frameSlot = 0; frameSlot < image[(int)GhostMode.Random][directionSlot].Length; frameSlot++) { string imageLocation = "PacManSprites/ghost" + colour + directionName[directionSlot] + (frameSlot + 1) + ".png"; image[(int)GhostMode.Random][directionSlot][frameSlot] = new Bitmap(imageLocation); } } //FRIGHTENED MODE //This declares the size of the middle layer/array for the frightened state. image[(int)GhostMode.Frightened] = new Bitmap[1][]; //Declares the size of the innermost array (which represents number of animation frames) image[(int)GhostMode.Frightened][0] = new Bitmap[ANIMATION_FRAMES]; //Puts the image in! for (int frameSlot = 0; frameSlot < image[(int)GhostMode.Frightened][0].Length; frameSlot++) { string imageLocation = "PacManSprites/ghostEdible" + (frameSlot + 1) + ".png"; image[(int)GhostMode.Frightened][0][frameSlot] = new Bitmap(imageLocation); } //EATEN MODE //This declares the size of the middle layer/array for the Eaten state. image[(int)GhostMode.Eaten] = new Bitmap[1][]; //Declares the size of the innermost array (which represents number of animation frames) image[(int)GhostMode.Eaten][0] = new Bitmap[ANIMATION_FRAMES]; //Puts the image in! for (int frameSlot = 0; frameSlot < image[(int)GhostMode.Eaten][0].Length; frameSlot++) { string imageLocation = "PacManSprites/ghostDeadEyes" + (frameSlot + 1) + ".png"; image[(int)GhostMode.Eaten][0][frameSlot] = new Bitmap(imageLocation); } adjustImageSizeAndTransparency(); } /// /// Adjusts the size and transparency of the ghost's image array /// private void adjustImageSizeAndTransparency() { for (int behaviourSlot = 0; behaviourSlot < image.Length; behaviourSlot++) { for (int directionSlot = 0; directionSlot < image[behaviourSlot].Length; directionSlot++) { for (int frameSlot = 0; frameSlot < image[behaviourSlot][directionSlot].Length; frameSlot++) { //makes all the images in the ghost image array the same size. Bitmap nicelySizedBitmap = new Bitmap(image[behaviourSlot][directionSlot][frameSlot], IMAGE_SIZE, IMAGE_SIZE); image[behaviourSlot][directionSlot][frameSlot] = nicelySizedBitmap; //makes the background of images transparent. Decides on the colour to make transparent based on top left pixel of image. Color transparentColour = image[behaviourSlot][directionSlot][frameSlot].GetPixel(0, 0); image[behaviourSlot][directionSlot][frameSlot].MakeTransparent(transparentColour); } } } } /// /// Specifies the specific ghost image to draw at its current location /// /// public override void Draw(Graphics graphics) { //current direction gets modded by the length of the direction array. //this prevents an index out of range exception on arrays that have a direction array length of size 1 int directionSlot = (int)direction % image[(int)behaviourType].Length; graphics.DrawImage(image[(int)behaviourType][directionSlot][imageToggle], location); } /// /// Randomises the direction the ghost moves in. /// Specifies that a ghost should not move in the opposite direction of the one he's currently moving in. /// /// /// public void RandomiseDirection(Random rand, Grid dataGrid) { int nPossibleDirections = Enum.GetNames(typeof(Direction)).Length; Direction tempDirection = (Direction)rand.Next(nPossibleDirections); Point attemptedLocation = GetNextLocation(tempDirection); //while the direction randomised is the opposite direction of the one he's currently moving in, randomise again. while (((int)tempDirection == (((int)direction + 2) % nPossibleDirections)) || (dataGrid.CheckForWall(attemptedLocation) == true)) { tempDirection = (Direction)rand.Next(nPossibleDirections); attemptedLocation = GetNextLocation(tempDirection); } direction = tempDirection; } /// /// Determines the location the user is trying to move to /// /// /// public Point GetNextLocation(Direction directionToMove) { Point attemptedLocation = location_cellIndex; switch (directionToMove) { case Direction.Up: attemptedLocation.Y--; break; case Direction.Left: attemptedLocation.X--; break; case Direction.Right: attemptedLocation.X++; break; case Direction.Down: attemptedLocation.Y++; break; default: break; } return attemptedLocation; } /// /// Changes the ghost's position to a new valid position /// /// /// public void Move(Random rand, Grid dataGrid) { //checks to see if the ghost is perfectly aligned with a cell if ((location.X % IMAGE_SIZE == 0) && (location.Y % IMAGE_SIZE == 0)) { location_cellIndex = new Point((location.X / IMAGE_SIZE), (location.Y / IMAGE_SIZE)); RandomiseDirection(rand, dataGrid); switch (direction) { case Direction.Up: location.Y -= speed; break; case Direction.Left: location.X -= speed; break; case Direction.Right: location.X += speed; break; case Direction.Down: location.Y += speed; break; default: break; } imageToggle++; imageToggle %= ANIMATION_FRAMES; } else { switch (direction) { case Direction.Up: location.Y -= speed; break; case Direction.Left: location.X -= speed; break; case Direction.Right: location.X += speed; break; case Direction.Down: location.Y += speed; break; default: break; } imageToggle++; imageToggle %= ANIMATION_FRAMES; } } /// /// Updates the ghost's mode /// public void UpdateMode() { switch (behaviourType) { case GhostMode.Aggressive: break; case GhostMode.Frightened: if (frightenedDurationCountdown > 0) { frightenedDurationCountdown--; } else { BehaviourType = GhostMode.Aggressive; } break; case GhostMode.Eaten: if (eatenDurationCountdown > 0) { eatenDurationCountdown--; } else { BehaviourType = GhostMode.Aggressive; } break; case GhostMode.Random: break; default: break; } } /// /// Gets the ghosts current location /// public Point Location { get { return location; } } /// /// Gets/Sets the ghost's behaviour type /// public GhostMode BehaviourType { get { return behaviourType; } set { behaviourType = value; switch (behaviourType) { case GhostMode.Aggressive: speed = BASE_SPEED; break; case GhostMode.Frightened: speed = FRIGHTENED_SPEED; int nPossibleDirections = Enum.GetNames(typeof(Direction)).Length; direction = (Direction)(((int)direction + 2) % nPossibleDirections); frightenedDurationCountdown = FRIGHTENED_DURATION; break; case GhostMode.Eaten: speed = EATEN_SPEED; eatenDurationCountdown = EATEN_DURATION; break; default: break; } } } } }