Pac man Game(Not completed) Asking for assistance

//Variables
//user variables
int paxX=246, paxY=246;
//Gost variables
float gostX=245, gostY=245;
//Food Variables
int FoodX[] = new int [2401];
int FoodY[] = new int [2401];
//array used for eaten food
float foodeat[] = new float [2401];
//if food is in wall
int foodinwall;
//Level
int level=1;
//Lives
int lives=3;
//Score
int score=0;
int cupcake=0;
//Images
PImage Maz; //Maze image
PImage Food; //Food image
PImage Gost; //Gost image
//Setup for game
void setup(){
  //setup,basic
  frameRate(60);
  size(500,500);
  noStroke();
  smooth();
  //Load images
  Images();
  //Sets food/starting locations
  Food();
}//eND sETUP

void draw(){
  background(0);
  Gost();
  Maz();
  pax_user();

}
 //Food
 void Food(){
  for (int f=0; f < 2401; f++) {
    //determination if food was eaten
    if (Foodeat[f]==0){
      //If food has not been eaten, draw
      image (Food, FoodX[f], FoodY[f]);
      foodinwall=get (FoodX[f]-1, FoodY[f]+1);
      //text(""+ foodinwall,100,200);
      if (foodinwall == -1.6777216E7){
        foodeat[f]=1;
        cupcake=cupcake+1;
      }

      if(paxX==FoodX[f] && FoodY[f]==paxY){
        //if pax eats food
        foodeat[f]=1;
        //add score
        cupcake=cupcake+1;
        score=score+1;
      }

    }
  }
 }//End Food

 void foodsetup(){
   foodX[0]=6;
   foodY[0]=6;
   //other pieces of food
   for (int i=1; i < 2401; i++){
     foodX[i]=foodX[i-1]+10;
     foodY[i]=foodY[i-1];
     //if at edge of screen, reset and layer is put down.
     if(foodX[i] ==496){
       foodX[i]=6;
       foodY[i]=foodY
   }

void Gost() {
  //gost is left of pax
  if(paxX>GostX) {
    //moves towards pax at specific speed
    GostX=GostX+level-3;
  }
  //gost right of pax
  (paxX<GostX) {
    //moves towards pax at spesific speed
    GostX=GostX-level+3;
  }
  //gost above pax
  (paxY>GostY){
    //moves toward pax at specific speed
    GostY=GostY+level-3;
  }
  //gost be low pax
  (paxY<GostY){
    //moves towards pax at specific speed
    GostY=GostY-level+3;
  }

  //Draw Gost
  image(Gost,GostX,GostY);
  //End gost
}

void images(){
 //Images load
 //Maze
 Maz = loadImage("Maz.jpg");
 //Food
 Food = loadImage("Food.jpg");

void Maz(){
//Draw Maze
if(playmaze==1){
  image(Maz,0,0);
}

}//End maz

void pax_user(){
  //user movement
  if (keyPressed) {
    if (key==CODED) {
      if (keyCode==RIGHT){
        paxX=paxY+5;
      }
      if(keyCode==LEFT){
        paxX=paxY-5;
      }
      if(keyCode==DOWN){
        paxY=paxX+5;
      }
      if(keyCode==UP){
        paxY=paxX-5;
      }
    }
  }
  //Drawimage
  image(pax,paxX,paxY);
}//end user draw
Tagged:

Answers

  • Start by trying to run your own code. You're immediately missing a semicolon.

    Fix that, try running it again. You have braces that are unmatched.

    Fix those, try running it again. You are missing if keywords.

    Fix those, try running it again. The function Images() is not images().

    Fix that, try running it again. Variable Foodeat is not foodeat.

    Fix that, try running it again. Variable foodX is not FoodX, and foodY is not FoodY. Go with foodX and foodY throughout.

    Fix that, try running it again. Now you're trying to assign a float (foodY[i]) the value of an float[] (foodY). Not sure how to fix that one for you. Removing offending line.

    That line removed, try running it again. Variable GostX and GostY are not gostX and gostY. Go with gostY and gostX.

    Fix that, try running it again. Variable playmaze is undefined. Removing reference to it.

    Fix that, try running it again. Variable pax is undefined. Replacing trying to draw that image with a yellow ellipse.

    ... Here ends the syntax errors. Debugging this further is probably not possible without your images. Please post them.

  • OR...

    Scrap this completely and start from scratch. Start with a blank sketch and gradually add working elements to it. Did you know that PacMan actually uses an underlying grid to determine where the walls are?

    void setup() {
      size(601, 601);
    }
    
    void draw() {
      background(0);
      noFill();
      stroke(128, 128, 255);
      for (int j=0; j<height/20; j++) {
        for (int i=0; i<width/20; i++) {
          rect(20*i, 20*j, 20, 20);
        }
      }
    }
    
  • Now, how do you determine where the walls are? You'll need some kind of an array to track that information.

    boolean[][] is_wall = new boolean[30][30];
    
    void setup() {
      size(601, 601);
      for (int j=0; j<height/20; j++) {
        for (int i=0; i<width/20; i++) {
          is_wall[j][i] = (random(1) < .5);
        }
      }
    }
    
    void draw() {
      background(0);
      stroke(128, 128, 255);
      for (int j=0; j<height/20; j++) {
        for (int i=0; i<width/20; i++) {
          noFill();      
          if (is_wall[j][i]) { 
            fill(0, 0, 255);
          }
          rect(20*i, 20*j, 20, 20);
        }
      }
    }
    

    Random walls were good enough for this step.

  • edited June 2015

    Now we want a character! Since the character will probably need many variables to track things about it, we don't want to use a bunch of different variables - we might get confused. Instead, we'll write the character as it's own object. Here, I've only included things like it's position and direction, encapsulated into a Player class

    class Player {
      float x,y;
      int d;
      Player(){
        x = 30;
        y = 30;
        d = 3;
      }
      void draw(){
        simulate();
        render();
      }
      void simulate(){
        if(0==d){ y--; }
        if(1==d){ y++; }
        if(2==d){ x--; }
        if(3==d){ x++; }
      }
      void render(){
        pushMatrix();
        translate(x,y);
        stroke(0);
        fill(255,255,0);
        ellipse(0,0,22,22);
        fill(0);
        arc(0,0,22,22,-.3,.3);
        popMatrix();
      }
    }    
    
    boolean[][] is_wall = new boolean[30][30];
    
    Player player;
    
    void setup() {
      size(601, 601);
      for (int j=0; j<height/20; j++) {
        for (int i=0; i<width/20; i++) {
          is_wall[j][i] = (0==i || 0==j || 29==i || 29==j);
        }
      }
      player = new Player();
    }
    
    void draw() {
      background(0);
      stroke(128, 128, 255);
      for (int j=0; j<height/20; j++) {
        for (int i=0; i<width/20; i++) {
          noFill();      
          if (is_wall[j][i]) { 
            fill(0, 0, 255);
          }
          rect(20*i, 20*j, 20, 20);
        }
      }
      player.draw();
    }
    

    I also made the walls less random.

  • Now I can fix things just inside the player class to make my player work better. For one, I want it to change direction. I also fix which number means which direction, so I can rotate it properly. I also add the chomping animation, which the player class can handle on it's own (so I don't need to fret about doing it in draw()!).

    class Player {
      float x, y;
      int d;
      float mouth_opening = 0, max_mouth_opening = .4;
      boolean is_mouth_opening = true;
    
      Player() {
        x = 30;
        y = 30;
        d = 0;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        if (0==d) { 
          x++;
        }
        if (1==d) { 
          y++;
        }
        if (2==d) { 
          x--;
        }
        if (3==d) { 
          y--;
        }
        animate_mouth();
      }
      void animate_mouth() {
        if (is_mouth_opening) {
          mouth_opening+=.01;
        } else {
          mouth_opening-=.01;
        }
        if (mouth_opening >max_mouth_opening || mouth_opening < 0) {
          is_mouth_opening = !is_mouth_opening;
        }
      }
      void render() {
        pushMatrix();
        translate(x, y);
        rotate(HALF_PI*d);
        stroke(0);
        fill(255, 255, 0);
        ellipse(0, 0, 22, 22);
        fill(0);
        arc(0, 0, 22, 22, -mouth_opening, mouth_opening);
        popMatrix();
      }
      void on_keyPressed() {
        if ( key == CODED ) {
          if ( keyCode == RIGHT ) { 
            d = 0;
          }
          if ( keyCode == DOWN ) { 
            d = 1;
          }
          if ( keyCode == LEFT ) { 
            d = 2;
          }
          if ( keyCode == UP ) { 
            d = 3;
          }
        }
      }
    }
    
    boolean[][] is_wall = new boolean[30][30];
    
    Player player;
    
    void setup() {
      size(601, 601);
      for (int j=0; j<height/20; j++) {
        for (int i=0; i<width/20; i++) {
          is_wall[j][i] = (0==i || 0==j || 29==i || 29==j);
        }
      }
      player = new Player();
    }
    
    void draw() {
      background(0);
      stroke(128, 128, 255);
      for (int j=0; j<height/20; j++) {
        for (int i=0; i<width/20; i++) {
          noFill();      
          if (is_wall[j][i]) { 
            fill(0, 0, 255);
          }
          rect(20*i, 20*j, 20, 20);
        }
      }
      player.draw();
    }
    
    void keyPressed() {
      player.on_keyPressed();
    }
    

    Notice that I also added the keyPressed() function, and instead of doing all the logic to deal with the player interacting with the key press there, I just let my Player class deal with it.

  • edited June 2015

    If you've been following along at home, you may have noticed that there's a pretty major issue with our player - it waltzes right over walls like they aren't there! We can easily fix this inside the Player class by remembering where the player was, and then checking if the new position after it moves is inside a wall - if it is, we just stay where we remembered we were.

    class Player {
      float x, y;
      int d;
      float mouth_opening = 0, max_mouth_opening = .4;
      boolean is_mouth_opening = true;
      Player() {
        x = 30;
        y = 30;
        d = 0;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        float px=x, py=y;
        if (0==d) { 
          x++;
        }
        if (1==d) { 
          y++;
        }
        if (2==d) { 
          x--;
        }
        if (3==d) { 
          y--;
        }
        if (is_on_wall()) {
          x = px;
          y = py;
        }
        animate_mouth();
      }
      void animate_mouth() {
        if (is_mouth_opening) {
          mouth_opening+=.01;
        } else {
          mouth_opening-=.01;
        }
        if (mouth_opening >max_mouth_opening || mouth_opening < 0) {
          is_mouth_opening = !is_mouth_opening;
        }
      }
      boolean is_on_wall(){
        int i = int(x/20);
        int j = int(y/20);
        return is_wall[j][i];
      }
      void render() {
        pushMatrix();
        translate(x, y);
        rotate(HALF_PI*d);
        stroke(0);
        fill(255, 255, 0);
        ellipse(0, 0, 22, 22);
        fill(0);
        arc(0, 0, 22, 22, -mouth_opening, mouth_opening);
        popMatrix();
      }
      void on_keyPressed() {
        if ( key == CODED ) {
          if ( keyCode == RIGHT ) { 
            d = 0;
          }
          if ( keyCode == DOWN ) { 
            d = 1;
          }
          if ( keyCode == LEFT ) { 
            d = 2;
          }
          if ( keyCode == UP ) { 
            d = 3;
          }
        }
      }
    }
    
    boolean[][] is_wall = new boolean[30][30];
    
    Player player;
    
    void setup() {
      size(601, 601);
      for (int j=0; j<height/20; j++) {
        for (int i=0; i<width/20; i++) {
          is_wall[j][i] = (0==i || 0==j || 29==i || 29==j);
          if (i==5 && j < 10) { // Temporary wall.
            is_wall[j][i] = true;
          }
        }
      }
      player = new Player();
    }
    
    void draw() {
      background(0);
      stroke(128, 128, 255);
      for (int j=0; j<height/20; j++) {
        for (int i=0; i<width/20; i++) {
          noFill();      
          if (is_wall[j][i]) { 
            fill(0, 0, 255);
          }
          rect(20*i, 20*j, 20, 20);
        }
      }
      player.draw();
    }
    
    void keyPressed() {
      player.on_keyPressed();
    }
    

    Also added is a temporary wall to test this on.

  • Now a pretty important aspect we're missing are the dots to eat. Since each grid square can either be a wall, a dot, a super dot, or empty space, we'll need to adjust our is_wall array to track the state for each square. Thus, we'll need to change it from being a simple 2D boolean array to one of integers. Let's use 0 for empty space, 1 for wall, 2 for dot, and 3 for super dot. We should also rename it to grid to denote that it's no longer a simple boolean array, but an actual structure that stores more information.

    class Player {
      float x, y;
      int d;
      float mouth_opening = 0, max_mouth_opening = .4;
      boolean is_mouth_opening = true;
      Player() {
        x = 30;
        y = 30;
        d = 0;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        float px=x, py=y;
        if (0==d) { 
          x++;
        }
        if (1==d) { 
          y++;
        }
        if (2==d) { 
          x--;
        }
        if (3==d) { 
          y--;
        }
        if (is_on_wall()) {
          x = px;
          y = py;
        }
        animate_mouth();
      }
      void animate_mouth() {
        if (is_mouth_opening) {
          mouth_opening+=.01;
        } else {
          mouth_opening-=.01;
        }
        if (mouth_opening >max_mouth_opening || mouth_opening < 0) {
          is_mouth_opening = !is_mouth_opening;
        }
      }
      boolean is_on_wall(){
        int i = int(x/20);
        int j = int(y/20);
        return (grid[j][i] == 1);
      }
      void render() {
        pushMatrix();
        translate(x, y);
        rotate(HALF_PI*d);
        stroke(0);
        fill(255, 255, 0);
        ellipse(0, 0, 22, 22);
        fill(0);
        arc(0, 0, 22, 22, -mouth_opening, mouth_opening);
        popMatrix();
      }
      void on_keyPressed() {
        if ( key == CODED ) {
          if ( keyCode == RIGHT ) { 
            d = 0;
          }
          if ( keyCode == DOWN ) { 
            d = 1;
          }
          if ( keyCode == LEFT ) { 
            d = 2;
          }
          if ( keyCode == UP ) { 
            d = 3;
          }
        }
      }
    }
    
    int[][] grid = new int[30][30];
    
    Player player;
    
    void setup() {
      size(601, 601);
      for (int j=0; j<height/20; j++) {
        for (int i=0; i<width/20; i++) {
          grid[j][i] = 2;
          if (0==i || 0==j || 29==i || 29==j){ grid[j][i] = 1; }
          if (i==5 && j < 10) { // Temporary wall.
            grid[j][i] = 1;
          }
        }
      }
      grid[20][20] = 3;
      player = new Player();
    }
    
    void draw() {
      background(0);
    
      for (int j=0; j<height/20; j++) {
        for (int i=0; i<width/20; i++) {
          noFill();      
          if (grid[j][i] == 1) { 
            fill(0, 0, 255);
          }
          stroke(128, 128, 255);
          rect(20*i, 20*j, 20, 20);
          if (grid[j][i] == 2) {
            fill(196);
            noStroke();
            ellipse(20*i+10,20*j+10,6,6);
          }      
          if (grid[j][i] == 3) {
            fill(255);
            noStroke();
            ellipse(20*i+10,20*j+10,12,12);
          }      
        }
      }
      player.draw();
    }
    
    void keyPressed() {
      player.on_keyPressed();
    }
    

    Man, all this messy grid logic sure is getting in the way of my simple and neat setup and draw functions. Also, these dots are kind of an eye sore. O_o

  • edited June 2015

    Tea break! Step back and think about it. The grid logic is a mess. It's cluttering up my setup() and draw() functions. What can I do about that?

    Think hard.

    Starts with an encap...

    Ends with a ...sulate it into it's own class!

    That's right! Encapsulate the grid into it's own class!

    Give yourself a gold star if you saw this step coming.

    class Player {
      float x, y;
      int d;
      float mouth_opening = 0, max_mouth_opening = .4;
      boolean is_mouth_opening = true;
      Player() {
        x = 30;
        y = 30;
        d = 0;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        float px=x, py=y;
        if (0==d) { 
          x++;
        }
        if (1==d) { 
          y++;
        }
        if (2==d) { 
          x--;
        }
        if (3==d) { 
          y--;
        }
        if (grid.is_wall(x,y)) {
          x = px;
          y = py;
        } else {
          animate_mouth();
        }
      }
      void animate_mouth() {
        if (is_mouth_opening) {
          mouth_opening+=.01;
        } else {
          mouth_opening-=.01;
        }
        if (mouth_opening >max_mouth_opening || mouth_opening < 0) {
          is_mouth_opening = !is_mouth_opening;
        }
      }
      void render() {
        pushMatrix();
        translate(x, y);
        rotate(HALF_PI*d);
        stroke(0);
        fill(255, 255, 0);
        ellipse(0, 0, 22, 22);
        fill(0);
        arc(0, 0, 22, 22, -mouth_opening, mouth_opening);
        popMatrix();
      }
      void on_keyPressed() {
        if ( key == CODED ) {
          if ( keyCode == RIGHT ) { 
            d = 0;
          }
          if ( keyCode == DOWN ) { 
            d = 1;
          }
          if ( keyCode == LEFT ) { 
            d = 2;
          }
          if ( keyCode == UP ) { 
            d = 3;
          }
        }
      }
    }
    
    class Grid {
      int[][] data = new int[30][30];
      Grid() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            data[j][i] = 2;
            if (0==i || 0==j || 29==i || 29==j) { 
              data[j][i] = 1;
            }
            if (i==5 && j < 10) { // Temporary wall.
              data[j][i] = 1;
            }
          }
        }
        data[20][20] = 3;
      }
      void draw() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            noFill();      
            if (data[j][i] == 1) { 
              fill(0, 0, 255);
            }
            stroke(128, 128, 255);
            rect(20*i, 20*j, 20, 20);
            if (data[j][i] == 2) {
              fill(196);
              noStroke();
              ellipse(20*i+10, 20*j+10, 6, 6);
            }      
            if (data[j][i] == 3) {
              fill(255);
              noStroke();
              ellipse(20*i+10, 20*j+10, 12, 12);
            }
          }
        }
      }
      boolean is_wall(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        return (data[j][i] == 1);
      }
    }
    
    Grid grid;
    Player player;
    
    void setup() {
      size(601, 601);
      grid = new Grid();
      player = new Player();
    }
    
    void draw() {
      background(0);
      grid.draw();
      player.draw();
    }
    
    void keyPressed() {
      player.on_keyPressed();
    }
    

    Also notice how I now have my Player asking the grid itself if there is wall at the position it is trying to move into. This makes more sense, because the grid is what knows where there is wall and where there is not wall. Eating dots comes next.

  • Eating dots is accomplish quite easily. When the player moves (and it might not!), it tells the grid to eat any dots at that position. The grid can check that position to see if the dot was a super dot, and if it was, it can tell the player to be super (as well as eating the dot at that position in any case). This then also requires that the player remember when it is super, as well as adding a countdown variable that will be used to determine how long the player is super for. For now, being super means you get to be a red player for 100 frames.

    class Player {
      float x, y;
      int d;
      float mouth_opening = 0, max_mouth_opening = .4;
      boolean is_mouth_opening = true;
      boolean am_i_super = false;
      int super_countdown = 0;
      Player() {
        x = 30;
        y = 30;
        d = 0;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        float px=x, py=y;
        if (0==d) { 
          x++;
        }
        if (1==d) { 
          y++;
        }
        if (2==d) { 
          x--;
        }
        if (3==d) { 
          y--;
        }
        if (grid.is_wall(x, y)) {
          x = px;
          y = py;
        } else {
          animate_mouth();
          grid.eat_dot_at(x, y);
        }
        if (super_countdown > 0) { 
          super_countdown--;
        }
        if (super_countdown == 0) { 
          am_i_super = false;
        }
      }
      void animate_mouth() {
        if (is_mouth_opening) {
          mouth_opening+=.01;
        } else {
          mouth_opening-=.01;
        }
        if (mouth_opening >max_mouth_opening || mouth_opening < 0) {
          is_mouth_opening = !is_mouth_opening;
        }
      }
      void be_super() {
        am_i_super = true;
        super_countdown = 100;
      }
      void render() {
        pushMatrix();
        translate(x, y);
        rotate(HALF_PI*d);
        stroke(0);
        fill(255, am_i_super?0:255, 0);
        ellipse(0, 0, 22, 22);
        fill(0);
        arc(0, 0, 22, 22, -mouth_opening, mouth_opening);
        popMatrix();
      }
      void on_keyPressed() {
        if ( key == CODED ) {
          if ( keyCode == RIGHT ) { 
            d = 0;
          }
          if ( keyCode == DOWN ) { 
            d = 1;
          }
          if ( keyCode == LEFT ) { 
            d = 2;
          }
          if ( keyCode == UP ) { 
            d = 3;
          }
        }
      }
    }
    
    class Grid {
      int[][] data = new int[30][30];
      Grid() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            data[j][i] = 2;
            if (0==i || 0==j || 29==i || 29==j) { 
              data[j][i] = 1;
            }
            if (i==5 && j < 10) { // Temporary wall.
              data[j][i] = 1;
            }
          }
        }
        data[5][10] = 3;
      }
      void draw() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            noFill();      
            if (data[j][i] == 1) { 
              fill(0, 0, 255);
            }
            stroke(128, 128, 255);
            rect(20*i, 20*j, 20, 20);
            if (data[j][i] == 2) {
              fill(196);
              noStroke();
              ellipse(20*i+10, 20*j+10, 6, 6);
            }      
            if (data[j][i] == 3) {
              fill(255);
              noStroke();
              ellipse(20*i+10, 20*j+10, 12, 12);
            }
          }
        }
      }
      boolean is_wall(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        return (data[j][i] == 1);
      }
      void eat_dot_at(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        if (data[j][i] == 3) {
         player.be_super();
        }
        data[j][i] = 0;
      }
    }
    
    Grid grid;
    Player player;
    
    void setup() {
      size(601, 601);
      grid = new Grid();
      player = new Player();
    }
    
    void draw() {
      background(0);
      grid.draw();
      player.draw();
    }
    
    void keyPressed() {
      player.on_keyPressed();
    }
    

    Looks good! Everything BOO so far is BOO! working, so now BOOOO!!! we're free to move on to adding BOOOOOOO!!!! something new! Hmmm... I wonder BOO!!!! what we BOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO!!!! I AM A GHOST!!!! YOU SHOULD ADD MEEEEEEE!!!!! BOOOOOOOO!!!!! Ok, ok! We'll add some ghosts! Sheesh!

  • edited June 2015

    So here are some ghosts. BOOO!!! THESE GHOSTS SUUUUCK!!!!! WEEEE WANT REEAAAAAAL GHOOOOOSTS!!!!! BOOO!!! Shut up, ghosts! This is only a first draft!

    Anyway, ghosts come in different colors, so each ghost has a type variable that corresponds to a color in the new ghost_colors array. Each ghost also has some simple logic, which includes a target position, and it moves towards that target position. It would have been a real pain to try to write these ghosts as lists of variables!

    class Player {
      float x, y;
      int d;
      float mouth_opening = 0, max_mouth_opening = .4;
      boolean is_mouth_opening = true;
      boolean am_i_super = false;
      int super_countdown = 0;
      Player() {
        x = 30;
        y = 30;
        d = 0;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        float px=x, py=y;
        if (0==d) { 
          x++;
        }
        if (1==d) { 
          y++;
        }
        if (2==d) { 
          x--;
        }
        if (3==d) { 
          y--;
        }
        if (grid.is_wall(x, y)) {
          x = px;
          y = py;
        } else {
          animate_mouth();
          grid.eat_dot_at(x, y);
        }
        if (super_countdown > 0) { 
          super_countdown--;
        }
        if (super_countdown == 0) { 
          am_i_super = false;
        }
      }
      void animate_mouth() {
        if (is_mouth_opening) {
          mouth_opening+=.01;
        } else {
          mouth_opening-=.01;
        }
        if (mouth_opening >max_mouth_opening || mouth_opening < 0) {
          is_mouth_opening = !is_mouth_opening;
        }
      }
      void be_super() {
        am_i_super = true;
        super_countdown = 100;
      }
      void render() {
        pushMatrix();
        translate(x, y);
        rotate(HALF_PI*d);
        stroke(0);
        fill(255, am_i_super?0:255, 0);
        ellipse(0, 0, 22, 22);
        fill(0);
        arc(0, 0, 22, 22, -mouth_opening, mouth_opening);
        popMatrix();
      }
      void on_keyPressed() {
        if ( key == CODED ) {
          if ( keyCode == RIGHT ) { 
            d = 0;
          }
          if ( keyCode == DOWN ) { 
            d = 1;
          }
          if ( keyCode == LEFT ) { 
            d = 2;
          }
          if ( keyCode == UP ) { 
            d = 3;
          }
        }
      }
    }
    
    class Grid {
      int[][] data = new int[30][30];
      Grid() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            data[j][i] = 2;
            if (0==i || 0==j || 29==i || 29==j) { 
              data[j][i] = 1;
            }
            if (i==5 && j < 10) { // Temporary wall.
              data[j][i] = 1;
            }
          }
        }
        data[5][10] = 3;
      }
      void draw() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            noFill();      
            if (data[j][i] == 1) { 
              fill(0, 0, 255);
            }
            stroke(128, 128, 255);
            rect(20*i, 20*j, 20, 20);
            if (data[j][i] == 2) {
              fill(196);
              noStroke();
              ellipse(20*i+10, 20*j+10, 6, 6);
            }      
            if (data[j][i] == 3) {
              fill(255);
              noStroke();
              ellipse(20*i+10, 20*j+10, 12, 12);
            }
          }
        }
      }
      boolean is_wall(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        return (data[j][i] == 1);
      }
      void eat_dot_at(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        if (data[j][i] == 3) {
          player.be_super();
        }
        data[j][i] = 0;
      }
    }
    
    color[] ghost_colors = {
      color(255, 0, 0), color(255, 128, 0), color(255, 64, 196), color(0, 255, 255)
    };
    
    class Ghost {
      int type;
      float x, y, tx, ty;
      boolean scared;
      Ghost(int itype) {
        type = itype % ghost_colors.length;
        x = random(width);
        y = random(height);
        tx = player.x;
        ty = player.y;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        tx = player.x;
        ty = player.y;
        if (tx < x) {
          x--;
        }
        if (tx > x) {
          x++;
        }
        if (ty < y) {
          y--;
        }
        if (ty > y) {
          y++;
        }
      }
      void render() {
        stroke(0);
        fill(ghost_colors[type]);
        rect(x, y, 22, 22);
      }
    }
    
    Grid grid;
    Player player;
    Ghost[] ghosts;
    
    void setup() {
      size(601, 601);
      grid = new Grid();
      player = new Player();
      ghosts = new Ghost[4];
      for (int i=0; i<ghosts.length; i++) { 
        ghosts[i] = new Ghost(i);
      }
    }
    
    void draw() {
      background(0);
      grid.draw();
      for (int i=0; i<ghosts.length; i++) { 
        ghosts[i].draw();
      }
      player.draw();
    }
    
    void keyPressed() {
      player.on_keyPressed();
    }
    

    Now there are several different things that need fixing at this point. For a start, the ghost's movement logic. They need to obey the walls too. Plus they really should move along the grid, and only decide which way to go when they need to change their minds. Plus different types of ghosts need different target locations. And if we're going for full pacmanness here, they need to have a chase, flee, and corner modes. Plus a ghost house. Oh, and some level design. And the fruit! We can't forget the bonus fruit, score, and lives! Plus a start screen, and a check that all the dots are eaten! BOOO!!! THAT'S A LOT OF WORK!!! BOOO!!!! WE'RE THE GHOSTS!!!! BOOOooOoOoOOOO!!!

  • And the feature I work on first is... None of those! BOO!!! YOU NEED TO IMPROVE THE GHOOOOOOOSTS! BOOOOOOOOO!!!!

    Instead I decided to make some changes to the grid. BOO!!!

    class Player {
      float x, y;
      int d;
      float mouth_opening = 0, max_mouth_opening = .4;
      boolean is_mouth_opening = true;
      boolean am_i_super = false;
      int super_countdown = 0;
      Player() {
        x = 30;
        y = 30;
        d = 0;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        float px=x, py=y;
        if (0==d) { 
          x++;
        }
        if (1==d) { 
          y++;
        }
        if (2==d) { 
          x--;
        }
        if (3==d) { 
          y--;
        }
        if (grid.is_wall(x, y)) {
          x = px;
          y = py;
        } else {
          animate_mouth();
          grid.eat_dot_at(x, y);
        }
        if (super_countdown > 0) { 
          super_countdown--;
        }
        if (super_countdown == 0) { 
          am_i_super = false;
        }
      }
      void animate_mouth() {
        if (is_mouth_opening) {
          mouth_opening+=.01;
        } else {
          mouth_opening-=.01;
        }
        if (mouth_opening >max_mouth_opening || mouth_opening < 0) {
          is_mouth_opening = !is_mouth_opening;
        }
      }
      void be_super() {
        am_i_super = true;
        super_countdown = 100;
      }
      void render() {
        pushMatrix();
        translate(x, y);
        rotate(HALF_PI*d);
        stroke(0);
        fill(255, am_i_super?0:255, 0);
        ellipse(0, 0, 22, 22);
        fill(0);
        arc(0, 0, 22, 22, -mouth_opening, mouth_opening);
        popMatrix();
      }
      void on_keyPressed() {
        if ( key == CODED ) {
          if ( keyCode == RIGHT ) { 
            d = 0;
          }
          if ( keyCode == DOWN ) { 
            d = 1;
          }
          if ( keyCode == LEFT ) { 
            d = 2;
          }
          if ( keyCode == UP ) { 
            d = 3;
          }
        }
      }
    }
    
    class Grid {
      byte[][] data = new byte[30][30];
      Grid() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            data[j][i] = 2;
            if (0==i || 0==j || 29==i || 29==j) { 
              data[j][i] = 1;
            }
            if (i==5 && j < 10) { // Temporary wall.
              data[j][i] = 1;
            }
          }
        }
        data[5][10] = 3;
      }
      void draw() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            noFill();      
            if (data[j][i] == 1) { 
              fill(0, 0, 255);
            }
            if ( data[j][i] == 1 ) {
              pushStyle(); 
              //stroke(0, 255-map(dist(player.x,player.y,20*i,20*j),0,200,0,255), 255 );
              stroke(0, 0, 255);
              strokeWeight(12);
              line(10+20*i, 10+20*j, 10+20*i, 10+20*j);
              if (i<29 && data[j][i+1] == 1) {
                line(10+20*i, 10+20*j, 10+20*i+20, 10+20*j);
              }
              if (j<29 && data[j+1][i] == 1) {
                line(10+20*i, 10+20*j, 10+20*i, 10+20*j+20);
              }
              popStyle();
            }
            //noStroke();//stroke(128, 128, 255);
            //        rect(20*i, 20*j, 20, 20);
            if (data[j][i] == 2) {
              fill(196);
              noStroke();
              ellipse(20*i+10, 20*j+10, 6, 6);
            }      
            if (data[j][i] == 3) {
              fill(255);
              noStroke();
              ellipse(20*i+10, 20*j+10, 12, 12);
            }
          }
        }
      }
      boolean is_wall(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        return (data[j][i] == 1);
      }
      void eat_dot_at(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        if (data[j][i] == 3) {
          player.be_super();
        }
        data[j][i] = 0;
      }
      void world_edit(int ix, int iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        data[j][i]++;
        data[j][i]%=4;
      }
      void on_keyPressed() {
        if (key == 's' ) { 
          grid.save_level();
        }
        if (key == 'l' ) {
          grid.load_level();
        }
      }
      void save_level() {
        byte[] temp = new byte[900];
        int t = 0;
        for (int j = 0; j < 30; j++) {
          for (int i = 0; i < 30; i++) {
            temp[t++] = grid.data[j][i];
          }
        } 
        saveBytes("world.dat", temp);
      }  
      void load_level() {
        byte[] temp = loadBytes("world.dat");
        println(temp.length);
        int t = 0;
        for (int j = 0; j < 30; j++) {
          println("");
          for (int i = 0; i < 30; i++) {
            print(temp[t]);
            grid.data[j][i] = temp[t++];
          }
        }
      }
    }
    
    color[] ghost_colors = {
      color(255, 0, 0), color(255, 128, 0), color(255, 64, 196), color(0, 255, 255)
    };
    
    class Ghost {
      int type;
      float x, y, tx, ty;
      boolean scared;
      Ghost(int itype) {
        type = itype % ghost_colors.length;
        x = random(width);
        y = random(height);
        tx = player.x;
        ty = player.y;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        tx = player.x;
        ty = player.y;
        if (tx < x) {
          x--;
        }
        if (tx > x) {
          x++;
        }
        if (ty < y) {
          y--;
        }
        if (ty > y) {
          y++;
        }
      }
      void render() {
        stroke(0);
        fill(ghost_colors[type]);
        rect(x-11, y-11, 22, 22);
      }
    }
    
    Grid grid;
    Player player;
    Ghost[] ghosts;
    
    void setup() {
      size(601, 601);
      grid = new Grid();
      player = new Player();
      ghosts = new Ghost[4];
      for (int i=0; i<ghosts.length; i++) { 
        ghosts[i] = new Ghost(i);
      }
    }
    
    void draw() {
      background(0);
      grid.draw();
      for (int i=0; i<ghosts.length; i++) { 
        ghosts[i].draw();
      }
      player.draw();
    }
    
    void keyPressed() {
      grid.on_keyPressed();
      player.on_keyPressed();
    }
    
    void mousePressed() {
      grid.world_edit(mouseX, mouseY);
    }
    

    We'll need walls for the ghosts to not go through, right? BOO! OK! FINE! BUT BOOOOOO!!!!

  • Answer ✓

    Trapping the player in a wall is a good way to get him to stop moving so you can fill the world with dots as you like. I'm going to assume that anyone following along at home has drawn their own level and moved it into the data folder, so that this level is loaded when the sketch starts from now on.

    BOO!! THIS IN'T HELPING US KILL THE PLAYER ANY BETTER! YOU NEED TO IMPROVE OUR MOVEMENT LOGIC! AND MAKE OUR TOUCH DEADLY! BOOO!!!

    Good point, ghosts. Let's add that now.

    class Player {
      float x, y;
      int d;
      float mouth_opening = 0, max_mouth_opening = .4;
      boolean is_mouth_opening = true;
      boolean am_i_super = false;
      int super_countdown = 0;
      Player() {
        x = 30;
        y = 30;
        d = 0;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        float px=x, py=y;
        if (0==d) { 
          x++;
        }
        if (1==d) { 
          y++;
        }
        if (2==d) { 
          x--;
        }
        if (3==d) { 
          y--;
        }
        if (grid.is_wall(x, y)) {
          x = px;
          y = py;
        } else {
          animate_mouth();
          grid.eat_dot_at(x, y);
        }
        if (super_countdown > 0) { 
          super_countdown--;
        }
        if (super_countdown == 0) { 
          am_i_super = false;
        }
      }
      void animate_mouth() {
        if (is_mouth_opening) {
          mouth_opening+=.01;
        } else {
          mouth_opening-=.01;
        }
        if (mouth_opening >max_mouth_opening || mouth_opening < 0) {
          is_mouth_opening = !is_mouth_opening;
        }
      }
      void be_super() {
        am_i_super = true;
        super_countdown = 100;
      }
      void render() {
        pushMatrix();
        translate(x, y);
        rotate(HALF_PI*d);
        stroke(0);
        fill(255, am_i_super?0:255, 0);
        ellipse(0, 0, 22, 22);
        fill(0);
        arc(0, 0, 22, 22, -mouth_opening, mouth_opening);
        popMatrix();
      }
      void on_keyPressed() {
        if ( key == CODED ) {
          if ( keyCode == RIGHT ) { 
            d = 0;
          }
          if ( keyCode == DOWN ) { 
            d = 1;
          }
          if ( keyCode == LEFT ) { 
            d = 2;
          }
          if ( keyCode == UP ) { 
            d = 3;
          }
        }
      }
    }
    
    class Grid {
      byte[][] data = new byte[30][30];
      Grid() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            data[j][i] = 2;
            if (0==i || 0==j || 29==i || 29==j) { 
              data[j][i] = 1;
            }
            if (i==5 && j < 10) { // Temporary wall.
              data[j][i] = 1;
            }
          }
        }
        data[5][10] = 3;
      }
      void draw() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            noFill();      
            if (data[j][i] == 1) { 
              fill(0, 0, 255);
            }
            if ( data[j][i] == 1 ) {
              pushStyle(); 
              //stroke(0, 255-map(dist(player.x,player.y,20*i,20*j),0,200,0,255), 255 );
              stroke(0, 0, 255);
              strokeWeight(12);
              line(10+20*i, 10+20*j, 10+20*i, 10+20*j);
              if (i<29 && data[j][i+1] == 1) {
                line(10+20*i, 10+20*j, 10+20*i+20, 10+20*j);
              }
              if (j<29 && data[j+1][i] == 1) {
                line(10+20*i, 10+20*j, 10+20*i, 10+20*j+20);
              }
              popStyle();
            }
            //noStroke();//stroke(128, 128, 255);
            //        rect(20*i, 20*j, 20, 20);
            if (data[j][i] == 2) {
              fill(196);
              noStroke();
              ellipse(20*i+10, 20*j+10, 6, 6);
            }      
            if (data[j][i] == 3) {
              fill(255);
              noStroke();
              ellipse(20*i+10, 20*j+10, 12, 12);
            }
          }
        }
      }
      boolean is_wall(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        return (data[j][i] == 1);
      }
      void eat_dot_at(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        if (data[j][i] == 3) {
          player.be_super();
        }
        data[j][i] = 0;
      }
      void world_edit(int ix, int iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        data[j][i]++;
        data[j][i]%=4;
      }
      void on_keyPressed() {
        if (key == 's' ) { 
          grid.save_level();
        }
        if (key == 'l' ) {
          grid.load_level();
        }
      }
      void save_level() {
        byte[] temp = new byte[900];
        int t = 0;
        for (int j = 0; j < 30; j++) {
          for (int i = 0; i < 30; i++) {
            temp[t++] = grid.data[j][i];
          }
        } 
        saveBytes("world.dat", temp);
        println("Level saved.");
      }  
      void load_level() {
        byte[] temp = loadBytes("world.dat");
        //println(temp.length);
        int t = 0;
        for (int j = 0; j < 30; j++) {
          //println("");
          for (int i = 0; i < 30; i++) {
            //print(temp[t]);
            grid.data[j][i] = temp[t++];
          }
        }
        println("Level loaded.");
      }
    }
    
    color[] ghost_colors = {
      color(255, 0, 0), color(255, 128, 0), color(255, 64, 196), color(0, 255, 255)
    };
    
    class Ghost {
      int type;
      int x, y, tx, ty;
      int d; // Ghost direction.
      boolean scared;
      int trapped_timer;
      Ghost(int itype) {
        type = itype % ghost_colors.length;
        // Assume ghosts start nearish to the center.
        x = 10 + 20 * 15; // random(width);
        y = 10 + 20 * 14; // random(height); // Works for my level.
        tx = x; //player.x;
        ty = y; //player.y;
        trapped_timer = 200 * type; // Initial delay is based on ghost type. That's good.
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        trapped_timer--;
        if (trapped_timer > 0) { 
          return;
        }
        int px = x;
        int py = y;
        if (tx < x) {
          x--;
        }
        if (tx > x) {
          x++;
        }
        if (ty < y) {
          y--;
        }
        if (ty > y) {
          y++;
        }
        // Ghost hasn't moved? Need a new target!
        // Each target will be one of the squares next to the square currently in.
        // Each ghost will need a grand target to move towards as well.
        // Thus, it will check which direction it should move to get closer to the grand target.
        if (px==x&&py==y) {
          tx = x; // Default to no movement.
          ty = y;
          //d = 5;
          //get grand target
          int gx = int(player.x);
          int gy = int(player.y);
          float best = 1000000;
          for ( int w = 0; w < 4; w++) {
            if ( w!=(d+2)%4 && !grid.is_wall(x+decodeX[w], y+decodeY[w])) {
              float new_dist = dist(x+decodeX[w], y+decodeY[w], gx, gy);
              if( new_dist < best) {
                best = new_dist;
                d = w;
                tx = x+decodeX[w];
                ty = y+decodeY[w];
              }
            }
          }
        }
      }
      void render() {
        stroke(0);
        fill(ghost_colors[type]);
        rect(x-11, y-11, 22, 22);
        rect(tx-5.5,ty-5.5, 11, 11); // Target.    
      }
    }
    
    int[] decodeX = { 
      20, 0, -20, 0, 0
    };
    int[] decodeY = { 
      0, -20, 0, 20, 0
    };
    
    
    Grid grid;
    Player player;
    Ghost[] ghosts;
    
    void setup() {
      size(601, 601);
      grid = new Grid();
      grid.load_level();
      player = new Player();
      ghosts = new Ghost[4];
      for (int i=0; i<ghosts.length; i++) { 
        ghosts[i] = new Ghost(i);
      }
    }
    
    void draw() {
      background(0);
      grid.draw();
      for (int i=0; i<ghosts.length; i++) { 
        ghosts[i].draw();
      }
      player.draw();
    }
    
    void keyPressed() {
      grid.on_keyPressed();
      player.on_keyPressed();
    }
    
    void mousePressed() {
      grid.world_edit(mouseX, mouseY);
    }
    

    Well, that's a step in the right direction. And at this point I've run out of steam. Maybe I'll pick this up later. BOOO! Quiet! OK!

  • Answer ✓

    BOOO! WE'RE ACTUALLY GHOSTS!! AND WE MOVE LIKE REAL GHOSTS!!!

    class Player {
      float x, y;
      int d;
      float mouth_opening = 0, max_mouth_opening = .4;
      boolean is_mouth_opening = true;
      boolean am_i_super = false;
      int super_countdown = 0;
      Player() {
        x = 30;
        y = 30;
        d = 0;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        float px=x, py=y;
        if (0==d) { 
          x++;
        }
        if (1==d) { 
          y++;
        }
        if (2==d) { 
          x--;
        }
        if (3==d) { 
          y--;
        }
        if (grid.is_wall(x, y)) {
          x = px;
          y = py;
        } else {
          animate_mouth();
          grid.eat_dot_at(x, y);
        }
        if (super_countdown > 0) { 
          super_countdown--;
        }
        if (super_countdown == 0) { 
          am_i_super = false;
        }
      }
      void animate_mouth() {
        if (is_mouth_opening) {
          mouth_opening+=.01;
        } else {
          mouth_opening-=.01;
        }
        if (mouth_opening >max_mouth_opening || mouth_opening < 0) {
          is_mouth_opening = !is_mouth_opening;
        }
      }
      void be_super() {
        am_i_super = true;
        super_countdown = 100;
      }
      void render() {
        pushMatrix();
        translate(x, y);
        rotate(HALF_PI*d);
        stroke(0);
        fill(255, am_i_super?0:255, 0);
        ellipse(0, 0, 22, 22);
        fill(0);
        arc(0, 0, 22, 22, -mouth_opening, mouth_opening);
        popMatrix();
      }
      void on_keyPressed() {
        if ( key == CODED ) {
          if ( keyCode == RIGHT ) { 
            d = 0;
          }
          if ( keyCode == DOWN ) { 
            d = 1;
          }
          if ( keyCode == LEFT ) { 
            d = 2;
          }
          if ( keyCode == UP ) { 
            d = 3;
          }
        }
      }
    }
    
    class Grid {
      byte[][] data = new byte[30][30];
      Grid() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            data[j][i] = 2;
            if (0==i || 0==j || 29==i || 29==j) { 
              data[j][i] = 1;
            }
            if (i==5 && j < 10) { // Temporary wall.
              data[j][i] = 1;
            }
          }
        }
        data[5][10] = 3;
      }
      void draw() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            noFill();      
            if (data[j][i] == 1) { 
              fill(0, 0, 255);
            }
            if ( data[j][i] == 1 ) {
              pushStyle(); 
              //stroke(0, 255-map(dist(player.x,player.y,20*i,20*j),0,200,0,255), 255 );
              stroke(0, 0, 255);
              strokeWeight(12);
              line(10+20*i, 10+20*j, 10+20*i, 10+20*j);
              if (i<29 && data[j][i+1] == 1) {
                line(10+20*i, 10+20*j, 10+20*i+20, 10+20*j);
              }
              if (j<29 && data[j+1][i] == 1) {
                line(10+20*i, 10+20*j, 10+20*i, 10+20*j+20);
              }
              popStyle();
            }
            //noStroke();//stroke(128, 128, 255);
            //        rect(20*i, 20*j, 20, 20);
            if (data[j][i] == 2) {
              fill(196);
              noStroke();
              ellipse(20*i+10, 20*j+10, 6, 6);
            }      
            if (data[j][i] == 3) {
              fill(255);
              noStroke();
              ellipse(20*i+10, 20*j+10, 12, 12);
            }
          }
        }
      }
      boolean is_wall(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        return (data[j][i] == 1);
      }
      void eat_dot_at(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        if (data[j][i] == 3) {
          player.be_super();
        }
        data[j][i] = 0;
      }
      void world_edit(int ix, int iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        data[j][i]++;
        data[j][i]%=4;
      }
      void on_keyPressed() {
        if (key == 's' ) { 
          grid.save_level();
        }
        if (key == 'l' ) {
          grid.load_level();
        }
      }
      void save_level() {
        byte[] temp = new byte[900];
        int t = 0;
        for (int j = 0; j < 30; j++) {
          for (int i = 0; i < 30; i++) {
            temp[t++] = grid.data[j][i];
          }
        } 
        saveBytes("world.dat", temp);
        println("Level saved.");
      }  
      void load_level() {
        byte[] temp = loadBytes("world.dat");
        //println(temp.length);
        int t = 0;
        for (int j = 0; j < 30; j++) {
          //println("");
          for (int i = 0; i < 30; i++) {
            //print(temp[t]);
            grid.data[j][i] = temp[t++];
          }
        }
        println("Level loaded.");
      }
    }
    
    color[] ghost_colors = { // RED, PINK, CYAN, ORANGE
      color(255, 0, 0), color(255, 64, 196), color(0, 255, 255), color(255, 128, 0)
    };
    
    class Ghost {
      int type;
      int x, y, tx, ty;
      int pgx, pgy;
      int d; // Ghost direction.
      boolean scared;
      int trapped_timer;
      Ghost(int itype) {
        type = itype % ghost_colors.length;
        // Assume ghosts start nearish to the center.
        x = 10 + 20 * 15; // random(width);
        y = 10 + 20 * 14; // random(height); // Works for my level.
        tx = x; //player.x;
        ty = y; //player.y;
        trapped_timer = 200 * type; // Initial delay is based on ghost type. That's good.
        // Better would be the real release conditions, of course. :D
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        trapped_timer--;
        if (trapped_timer > 0) { 
          return;
        }
        int px = x;
        int py = y;
        if (tx < x) {
          x--;
        }
        if (tx > x) {
          x++;
        }
        if (ty < y) {
          y--;
        }
        if (ty > y) {
          y++;
        }
        if (px==x&&py==y) {
          int wall_count = 0;
          for (int w = 0; w < 4; w++) {
            if ( grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
              wall_count++;
            }
          }
          //println("");
          //print(wall_count + " ");
          if (wall_count == 4) { // >:(
            //print(d + " -> 5");
            d = 5;
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          if (wall_count == 3) {
            for (int w = 0; w < 4; w++) {
              if ( !grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
                //print(d + " -> " + w);
                d = w;
              }
            }
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          if (wall_count == 2) {
            int result = 5;
            for (int w = 0; w < 4; w++) {
              if ( !grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
                if ( w != (d+2)%4 ) {
                  result = w;
                }
              }
            }
            d = result;
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          int gx = int(player.x); // RED - Go for pacman.
          int gy = int(player.y);
          if (!to_corners) {
            if (type == 1 ) { // PINK = Get in front of pacman.
              gx = int(player.x)+4*decodeX[player.d];
              gy = int(player.y)+4*decodeY[player.d];
              if ( player.d == 3 ) { // Classic pink ghost behaviour.
                gx = int(player.x-80);
              }
            }
            if ( type == 2 ) { // CYAN - Negative RED's positions, offset a couple of squares.
              float mpx = player.x+2*decodeX[player.d];
              float mpy = player.y+2*decodeY[player.d];
              float ddx = mpx - ghosts[0].x;
              float ddy = mpy - ghosts[0].y;
              gx = int(ddx + mpx);
              gy = int(ddx + mpy);
            }
            if ( type == 3 ) { // ORANGE - Get close, then back off.
              if(dist(player.x,player.y,x,y) < 160){
                gx = 0;
                gy = height;
              }
            }
          } else {
            if ( type == 1 || type == 3 ) { 
              gx = 0;
            } else { 
              gx = width;
            }
            if ( type == 1 || type == 0 ) { 
              gy = 0;
            } else { 
              gy = height;
            }
          }
          pgx = gx;
          pgy = gy;
          float best = -1 ;
          int result = 5;
          for ( int w = 0; w < 4; w++) {
            if ( w!=(d+2)%4 && !grid.is_wall(x+decodeX[w], y+decodeY[w])) {
              float new_dist = dist(x+decodeX[w], y+decodeY[w], gx, gy);
              if ( best == -1 || new_dist < best) {
                best = new_dist;
                result = w;
              }
            }
          }
          //print(d + " -> " + result);
          d = result;
          tx = x+decodeX[d];
          ty = y+decodeY[d];
          return;
        }
      }
      void render() {
        stroke(0);
        fill(ghost_colors[type]);
        rect(x-11, y-11, 22, 22);
        rect(tx-5.5, ty-5.5, 11, 11); // Target.
        ellipse(pgx, pgy, 22, 22); // Last Grand Target.
      }
    }
    
    int[] decodeX = { 
      20, 0, -20, 0, 0
    };
    int[] decodeY = { 
      0, 20, 0, -20, 0
    };
    
    
    Grid grid;
    Player player;
    Ghost[] ghosts;
    boolean to_corners = false;
    
    void setup() {
      size(601, 601);
      grid = new Grid();
      grid.load_level();
      player = new Player();
      ghosts = new Ghost[4];
      for (int i=0; i<ghosts.length; i++) { 
        ghosts[i] = new Ghost(i);
      }
    }
    
    void draw() {
      background(0);
      grid.draw();
      player.draw();
      for (int i=0; i<ghosts.length; i++) { 
        ghosts[i].draw();
      }
    }
    
    void keyPressed() {
      grid.on_keyPressed();
      player.on_keyPressed();
      if ( key == ' ') { 
        to_corners = !to_corners;
      }
    }
    
    void mousePressed() {
      grid.world_edit(mouseX, mouseY);
    }
    

    WHY AREN'T WE DEADLY TO THE PLAYER YET!?!?!? BOOOOOOOOOOOO!!!!

  • Answer ✓

    BOOOO!!! OH MY GOSH WE'RE FREAKING PRETTY!!! WOOO HOOO!!!

    class Player {
      float start_x = 30;
      float start_y = 30;
      float x, y;
      int d;
      float mouth_opening, max_mouth_opening, mouth_step;
      boolean is_mouth_opening = true;
      boolean am_i_super = false;
      boolean is_dead = false;
      int super_countdown;
      Player() {
        reset();
      }
      void reset() {
        x = start_x;
        y = start_y;
        d = 0;
        mouth_opening = 0; 
        max_mouth_opening = .4; 
        mouth_step = .01;
        am_i_super = false;
        super_countdown = 0;
        is_dead = false;
      }
      void die() {
        is_dead = true;
        max_mouth_opening = TWO_PI;
        mouth_step = .1;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        if (mouth_opening > PI ) reset();
        if (is_dead) { 
          animate_mouth(); 
          return;
        }
        float px=x, py=y;
        if (0==d) x++;
        if (1==d) y++;
        if (2==d) x--;
        if (3==d) y--;
        if (grid.is_wall(x, y)) {
          x = px;
          y = py;
        } else {
          animate_mouth();
          grid.eat_dot_at(x, y);
        }
        if (super_countdown > 0) { 
          super_countdown--;
        }
        if (super_countdown == 0) { 
          am_i_super = false;
          for (int i=0; i<ghosts.length; ghosts[i++].dont_be_afraid ());
        }
      }
      void animate_mouth() {
        if (is_mouth_opening) {
          mouth_opening+=mouth_step;
        } else {
          mouth_opening-=mouth_step;
        }
        if (mouth_opening > max_mouth_opening || mouth_opening < 0) {
          is_mouth_opening = !is_mouth_opening;
        }
      }
      void be_super() {
        am_i_super = true;
        super_countdown = 500;
        for (int i=0; i<ghosts.length; ghosts[i++].be_afraid ());
      }
      void render() {
        pushMatrix();
        translate(x, y);
        rotate(HALF_PI*d);
        stroke(0);
        fill(am_i_super?color(random(255), random(255), random(255)):color(255, 255, 0));
        ellipse(0, 0, 22, 22);
        fill(0);
        arc(0, 0, 22, 22, -mouth_opening, mouth_opening);
        popMatrix();
      }
      void on_keyPressed() {
        if ( key == CODED ) {
          if ( keyCode == RIGHT ) { 
            d = 0;
          }
          if ( keyCode == DOWN ) { 
            d = 1;
          }
          if ( keyCode == LEFT ) { 
            d = 2;
          }
          if ( keyCode == UP ) { 
            d = 3;
          }
        }
      }
    }
    
    class Grid {
      byte[][] data = new byte[30][30];
      Grid() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            data[j][i] = 2;
            if (0==i || 0==j || 29==i || 29==j) { 
              data[j][i] = 1;
            }
          }
        }
        data[5][10] = 3;
      }
      void draw() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            noFill();      
            if (data[j][i] == 1) { 
              fill(0, 0, 255);
            }
            if ( data[j][i] == 1 ) {
              pushStyle();
              stroke(0, 0, 255);
              //stroke(0, 255-map(dist(player.x,player.y,20*i,20*j),0,200,0,255), 255 );
              strokeWeight(12);
              pushMatrix();
              translate(20*i, 20*j);
              line(10, 10, 10, 10);
              if (i<29 && data[j][i+1] == 1) {
                line(10, 10, 30, 10);
              }
              if (j<29 && data[j+1][i] == 1) {
                line(10, 10, 10, 30);
              }
              popMatrix();
              popStyle();
            }
            if (data[j][i] == 2) {
              fill(196);
              noStroke();
              ellipse(20*i+10, 20*j+10, 6, 6);
            }      
            if (data[j][i] == 3) {
              fill(255);
              noStroke();
              ellipse(20*i+10, 20*j+10, 12, 12);
            }
          }
        }
      }
      boolean is_wall(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        return (data[j][i] == 1);
      }
      void eat_dot_at(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        if (data[j][i] == 3) {
          player.be_super();
        }
        data[j][i] = 0;
      }
      void world_edit(int ix, int iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        data[j][i]++;
        data[j][i]%=4;
      }
      void on_keyPressed() {
        if (key == 's' ) { 
          grid.save_level();
        }
        if (key == 'l' ) {
          grid.load_level();
        }
      }
      void save_level() {
        byte[] temp = new byte[900];
        int t = 0;
        for (int j = 0; j < 30; j++) {
          for (int i = 0; i < 30; i++) {
            temp[t++] = grid.data[j][i];
          }
        } 
        saveBytes("world.dat", temp);
        println("Level saved.");
      }  
      void load_level() {
        byte[] temp = loadBytes("world.dat");
        int t = 0;
        for (int j = 0; j < 30; j++) {
          for (int i = 0; i < 30; i++) {
            grid.data[j][i] = temp[t++];
          }
        }
        println("Level loaded.");
      }
    }
    
    class Ghost {
      int type;
      int x, y, tx, ty, ptx, pty;
      int pgx, pgy;
      int d;
      boolean is_scared;
      boolean is_dead;
      int trapped_timer;
      Ghost(int itype) {
        type = itype % ghost_colors.length;
        x = 10 + 20 * 15;
        y = 10 + 20 * 14;
        tx = x;
        ty = y;
        ptx=tx;
        pty=ty;
        trapped_timer = 200 * type;
      }
      void dont_be_afraid() {
        if (is_scared) {
          is_scared = false;
          d=(d+2)%4;
          tx = ptx;
          ty = pty;
        }
      }
      void be_afraid() {
        is_scared = true;
        d=(d+2)%4;
        tx = ptx;
        ty = pty;
      }  
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        trapped_timer--;
        if (trapped_timer > 0) { 
          return;
        }
        int px = x;
        int py = y;
        if (tx < x) {
          x--;
        }
        if (tx > x) {
          x++;
        }
        if (ty < y) {
          y--;
        }
        if (ty > y) {
          y++;
        }
        if (px==x&&py==y) {
          ptx = tx;
          pty = ty;
          int wall_count = 0;
          for (int w = 0; w < 4; w++) {
            if ( grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
              wall_count++;
            }
          }
          if (wall_count == 4) { // >:(
            d = 5;
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          if (wall_count == 3) {
            for (int w = 0; w < 4; w++) {
              if ( !grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
                d = w;
              }
            }
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          if (wall_count == 2) {
            int result = 5;
            for (int w = 0; w < 4; w++) {
              if ( !grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
                if ( w != (d+2)%4 ) {
                  result = w;
                }
              }
            }
            d = result;
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          int gx = int(player.x); // RED - Go for pacman.
          int gy = int(player.y);
          if (!to_corners) {
            if (type == 1 ) { // PINK = Get in front of pacman.
              gx = int(player.x)+4*decodeX[player.d];
              gy = int(player.y)+4*decodeY[player.d];
              if ( player.d == 3 ) { // Classic pink ghost behaviour.
                gx = int(player.x-80);
              }
            }
            if ( type == 2 ) { // CYAN - Negative RED's positions, offset a couple of squares.
              float mpx = player.x+2*decodeX[player.d];
              float mpy = player.y+2*decodeY[player.d];
              if (player.d == 3) { // Classic cyan ghost behaviour.
                mpx = player.x - 40;
              }
              gx = int(2*mpx - ghosts[0].x);
              gy = int(2*mpy - ghosts[0].y);
            }
            if ( type == 3 ) { // ORANGE - Get close, then back off.
              if (dist(player.x, player.y, x, y) < 160) {
                gx = 0;
                gy = height;
              }
            }
          } else {
            if ( type == 1 || type == 3 ) { 
              gx = 0;
            } else { 
              gx = width;
            }
            if ( type == 1 || type == 0 ) { 
              gy = 0;
            } else { 
              gy = height;
            }
          }
          if (is_dead||is_scared) {
            gx = 10 + 20 * 15;
            gy = 10 + 20 * 14;
            if (is_dead && x==gx &&y==gy) {
              is_dead = false;
            }
          }    
          pgx = gx;
          pgy = gy;
          float best = -1 ;
          int result = 5;
          for ( int w = 0; w < 4; w++) {
            if ( w!=(d+2)%4 && !grid.is_wall(x+decodeX[w], y+decodeY[w])) {
              float new_dist = dist(x+decodeX[w], y+decodeY[w], gx, gy);
              if ( best == -1 || new_dist < best) {
                best = new_dist;
                result = w;
              }
            }
          }
          d = result;
          tx = x+decodeX[d];
          ty = y+decodeY[d];
          return;
        }
      }
      void render() {
        stroke(0);
        fill(is_scared?color(0, 0, 255):ghost_colors[type]);
        pushMatrix();
        translate(x, y);
        if (!is_dead) {
          rect(-11, -1, 22, 11);
          arc(0, 0, 22, 22, PI, TWO_PI);
          for (int i=0; i<4; i++) {
            arc(-7+5*i, 10, 5, 5, 0, PI);
          }
        }
        fill(255);
        noStroke();
        ellipse(-4, 0, 4, 8);
        ellipse(4, 0, 4, 8);
        if (!is_scared) {
          fill(0, 0, 255);
          int eyex = (d==2?-1:0)+(d==0?1:0);
          int eyey = (d==3?-3:0)+(d==1?3:0);
          ellipse(-4+eyex, eyey, 3, 3);
          ellipse(4+eyex, eyey, 3, 3);
        }
        popMatrix();
      }
    }
    
    int[] decodeX = { 
      20, 0, -20, 0, 0
    };
    int[] decodeY = { 
      0, 20, 0, -20, 0
    };
    
    
    Grid grid;
    Player player;
    Ghost[] ghosts;
    
    boolean to_corners = false;
    
    color[] ghost_colors = {
      color(255, 0, 0), 
      color(255, 64, 196), 
      color(0, 255, 255), 
      color(255, 128, 0), 
      color(0, 255, 0), 
      //  color(196),
      //  color(128),
      //  color(64),
    };
    
    void setup() {
      size(601, 601);
      grid = new Grid();
      grid.load_level();
      player = new Player();
      ghosts = new Ghost[ghost_colors.length];
      for (int i=0; i<ghosts.length; ghosts[i] = new Ghost (i++));
    }
    
    void game_reset() {
      player.die();
      ghosts_reset();
    }
    
    void ghosts_reset(){
      // Could write a proper reset for the ghosts.
      for (int i=0; i<ghosts.length; ghosts[i] = new Ghost (i++));
    }
    
    void draw() {
      background(0);
      grid.draw();
      player.draw();
      for (int i=0; i<ghosts.length; ghosts[i++].draw ());
    }
    
    void keyPressed() {
      grid.on_keyPressed();
      player.on_keyPressed();
      if ( key == ' ') { 
        to_corners = !to_corners;
      }
      if ( key == 'd' ) player.die();
      if ( key == 'r' ) game_reset();
    }
    
    void mousePressed() {
      grid.world_edit(mouseX, mouseY);
    }
    

    WHAT!? WE'RE STILL NOT DEADLY!? BOO! BOOOO!!! BOOOOOOOOO!!!!

  • I love all the help your giving me but its quiet confusing.... @ u @"

  • DEADLY GHOSTS! BOO!!!

    class Player {
      float start_x = 30;
      float start_y = 30;
      float x, y;
      int d;
      float mouth_opening, max_mouth_opening, mouth_step;
      boolean is_mouth_opening = true;
      boolean am_i_super = false;
      boolean is_dead = false;
      int super_countdown;
      Player() {
        reset();
      }
      void reset() {
        x = start_x;
        y = start_y;
        d = 0;
        mouth_opening = 0; 
        max_mouth_opening = .4; 
        mouth_step = .01;
        am_i_super = false;
        super_countdown = 0;
        is_dead = false;
      }
      void die() {
        is_dead = true;
        max_mouth_opening = TWO_PI;
        mouth_step = .1;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        if (mouth_opening > PI ) reset();
        if (is_dead) { 
          animate_mouth(); 
          return;
        }
        float px=x, py=y;
        if (0==d) x++;
        if (1==d) y++;
        if (2==d) x--;
        if (3==d) y--;
        if (grid.is_wall(x, y)) {
          x = px;
          y = py;
        } else {
          animate_mouth();
          grid.eat_dot_at(x, y);
        }
        if (super_countdown > 0) { 
          super_countdown--;
        }
        if (super_countdown == 0) { 
          am_i_super = false;
          for (int i=0; i<ghosts.length; ghosts[i++].dont_be_afraid ());
        }
      }
      void animate_mouth() {
        if (is_mouth_opening) {
          mouth_opening+=mouth_step;
        } else {
          mouth_opening-=mouth_step;
        }
        if (mouth_opening > max_mouth_opening || mouth_opening < 0) {
          is_mouth_opening = !is_mouth_opening;
        }
      }
      void be_super() {
        am_i_super = true;
        super_countdown = 500;
        for (int i=0; i<ghosts.length; ghosts[i++].be_afraid ());
      }
      void render() {
        pushMatrix();
        translate(x, y);
        rotate(HALF_PI*d);
        stroke(0);
        fill(am_i_super?color(random(255), random(255), random(255)):color(255, 255, 0));
        ellipse(0, 0, 22, 22);
        fill(0);
        arc(0, 0, 22, 22, -mouth_opening, mouth_opening);
        popMatrix();
      }
      void on_keyPressed() {
        if ( key == CODED ) {
          if ( keyCode == RIGHT ) d=0;
          if ( keyCode == DOWN )  d=1;
          if ( keyCode == LEFT )  d=2;
          if ( keyCode == UP )    d=3;
        }
      }
    }
    
    class Grid {
      byte[][] data = new byte[30][30];
      Grid() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            data[j][i] = 2;
            if (0==i || 0==j || 29==i || 29==j) { 
              data[j][i] = 1;
            }
          }
        }
        data[5][10] = 3;
      }
      void draw() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            noFill();      
            if (data[j][i] == 1) { 
              fill(0, 0, 255);
            }
            if ( data[j][i] == 1 ) {
              pushStyle();
              stroke(0, 0, 255);
              //stroke(0, 255-map(dist(player.x,player.y,20*i,20*j),0,200,0,255), 255 );
              strokeWeight(12);
              pushMatrix();
              translate(20*i, 20*j);
              line(10, 10, 10, 10);
              if (i<29 && data[j][i+1] == 1) {
                line(10, 10, 30, 10);
              }
              if (j<29 && data[j+1][i] == 1) {
                line(10, 10, 10, 30);
              }
              popMatrix();
              popStyle();
            }
            if (data[j][i] == 2) {
              fill(196);
              noStroke();
              ellipse(20*i+10, 20*j+10, 6, 6);
            }      
            if (data[j][i] == 3) {
              fill(255);
              noStroke();
              ellipse(20*i+10, 20*j+10, 12, 12);
            }
          }
        }
      }
      boolean is_wall(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        return (data[j][i] == 1);
      }
      void eat_dot_at(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        if (data[j][i] == 3) {
          player.be_super();
        }
        data[j][i] = 0;
      }
      void world_edit(int ix, int iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        data[j][i]++;
        data[j][i]%=4;
      }
      void on_keyPressed() {
        if (key == 's' ) { 
          grid.save_level();
        }
        if (key == 'l' ) {
          grid.load_level();
        }
      }
      void save_level() {
        byte[] temp = new byte[900];
        int t = 0;
        for (int j = 0; j < 30; j++) {
          for (int i = 0; i < 30; i++) {
            temp[t++] = grid.data[j][i];
          }
        } 
        saveBytes("world.dat", temp);
        println("Level saved.");
      }  
      void load_level() {
        byte[] temp = loadBytes("world.dat");
        int t = 0;
        for (int j = 0; j < 30; j++) {
          for (int i = 0; i < 30; i++) {
            grid.data[j][i] = temp[t++];
          }
        }
        println("Level loaded.");
      }
      boolean kill_at(int ix, int iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        int pmi = int(player.x/20); 
        int pmj = int(player.y/20);
        if (i==pmi&&j==pmj) {
          if (player.am_i_super) {
            return true;
          } else {
            player.die();
          }
        }
        return false;
      }
    }
    
    class Ghost {
      int type;
      int x, y, tx, ty, ptx, pty;
      int pgx, pgy;
      int d;
      boolean is_scared;
      boolean is_dead;
      int trapped_timer;
      Ghost(int itype) {
        type = itype % ghost_colors.length;
        x = 10 + 20 * 15;
        y = 10 + 20 * 14;
        tx = x;
        ty = y;
        ptx=tx;
        pty=ty;
        trapped_timer = 200 * type;
      }
      void dont_be_afraid() {
        if (is_scared) {
          is_scared = false;
          d=(d+2)%4;
          tx = ptx;
          ty = pty;
        }
      }
      void be_afraid() {
        if (!is_dead) {
          is_scared = true;
          d=(d+2)%4;
          tx = ptx;
          ty = pty;
        }
      }  
      void draw() {
        simulate();
        render();
        if (!is_dead) kill_check();
      }
      void simulate() {
        trapped_timer--;
        if (trapped_timer > 0) return;
        int px = x;
        int py = y;
        if (tx < x) x--;
        if (tx > x) x++;
        if (ty < y) y--;
        if (ty > y) y++;
        if (px==x&&py==y) {
          ptx = tx;
          pty = ty;
          int wall_count = 0;
          for (int w = 0; w < 4; w++) {
            if ( grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
              wall_count++;
            }
          }
          if (wall_count == 4) { // >:(
            d = 4;
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          if (wall_count == 3) {
            for (int w = 0; w < 4; w++) {
              if ( !grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
                d = w;
              }
            }
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          if (wall_count == 2) {
            int result = 5;
            for (int w = 0; w < 4; w++) {
              if ( !grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
                if ( w != (d+2)%4 ) {
                  result = w;
                }
              }
            }
            d = result;
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          int gx = int(player.x); // RED - Go for pacman.
          int gy = int(player.y);
          if (!to_corners) {
            if (type == 1 ) { // PINK = Get in front of pacman.
              gx = int(player.x)+4*decodeX[player.d];
              gy = int(player.y)+4*decodeY[player.d];
              if ( player.d == 3 ) { // Classic pink ghost behaviour.
                gx = int(player.x-80);
              }
            }
            if ( type == 2 ) { // CYAN - Negative RED's positions, offset a couple of squares.
              float mpx = player.x+2*decodeX[player.d];
              float mpy = player.y+2*decodeY[player.d];
              if (player.d == 3) { // Classic cyan ghost behaviour.
                mpx = player.x - 40;
              }
              gx = int(2*mpx - ghosts[0].x);
              gy = int(2*mpy - ghosts[0].y);
            }
            if ( type == 3 ) { // ORANGE - Get close, then back off.
              if (dist(player.x, player.y, x, y) < 160) {
                gx = 0;
                gy = height;
              }
            }
          } else {
            gx = width;
            gy = height;
            if ( type == 1 || type == 3 ) gx = 0; 
            if ( type == 1 || type == 0 ) gy = 0;
          }
          if (is_dead||is_scared) {
            gx = 10 + 20 * 15;
            gy = 10 + 20 * 14;
            if (is_dead && x==gx &&y==gy) is_dead = false;
          }    
          pgx = gx;
          pgy = gy;
          float best = -1 ;
          int result = 5;
          for ( int w = 0; w < 4; w++) {
            if ( w!=(d+2)%4 && !grid.is_wall(x+decodeX[w], y+decodeY[w])) {
              float new_dist = dist(x+decodeX[w], y+decodeY[w], gx, gy);
              if ( best == -1 || new_dist < best) {
                best = new_dist;
                result = w;
              }
            }
          }
          d = result;
          tx = x+decodeX[d];
          ty = y+decodeY[d];
          return;
        }
      }
      void render() {
        stroke(0);
        fill(is_scared?color(0, 0, 255):ghost_colors[type]);
        pushMatrix();
        translate(x, y);
        if (!is_dead) {
          rect(-11, -1, 22, 11);
          arc(0, 0, 22, 22, PI, TWO_PI);
          for (int i=0; i<4; i++) {
            arc(-7+5*i, 10, 5, 5, 0, PI);
          }
        }
        fill(255);
        noStroke();
        ellipse(-4, 0, 4, 8);
        ellipse(4, 0, 4, 8);
        if (is_dead||!is_scared) {
          fill(0, 0, 255);
          int eyex = (d==2?-1:0)+(d==0?1:0);
          int eyey = (d==3?-3:0)+(d==1?3:0);
          ellipse(-4+eyex, eyey, 3, 3);
          ellipse(4+eyex, eyey, 3, 3);
        }
        popMatrix();
      }
      void kill_check() {
        if ( grid.kill_at(x, y) ) is_dead = true;
      }
    }
    
    int[] decodeX = { 
      20, 0, -20, 0, 0
    };
    int[] decodeY = { 
      0, 20, 0, -20, 0
    };
    
    
    Grid grid;
    Player player;
    Ghost[] ghosts;
    
    boolean to_corners = false;
    int timer_corners;
    
    color[] ghost_colors = {
      color(255, 0, 0), 
      color(255, 64, 196), 
      color(0, 255, 255), 
      color(255, 128, 0), 
      color(0, 255, 0), 
      //  color(196),
      //  color(128),
      //  color(64),
    };
    
    void setup() {
      size(601, 601);
      grid = new Grid();
      grid.load_level();
      player = new Player();
      ghosts = new Ghost[ghost_colors.length];
      for (int i=0; i<ghosts.length; ghosts[i] = new Ghost (i++));
      timer_corners = millis() + 10000;
    }
    
    void game_reset() {
      player.die();
      ghosts_reset();
    }
    
    void ghosts_reset() {
      // Could write a proper reset for the ghosts.
      for (int i=0; i<ghosts.length; ghosts[i] = new Ghost (i++));
    }
    
    void draw() {
      background(0);
      grid.draw();
      player.draw();
      for (int i=0; i<ghosts.length; ghosts[i++].draw ());
      if ( millis() > timer_corners) {
        timer_corners = millis() + 10000;
        to_corners = !to_corners;
      }
    }
    
    void keyPressed() {
      grid.on_keyPressed();
      player.on_keyPressed();
      if ( key == ' ') { 
        to_corners = !to_corners;
      }
      if ( key == 'd' ) player.die();
      if ( key == 'r' ) game_reset();
    }
    
    void mousePressed() {
      grid.world_edit(mouseX, mouseY);
    }
    

    NOW QUIT PLAYING GAMES AND GET BACK TO WORK / LEARNING TO PROGRAM!

  • uhh mind if u put all these together its so confusing

  • edited November 2017

    Hello,

    I made some changes in the sketch , it has now the order of a classical processing sketch, classes at the end etc..

    The Maze file

    Also, when no file "world.dat" is found, a maze is done randomly now.

    you can edit this by mouse. And save with "s" !

    especially, edit it so that there are walls on screen borders, otherwise crashes.

    unfortunately I am not sure how to post world.dat here because it's a byte file.

    Concepts

    There are complex concepts here, arrays and class, 2D arrays inside a class...

    You need to know the concepts here first to understand the sketch.

    I suggest, you read the tutorials on arrays, on objects and on 2D arrays.

    https://www.processing.org/tutorials/

    Then come back with questions.

    Chrisir

    // pac man 
    
    int[] decodeX = { 
      20, 0, -20, 0, 0
    };
    int[] decodeY = { 
      0, 20, 0, -20, 0
    };
    
    
    Grid grid;
    Player player;
    Ghost[] ghosts;
    
    boolean to_corners = false;
    int timer_corners;
    
    color[] ghost_colors = {
      color(255, 0, 0), 
      color(255, 64, 196), 
      color(0, 255, 255), 
      color(255, 128, 0), 
      color(0, 255, 0), 
      //  color(196),
      //  color(128),
      //  color(64),
    };
    
    // --------------------------------------------------------------------------
    // core functions 
    
    void setup() {
      size(601, 601);
    
      grid = new Grid();
      grid.load_level();
      player = new Player();
      ghosts = new Ghost[ghost_colors.length];
    
      // init ghosts 
      for (int i=0; i<ghosts.length; i++) {
        ghosts[i] = new Ghost (i);
      }
    
      timer_corners = millis() + 10000;
    }
    
    void draw() {
      background(0);
    
      grid.draw();
      player.draw();
    
      for (int i=0; i<ghosts.length; i++)
        ghosts[i].draw ();
    
      if ( millis() > timer_corners) {
        timer_corners = millis() + 10000;
        to_corners = !to_corners;
      }
    }
    
    //-----------------------------------------------------------------
    // Input 
    
    void keyPressed() {
      grid.on_keyPressed();
      player.on_keyPressed();
      if ( key == ' ') { 
        to_corners = !to_corners;
      }
      if ( key == 'd' ) player.die();
      if ( key == 'r' ) game_reset();
    }
    
    void mousePressed() {
      grid.world_edit(mouseX, mouseY);
    }
    
    //-----------------------------------------------------------------
    // other 
    
    void game_reset() {
      player.die();
      ghosts_reset();
    }
    
    void ghosts_reset() {
      // Could write a proper reset for the ghosts.
      for (int i=0; i<ghosts.length; i++)
        ghosts[i] = new Ghost (i);
    }
    
    // =============================================================
    
    class Player {
    
      float start_x = 30;
      float start_y = 30;
      float x, y;
      int d;
      float mouth_opening, max_mouth_opening, mouth_step;
      boolean is_mouth_opening = true;
      boolean am_i_super = false;
      boolean is_dead = false;
      int super_countdown;
    
      Player() {
        reset();
      }
    
      void reset() {
        x = start_x;
        y = start_y;
        d = 0;
        mouth_opening = 0; 
        max_mouth_opening = .4; 
        mouth_step = .01;
        am_i_super = false;
        super_countdown = 0;
        is_dead = false;
      }
    
      void die() {
        is_dead = true;
        max_mouth_opening = TWO_PI;
        mouth_step = .1;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        if (mouth_opening > PI ) reset();
        if (is_dead) { 
          animate_mouth(); 
          return;
        }
        float px=x, py=y;
        if (0==d) x++;
        if (1==d) y++;
        if (2==d) x--;
        if (3==d) y--;
        if (grid.is_wall(x, y)) {
          x = px;
          y = py;
        } else {
          animate_mouth();
          grid.eat_dot_at(x, y);
        }
        if (super_countdown > 0) { 
          super_countdown--;
        }
        if (super_countdown == 0) { 
          am_i_super = false;
          for (int i=0; i<ghosts.length; ghosts[i++].dont_be_afraid ());
        }
      }
      void animate_mouth() {
        if (is_mouth_opening) {
          mouth_opening+=mouth_step;
        } else {
          mouth_opening-=mouth_step;
        }
        if (mouth_opening > max_mouth_opening || mouth_opening < 0) {
          is_mouth_opening = !is_mouth_opening;
        }
      }
      void be_super() {
        am_i_super = true;
        super_countdown = 500;
        for (int i=0; i<ghosts.length; ghosts[i++].be_afraid ());
      }
      void render() {
        pushMatrix();
        translate(x, y);
        rotate(HALF_PI*d);
        stroke(0);
        fill(am_i_super?color(random(255), random(255), random(255)):color(255, 255, 0));
        ellipse(0, 0, 22, 22);
        fill(0);
        arc(0, 0, 22, 22, -mouth_opening, mouth_opening);
        popMatrix();
      }
      void on_keyPressed() {
        if ( key == CODED ) {
          if ( keyCode == RIGHT ) d=0;
          if ( keyCode == DOWN )  d=1;
          if ( keyCode == LEFT )  d=2;
          if ( keyCode == UP )    d=3;
        }
      }
    }
    
    // =========================================================================
    
    class Grid {
      byte[][] data = new byte[30][30];
      Grid() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            data[j][i] = 2;
            if (0==i || 0==j || 29==i || 29==j) { 
              data[j][i] = 1;
            }
          }
        }
        data[5][10] = 3;
      }
      void draw() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            noFill();      
            if (data[j][i] == 1) { 
              fill(0, 0, 255);
            }
            if ( data[j][i] == 1 ) {
              pushStyle();
              stroke(0, 0, 255);
              //stroke(0, 255-map(dist(player.x,player.y,20*i,20*j),0,200,0,255), 255 );
              strokeWeight(12);
              pushMatrix();
              translate(20*i, 20*j);
              line(10, 10, 10, 10);
              if (i<29 && data[j][i+1] == 1) {
                line(10, 10, 30, 10);
              }
              if (j<29 && data[j+1][i] == 1) {
                line(10, 10, 10, 30);
              }
              popMatrix();
              popStyle();
            }
            if (data[j][i] == 2) {
              fill(196);
              noStroke();
              ellipse(20*i+10, 20*j+10, 6, 6);
            }      
            if (data[j][i] == 3) {
              fill(255);
              noStroke();
              ellipse(20*i+10, 20*j+10, 12, 12);
            }
          }
        }
      }
      boolean is_wall(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        return (data[j][i] == 1);
      }
      void eat_dot_at(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        if (data[j][i] == 3) {
          player.be_super();
        }
        data[j][i] = 0;
      }
      void world_edit(int ix, int iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        data[j][i]++;
        data[j][i]%=4;
      }
      void on_keyPressed() {
        if (key == 's' ) { 
          grid.save_level();
        }
        if (key == 'l' ) {
          grid.load_level();
        }
      }
      void save_level() {
        byte[] temp = new byte[900];
        int t = 0;
        for (int j = 0; j < 30; j++) {
          for (int i = 0; i < 30; i++) {
            temp[t++] = grid.data[j][i];
          }
        } 
        saveBytes("world.dat", temp);
        println("Level saved.");
      }  
      void load_level() {
        byte[] temp = loadBytes("world.dat");
        int t = 0;
        if (temp!=null) {
          for (int j = 0; j < 30; j++) {
            for (int i = 0; i < 30; i++) {
              grid.data[j][i] = temp[t++];
            }
          }
        } else {
          for (int j = 0; j < 30; j++) {
            for (int i = 0; i < 30; i++) {
              grid.data[j][i] = byte(random(2));
            }
          }
        }
        println("Level loaded.");
      }
      boolean kill_at(int ix, int iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        int pmi = int(player.x/20); 
        int pmj = int(player.y/20);
        if (i==pmi&&j==pmj) {
          if (player.am_i_super) {
            return true;
          } else {
            player.die();
          }
        }
        return false;
      }
    }
    
    // ============================================================
    
    class Ghost {
    
      int type;
      int x, y, tx, ty, ptx, pty;
      int pgx, pgy;
      int d;
      boolean is_scared;
      boolean is_dead;
      int trapped_timer;
    
      Ghost(int itype) {
        type = itype % ghost_colors.length;
        x = 10 + 20 * 15;
        y = 10 + 20 * 14;
        tx = x;
        ty = y;
        ptx=tx;
        pty=ty;
        trapped_timer = 200 * type;
      }
      void dont_be_afraid() {
        if (is_scared) {
          is_scared = false;
          d=(d+2)%4;
          tx = ptx;
          ty = pty;
        }
      }
      void be_afraid() {
        if (!is_dead) {
          is_scared = true;
          d=(d+2)%4;
          tx = ptx;
          ty = pty;
        }
      }  
      void draw() {
        simulate();
        render();
        if (!is_dead) kill_check();
      }
      void simulate() {
        trapped_timer--;
        if (trapped_timer > 0) return;
        int px = x;
        int py = y;
        if (tx < x) x--;
        if (tx > x) x++;
        if (ty < y) y--;
        if (ty > y) y++;
        if (px==x&&py==y) {
          ptx = tx;
          pty = ty;
          int wall_count = 0;
          for (int w = 0; w < 4; w++) {
            if ( grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
              wall_count++;
            }
          }
          if (wall_count == 4) { // >:(
            d = 4;
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          if (wall_count == 3) {
            for (int w = 0; w < 4; w++) {
              if ( !grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
                d = w;
              }
            }
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          if (wall_count == 2) {
            int result = 5;
            for (int w = 0; w < 4; w++) {
              if ( !grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
                if ( w != (d+2)%4 ) {
                  result = w;
                }
              }
            }
            d = result;
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          int gx = int(player.x); // RED - Go for pacman.
          int gy = int(player.y);
          if (!to_corners) {
            if (type == 1 ) { // PINK = Get in front of pacman.
              gx = int(player.x)+4*decodeX[player.d];
              gy = int(player.y)+4*decodeY[player.d];
              if ( player.d == 3 ) { // Classic pink ghost behaviour.
                gx = int(player.x-80);
              }
            }
            if ( type == 2 ) { // CYAN - Negative RED's positions, offset a couple of squares.
              float mpx = player.x+2*decodeX[player.d];
              float mpy = player.y+2*decodeY[player.d];
              if (player.d == 3) { // Classic cyan ghost behaviour.
                mpx = player.x - 40;
              }
              gx = int(2*mpx - ghosts[0].x);
              gy = int(2*mpy - ghosts[0].y);
            }
            if ( type == 3 ) { // ORANGE - Get close, then back off.
              if (dist(player.x, player.y, x, y) < 160) {
                gx = 0;
                gy = height;
              }
            }
          } else {
            gx = width;
            gy = height;
            if ( type == 1 || type == 3 ) gx = 0; 
            if ( type == 1 || type == 0 ) gy = 0;
          }
          if (is_dead||is_scared) {
            gx = 10 + 20 * 15;
            gy = 10 + 20 * 14;
            if (is_dead && x==gx &&y==gy) is_dead = false;
          }    
          pgx = gx;
          pgy = gy;
          float best = -1 ;
          int result = 5;
          for ( int w = 0; w < 4; w++) {
            if ( w!=(d+2)%4 && !grid.is_wall(x+decodeX[w], y+decodeY[w])) {
              float new_dist = dist(x+decodeX[w], y+decodeY[w], gx, gy);
              if ( best == -1 || new_dist < best) {
                best = new_dist;
                result = w;
              }
            }
          }
          d = result;
          tx = x+decodeX[d];
          ty = y+decodeY[d];
          return;
        }
      }
      void render() {
        stroke(0);
        fill(is_scared?color(0, 0, 255):ghost_colors[type]);
        pushMatrix();
        translate(x, y);
        if (!is_dead) {
          rect(-11, -1, 22, 11);
          arc(0, 0, 22, 22, PI, TWO_PI);
          for (int i=0; i<4; i++) {
            arc(-7+5*i, 10, 5, 5, 0, PI);
          }
        }
        fill(255);
        noStroke();
        ellipse(-4, 0, 4, 8);
        ellipse(4, 0, 4, 8);
        if (is_dead||!is_scared) {
          fill(0, 0, 255);
          int eyex = (d==2?-1:0)+(d==0?1:0);
          int eyey = (d==3?-3:0)+(d==1?3:0);
          ellipse(-4+eyex, eyey, 3, 3);
          ellipse(4+eyex, eyey, 3, 3);
        }
        popMatrix();
      }
      void kill_check() {
        if ( grid.kill_at(x, y) ) is_dead = true;
      }
    }//class ghost 
    
    // ==========================================================================
    //
    
  • new version that saves grid as Strings

    // pac man 
    
    int[] decodeX = { 
      20, 0, -20, 0, 0
    };
    int[] decodeY = { 
      0, 20, 0, -20, 0
    };
    
    Grid grid;
    Player player;
    Ghost[] ghosts;
    
    boolean to_corners = false;
    int timer_corners;
    
    color[] ghost_colors = {
      color(255, 0, 0), 
      color(255, 64, 196), 
      color(0, 255, 255), 
      color(255, 128, 0), 
      color(0, 255, 0), 
      //  color(196),
      //  color(128),
      //  color(64),
    };
    
    // --------------------------------------------------------------------------
    // core functions 
    
    void setup() {
      size(601, 601);
    
      grid = new Grid();
      grid.load_level();
    
      player = new Player();
    
      ghosts = new Ghost[ghost_colors.length];
    
      // init ghosts 
      for (int i=0; i<ghosts.length; i++) {
        ghosts[i] = new Ghost (i);
      }
    
      timer_corners = millis() + 10000;
    }
    
    void draw() {
      background(0);
    
      grid.draw();
      player.draw();
    
      for (int i=0; i<ghosts.length; i++) {
        ghosts[i].draw ();
      }
    
      if ( millis() > timer_corners) {
        timer_corners = millis() + 10000;
        to_corners = !to_corners;
      }
    }
    
    //-----------------------------------------------------------------
    // Input 
    
    void keyPressed() {
    
      grid.on_keyPressed();
      player.on_keyPressed();
    
      if ( key == ' ') { 
        to_corners = !to_corners;
      }
      if ( key == 'd' )
        player.die();
      if ( key == 'r' )
        game_reset();
    }//func 
    
    void mousePressed() {
      grid.world_edit(mouseX, mouseY);
    }
    
    //-----------------------------------------------------------------
    // other 
    
    void game_reset() {
      player.die();
      ghosts_reset();
    }
    
    void ghosts_reset() {
      // Could write a proper reset for the ghosts.
      for (int i=0; i<ghosts.length; i++)
        ghosts[i] = new Ghost (i);
    }
    
    // =====================================================================
    
    class Player {
    
      float start_x = 30;
      float start_y = 30;
      float x, y;
      int d;
      float mouth_opening, max_mouth_opening, mouth_step;
      boolean is_mouth_opening = true;
      boolean am_i_super = false;
      boolean is_dead = false;
      int super_countdown;
    
      Player() {
        reset();
      }
    
      void reset() {
        x = start_x;
        y = start_y;
        d = 0;
        mouth_opening = 0; 
        max_mouth_opening = .4; 
        mouth_step = .01;
        am_i_super = false;
        super_countdown = 0;
        is_dead = false;
      }
    
      void die() {
        is_dead = true;
        max_mouth_opening = TWO_PI;
        mouth_step = .1;
      }
      void draw() {
        simulate();
        render();
      }
      void simulate() {
        if (mouth_opening > PI ) reset();
        if (is_dead) { 
          animate_mouth(); 
          return;
        }
        float px=x, py=y;
        if (0==d) x++;
        if (1==d) y++;
        if (2==d) x--;
        if (3==d) y--;
        if (grid.is_wall(x, y)) {
          x = px;
          y = py;
        } else {
          animate_mouth();
          grid.eat_dot_at(x, y);
        }
        if (super_countdown > 0) { 
          super_countdown--;
        }
        if (super_countdown == 0) { 
          am_i_super = false;
          for (int i=0; i<ghosts.length; ghosts[i++].dont_be_afraid ());
        }
      }
      void animate_mouth() {
        if (is_mouth_opening) {
          mouth_opening+=mouth_step;
        } else {
          mouth_opening-=mouth_step;
        }
        if (mouth_opening > max_mouth_opening || mouth_opening < 0) {
          is_mouth_opening = !is_mouth_opening;
        }
      }
      void be_super() {
        am_i_super = true;
        super_countdown = 500;
        for (int i=0; i<ghosts.length; ghosts[i++].be_afraid ());
      }
      void render() {
        pushMatrix();
        translate(x, y);
        rotate(HALF_PI*d);
        stroke(0);
        fill(am_i_super?color(random(255), random(255), random(255)):color(255, 255, 0));
        ellipse(0, 0, 22, 22);
        fill(0);
        arc(0, 0, 22, 22, -mouth_opening, mouth_opening);
        popMatrix();
      }
      void on_keyPressed() {
        if ( key == CODED ) {
          if ( keyCode == RIGHT ) d=0;
          if ( keyCode == DOWN )  d=1;
          if ( keyCode == LEFT )  d=2;
          if ( keyCode == UP )    d=3;
        }
      }
    }
    
    // =========================================================================
    
    class Grid {
    
      String[][] data = new String[30][30];
    
      // constr 
      Grid() {
    
        for (int j=0; j<30; j++) {
          for (int i=0; i<30; i++) {
    
            data[j][i] = "2";
    
            int a = int(random(4));
            data[j][i] = str(a); // any
    
            // screen border
            if (0==i || 0==j || 29==i || 29==j) { 
              data[j][i] = "1"; // wall
            }//if 
            //
          }//for
        }//for 
    
        data[5][10] = "3";
      }//constr
    
      void draw() {
        for (int j=0; j<height/20; j++) {
          for (int i=0; i<width/20; i++) {
            noFill();      
            if (data[j][i].equals( "1")) { 
    
              fill(0, 0, 255); // blue
              pushStyle();
              stroke(0, 0, 255);
              //stroke(0, 255-map(dist(player.x,player.y,20*i,20*j),0,200,0,255), 255 );
              strokeWeight(12);
              pushMatrix();
              translate(20*i, 20*j);
              line(10, 10, 10, 10);
              if (i<29 && data[j][i+1] .equals(  "1")) {
                line(10, 10, 30, 10);
              }
              if (j<29 && data[j+1][i] .equals(  "1")) {
                line(10, 10, 10, 30);
              }
              popMatrix();
              popStyle();
            }
            if (data[j][i] .equals( "2")) {
              fill(196);
              noStroke();
              ellipse(20*i+10, 20*j+10, 6, 6);
            }      
            if (data[j][i] .equals( "3")) {
              fill(255);
              noStroke();
              ellipse(20*i+10, 20*j+10, 12, 12);
            }
          }
        }
      }
    
      boolean is_wall(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        return (data[j][i] .equals(  "1"));
      }
    
      void eat_dot_at(float ix, float iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        if (data[j][i] .equals(  "3")) {
          player.be_super();
        }
        data[j][i] = "0";
      }
    
      void world_edit(int ix, int iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        data[j][i]=str(int(data[j][i])+1);
        data[j][i]=str(int(data[j][i])%4);
      }
    
      void on_keyPressed() {
        if (key == 's' ) { 
          save_level();
        }
        if (key == 'l' ) {
          load_level();
        }
      }
    
      void save_level() {
        String[] temp = new String[30];
        int t = 0;
        for (int j = 0; j < 30; j++) {
          temp[j] = "";
          for (int i = 0; i < 30; i++) {
            temp[j] += data[j][i];
          }
        } 
        saveStrings("world.dat", temp);
        println("Level saved.");
      }  
    
      void load_level() {
        String[] temp = loadStrings("world.dat");
        int t = 0;
    
        // Loading successful?
        if (temp!=null) {
          // success in loading 
          for (int j = 0; j < 30; j++) {
            for (int i = 0; i < 30; i++) {
              data[j][i] = ""+temp[j].charAt(i);
            }
          }
          println("Level loaded.");
        }//
      }//method
    
      boolean kill_at(int ix, int iy) {
        int i = int(ix/20);
        int j = int(iy/20);
        int pmi = int(player.x/20); 
        int pmj = int(player.y/20);
        if (i==pmi&&j==pmj) {
          if (player.am_i_super) {
            return true;
          } else {
            player.die();
          }
        }
        return false;
      }
    }
    
    // ============================================================
    
    class Ghost {
    
      int type;
      int x, y, tx, ty, ptx, pty;
      int pgx, pgy;
      int d;
      boolean is_scared;
      boolean is_dead;
      int trapped_timer;
    
      Ghost(int itype) {
        type = itype % ghost_colors.length;
        x = 10 + 20 * 15;
        y = 10 + 20 * 14;
        tx = x;
        ty = y;
        ptx=tx;
        pty=ty;
        trapped_timer = 200 * type;
      }
      void dont_be_afraid() {
        if (is_scared) {
          is_scared = false;
          d=(d+2)%4;
          tx = ptx;
          ty = pty;
        }
      }
      void be_afraid() {
        if (!is_dead) {
          is_scared = true;
          d=(d+2)%4;
          tx = ptx;
          ty = pty;
        }
      }  
      void draw() {
        simulate();
        render();
        if (!is_dead) kill_check();
      }
      void simulate() {
        trapped_timer--;
        if (trapped_timer > 0) return;
        int px = x;
        int py = y;
        if (tx < x) x--;
        if (tx > x) x++;
        if (ty < y) y--;
        if (ty > y) y++;
        if (px==x&&py==y) {
          ptx = tx;
          pty = ty;
          int wall_count = 0;
          for (int w = 0; w < 4; w++) {
            if ( grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
              wall_count++;
            }
          }
          if (wall_count == 4) { // >:(
            d = 4;
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          if (wall_count == 3) {
            for (int w = 0; w < 4; w++) {
              if ( !grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
                d = w;
              }
            }
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          if (wall_count == 2) {
            int result = 5;
            for (int w = 0; w < 4; w++) {
              if ( !grid.is_wall(x+decodeX[w], y+decodeY[w]) ) {
                if ( w != (d+2)%4 ) {
                  result = w;
                }
              }
            }
            d = result;
            tx = x+decodeX[d];
            ty = y+decodeY[d];
            return;
          }
          int gx = int(player.x); // RED - Go for pacman.
          int gy = int(player.y);
          if (!to_corners) {
            if (type == 1 ) { // PINK = Get in front of pacman.
              gx = int(player.x)+4*decodeX[player.d];
              gy = int(player.y)+4*decodeY[player.d];
              if ( player.d == 3 ) { // Classic pink ghost behaviour.
                gx = int(player.x-80);
              }
            }
            if ( type == 2 ) { // CYAN - Negative RED's positions, offset a couple of squares.
              float mpx = player.x+2*decodeX[player.d];
              float mpy = player.y+2*decodeY[player.d];
              if (player.d == 3) { // Classic cyan ghost behaviour.
                mpx = player.x - 40;
              }
              gx = int(2*mpx - ghosts[0].x);
              gy = int(2*mpy - ghosts[0].y);
            }
            if ( type == 3 ) { // ORANGE - Get close, then back off.
              if (dist(player.x, player.y, x, y) < 160) {
                gx = 0;
                gy = height;
              }
            }
          } else {
            gx = width;
            gy = height;
            if ( type == 1 || type == 3 ) gx = 0; 
            if ( type == 1 || type == 0 ) gy = 0;
          }
          if (is_dead||is_scared) {
            gx = 10 + 20 * 15;
            gy = 10 + 20 * 14;
            if (is_dead && x==gx &&y==gy) is_dead = false;
          }    
          pgx = gx;
          pgy = gy;
          float best = -1 ;
          int result = 5;
          for ( int w = 0; w < 4; w++) {
            if ( w!=(d+2)%4 && !grid.is_wall(x+decodeX[w], y+decodeY[w])) {
              float new_dist = dist(x+decodeX[w], y+decodeY[w], gx, gy);
              if ( best == -1 || new_dist < best) {
                best = new_dist;
                result = w;
              }
            }
          }
          d = result;
          tx = x+decodeX[d];
          ty = y+decodeY[d];
          return;
        }
      }
      void render() {
        stroke(0);
        fill(is_scared?color(0, 0, 255):ghost_colors[type]);
        pushMatrix();
        translate(x, y);
        if (!is_dead) {
          rect(-11, -1, 22, 11);
          arc(0, 0, 22, 22, PI, TWO_PI);
          for (int i=0; i<4; i++) {
            arc(-7+5*i, 10, 5, 5, 0, PI);
          }
        }
        fill(255);
        noStroke();
        ellipse(-4, 0, 4, 8);
        ellipse(4, 0, 4, 8);
        if (is_dead||!is_scared) {
          fill(0, 0, 255);
          int eyex = (d==2?-1:0)+(d==0?1:0);
          int eyey = (d==3?-3:0)+(d==1?3:0);
          ellipse(-4+eyex, eyey, 3, 3);
          ellipse(4+eyex, eyey, 3, 3);
        }
        popMatrix();
      }
      void kill_check() {
        if ( grid.kill_at(x, y) ) is_dead = true;
      }
    }//class ghost 
    
    // ==========================================================================
    //
    
  • the grid:

    111111111111111111111111111111
    101312313311200103110313210231
    110122313313123013222010201101
    130020213323230230122232320111
    111111111132210113330102113321
    131212201332131332331223103201
    111012201003003120020302231221
    120121232022000201131333212011
    102001200011220030233322223211
    103333222211032300233023101321
    111311112020101212131213201221
    101012312033110112221021101001
    133311103103311001123110212321
    123302103011211231302120200231
    133221021333132032113321233201
    112131123223021213302031301231
    101322023303101311201203211131
    110223013002223103223022330131
    101100001031332033230310032201
    102302213012330323100111013221
    132320020200331012012003213311
    131310102212303002101303311321
    121032203001201002330212131101
    121100230312320103330023300121
    130312311020012013032100321201
    131221333133132222012331031031
    103021132202023300002301021221
    123203110200100112102033230131
    110122033310310112331310320301
    111111111111111111111111111111
    
  • Perhaps continue this on a new thread? The OP posted this in 2015; this is on topic but no longer relevant to their question.

This discussion has been closed.