Loading...
Logo
Processing Forum
I month ago I started a thread asking for help with a game geared at helping disabled people gain coordination using a device a designed.
 
Chrisir jumped in and wrote a great game that I later just dressed up a little.
I thought I'd post the link here since its pretty fun to use and can be adapted to any theme by photo shopping the cards.
 
here are some screenshots and the link to all of the files.
I did it NFL theme because the patient is a huge NFL fan (NFL please don't sue me :) )
 
Thanks again Chrisir!!!
 
FILES: 
 
 
 
 
 
Copy code

  1. import ddf.minim.*;
    Minim minim;
    AudioPlayer player;
    AudioPlayer player1;
    AudioPlayer player2;
    //
    // to do (optional): if uneven, place non-existent tile into right lower corner? With 8 tiles.
    //        have each level twice? Twice two cards, twice 4 cards etc.
    //
    // global vars and constants
    //
    // how many images on the hard drive? (this+1) Must be in data folder and named 0.jpg, 1.jpg etc.
    final int howManyImages = 18;
    //
    //
    // level stuff
    final int maxLevel = 10; // how many levels, e.g. 6
    int level = 0;          // current level: 0
    //
    // state of program / game
    final int stateGameStartUp  = 0;
    final int stateGamePlay     = 1;
    final int stateGameGoToNextLevelPhase1 = 2; // these two provide a small delay
    final int stateGameGoToNextLevelPhase2 = 3;
    final int stateGameOver     = 4;
    final int stateGameShowHelp = 5;
    //
    int state = stateGameStartUp;  // current
    //
    //
    // data for tiles
    int winningNumberOfTiles;
    int TILES_HORZ ;
    int TILES_VERT ;
    int TOTAL_TILES ;
    int tileWidth;
    int tileHeight;
    Tile[] tiles ;
    int imageCode;
    //
    // allRandomNumberImage is a check list to avoid using the same image twice as long as possible...
    String allRandomNumberImage="#";
    PImage[] images = new PImage [howManyImages];
    //
    // image entering stuff
    // The var "openImages" is a counter that controls the input logic while making a move (aka opening two tiles).
    // It says how many tiles are currently shown? 0, 1 or 2. (before the move, during the move and after the move).
    // Only when openImages is == 2 we need to compare the two images (and reset openImages to 0 then).
    int openImages = 0;    // counter for current move  
    int lastImage = -1;    // which was the last tile? (1st tile opened)
    int currentImage = -1; // which is the current tile / image? (2nd tile opened)
    int timer;
    PImage imgLogo;
    PImage imgWin;
    PImage imgBackGlobal;
    PImage imgBack = new PImage();// image of back of card
    //
    //
    // ------------------------------------------------------------------
    // two main funcs
    //
    void setup()
    {
      size( 1800, 900);
      println("start of setup() ");
      //
        minim = new Minim(this);
            player = minim.loadFile("nfl.wav");
        player1 = minim.loadFile("mixdown.wav");
        player2 = minim.loadFile("crowd.wav");
      imgLogo       = loadImage("logo.jpg");
      imgBackGlobal = loadImage("cardBack.jpg");
      imgBack       = loadImage("cardBack.jpg");
      imgWin  = loadImage("youWon.jpg");
      //
      for (int x=0; x<howManyImages; x++) {
        images[x]=loadImage(str(x)+".jpg");
      } // for
      //
      timer=millis();
      println("end of setup()");
    }
    //
    void draw()
    {
      switch (state) {
      case stateGameStartUp:
        // start screen and new level
        println("STARTUP");
        startScreen() ;
  2.     break;
      case stateGamePlay:
        // play
        //println("gameplay");
        gamePlay();    
        break;
      case stateGameGoToNextLevelPhase1:
        // go to next level but only after a while
        println("GTNL1");
        goToNextLevel_1();
        break;
      case stateGameGoToNextLevelPhase2:
        // go to next level but only after a while
        println("GTNL2");
        goToNextLevel_2();
        break;   
      case stateGameOver:
        // All levels done
        println("gameover");
        showWinScreen();
        break;
      case stateGameShowHelp:
        // help - to do
        println ( "This is your help / reached by F1 / not done yet...");
        break;
      default:
        // error; shouldn't get here 
        println ("Error 86: unknown state");
        break;
      } // switch
      //
    } // func
    // ---------------------------------------------------------------
    // all funcs that get called from draw()
    //
    void startScreen() {
      player.play();
      player2.play();
      // start screen : to do: make a cool start screen image
      background(0);
      // fill(2, 2, 255);
     image(imgLogo, width/4.3, height/3.3);
      textSize(80);
      fill(255, 255, 255);
      text ( " MEMORY GAME", width/3.5+200, height/2.2);
      textSize(100);
      text ( "LEVEL:  "+(level+1), width/2.2, height/1.7);
      text ( "           ", 140, 301);
      text ( "                   ", 140, 401);
      // go next state but only after a while
      if (timer + 5200 < millis()) {
        initNewLevel();
        state = stateGamePlay;
      } // if
    } // func
    //
    void gamePlay() {
      // play
      background(0);
      drawTiles();
      checkTwoShownTiles ();
    } // func
    //
    void goToNextLevel_1() {
      // wait before go to next level but only after a while
      background(0);
      drawTiles();
      if (timer + 1000 < millis()) {
        state=stateGameGoToNextLevelPhase2;
        timer=millis();
      } // if
    } // func
    //
    void goToNextLevel_2() {
      // go to next level but only after a while
      background(0);
      drawTiles();
      showHooray(); 
      if (timer + 1000 < millis()) {
        // Was this the last level?
        if (level==maxLevel) {
          // yes, last level, game over.
          state = stateGameOver;   // won all levels
          println("game over (all levels done).");
        }
        else
        {
          // no, go to next level.
          state = stateGameStartUp;
          timer=millis();
        }
      } // if
    } // func
    //
    void showWinScreen() {
      background(0);
      drawTiles();
      showHooray() ;
      // show all levels done
     background(0) ;
     image(imgWin, 750,100);
      fill(0);   // black
      noStroke();
      rect (14, 104, 295, 100);
      fill(255, 255, 255);  // red
      text ( "   CONGRADULATIONS YOU FINISHED THE GAME!!!", 40, 160);
      textSize(20);
      text ( "                 CLICK MOUSE TO PLAY AGAIN", 40, 190);
      player1.play();
    } // func
    //
    // ------------------
    //
    void showHooray() {
  3.   fill(255);
      strokeWeight(3);
      stroke(0);
      rect (4, 4, 325, 100);
      fill(2, 2, 255);
      text ( "LEVEL FINISHED!!!", 10, 60);
     
    } // func
    // -----------------------------------------------------------
    // all funcs for inits
    //
    void initNewLevel () {
      //
  4.   println("Init New Level #"+level);
      //
      // depending on current level set some basic vars
      switch (level) {
      case 0:
        // just 2 pieces
        TILES_HORZ =2;
        TILES_VERT =1;
        winningNumberOfTiles = 2;
        break;
      case 1:
        // 4 pieces
        TILES_HORZ =2;
        TILES_VERT =2;
        winningNumberOfTiles = 4;
        break;
      case 2:
        TILES_HORZ =3;
        TILES_VERT =2;
        winningNumberOfTiles = 6;
        break;
      case 3:
        TILES_HORZ =3;
        TILES_VERT =3;
        winningNumberOfTiles = 9; // is 8
        break;
      case 4:
        TILES_HORZ =4;
        TILES_VERT =3;
        winningNumberOfTiles = 12; // is 12
        break;
      case 5:
        TILES_HORZ =4;
        TILES_VERT =4;
        winningNumberOfTiles = 16; // is 16
        break;
          case 6:
        TILES_HORZ =5;
        TILES_VERT =4;
        winningNumberOfTiles = 20; // is 20
        break;
          case 7:
        TILES_HORZ =5;
        TILES_VERT =5;
        winningNumberOfTiles = 25; // is 24
        break;
          case 8:
        TILES_HORZ =6;
        TILES_VERT =5;
        winningNumberOfTiles = 30; // is 30
        break;
          case 9:
        TILES_HORZ =6;
        TILES_VERT =6;
        winningNumberOfTiles = 36; // is 36
        break;
  5.    
      default:
        println("Error 55: Unknown Level");
        break;
      } // switch
      //
      // have other vars based on that defined  
      if (level>0) {
        // level > 0
        defineNormalTileSet() ;
      }
      else
      {
        // level is 0
        defineTileSetForLevelZero() ;
      }
      textSize(54);
  6. } // func
    //
    void defineTileSetForLevelZero() {
      // level is 0
      //
      println ("******************LEVEL ZERO********************************");
      // make data for tiles and the tiles
      tileWidth=width/2;
      tileHeight=height/2;
      TOTAL_TILES = 2;
      tiles = new Tile [TOTAL_TILES+1];
      tiles[0] = new Tile (0, height-tileHeight);
      tiles[1] = new Tile (tileWidth, height-tileHeight);
      println("ENDTILES");
      //
      //
      // make duplicates ---------------------
      tiles[0].hasDuplicate=true;   // both tiles have a duplicate now
      tiles[1].hasDuplicate=true;
      tiles[0].theImageCode=44;  // both tiles get the same imageCode
      tiles[1].theImageCode=44;  // saying: you two are belonging together
      int myImageIndex = giveImageIndex(); // get an index
      tiles[0].loadImageIntoTile ( myImageIndex ); // same image
      tiles[1].loadImageIntoTile ( myImageIndex );
  7.   imgBack.copy(imgBackGlobal,
      0, 0, imgBackGlobal.width, imgBackGlobal.height,
      0, 0, tileWidth, 0);
  8. }
    //
    void defineNormalTileSet() {
      //
      int i=0;
      tileWidth=width/TILES_HORZ-1 ;
      tileHeight=tileWidth/2;
      TOTAL_TILES = (TILES_HORZ)*(TILES_VERT);
      // not even?
      if (winningNumberOfTiles%2 != 0 ) {
  9.     winningNumberOfTiles--;
      }
      tiles = new Tile [TOTAL_TILES+1];
      // now define the tiles without the images ------------------
      for (int x=0; x<TILES_HORZ; x++) {
        for (int y=0; y<TILES_VERT; y++) {  
          tiles[i] = new Tile (tileWidth*x, tileHeight*y );
          i++;
        }
      }
      //
      // make duplicates ---------------------
      i=0;
      // this arraylist "intTileIndexes" serves as a memory which
      // cards we already treated
      ArrayList <Integer> intTileIndexes = new ArrayList();
      intTileIndexes.clear();
      // fill the arraylist
      for (int x=0; x<TILES_HORZ; x++) {
        for (int y=0; y<TILES_VERT; y++) {
          intTileIndexes.add( i );
          i++;
        }
      }
      // still make duplicates ------
      i=0;
      imageCode=0;
      allRandomNumberImage="#";
      for (int x=0; x<TILES_HORZ; x++) {
        for (int y=0; y<TILES_VERT; y++) {
          makeItHaveAnDuplicate( intTileIndexes, i );
          i++;
        } // for
      } // for
      //
      // if not even, make one tile inexistent
      i=0;
      for (int x=0; x<TILES_HORZ; x++) {
        for (int y=0; y<TILES_VERT; y++) {
          // if our tile doesn't have a duplicate yet
          if (!tiles[i].hasDuplicate) {
            // we don't show it
            tiles[i].exists=false;
          } // if
          i++;
        } // for
      } // for
      // 
      imgBack.copy(imgBackGlobal,
      0, 0, imgBackGlobal.width, imgBackGlobal.height,
      0, 0, tileWidth, 0);
    } // func
    //
    void makeItHaveAnDuplicate(  ArrayList <Integer> intTileIndexes, int i ) {
      // makeItHaveAnDuplicate
      // if our tile doesn't have a duplicate yet, then it's on our to do list:
      if (!tiles[i].hasDuplicate) {
        // we search a random partner
        int safetyCounter = 0; // that avoids that the loop takes too long...
        // now we calculate a random number which is a index for intTileIndexes
        int j2 = int(random (0, intTileIndexes.size()));
        int j  = intTileIndexes.get(j2);
        // remark: he can't find a partner when the tiles are e.g. 9 (uneven),
        // then we get an error here but that's ok
        while ( (i==j || tiles[j].hasDuplicate )  && 
          (safetyCounter<50) ) {
          j2 = int(random (0, intTileIndexes.size()));
          j  = intTileIndexes.get(j2);
          safetyCounter++;
        }
        // Did he found one?
        if ( (i!=j) && (!tiles[j].hasDuplicate) ) {
          // yes
          // remove those from the arraylist
          removeFromArrayList (intTileIndexes, i);
          removeFromArrayList (intTileIndexes, j);
          tiles[i].hasDuplicate=true;   // both tiles have a duplicate now
          tiles[j].hasDuplicate=true;
          tiles[i].theImageCode=imageCode;  // both tiles get the same imageCode
          tiles[j].theImageCode=imageCode;  // saying: you two are belonging together
          int myImageIndex=giveImageIndex(); // get a name
          tiles[i].loadImageIntoTile ( myImageIndex ); // same image
          tiles[j].loadImageIntoTile ( myImageIndex );
          //
          imageCode++;                    // increase the code since it must be unique
        }
        else {
          // println ("error 119");
        } // else
      } // if
    }
    //
    int giveImageIndex() {
      // gives a image file name (that is new)
      int randomNumberImage = int (random(0, howManyImages));
      int safetyCounter = 0;
      // while not a new image keep on searching
      while ( (allRandomNumberImage.indexOf ( "#"+ str ( randomNumberImage ) + "#" ) >  -1 ) &&
        (safetyCounter<30) ) {
        randomNumberImage = int (random(0, howManyImages));
        safetyCounter++;
      }
      // found a new one
      allRandomNumberImage = allRandomNumberImage + "#" +  str( randomNumberImage ) + "#" ;
      // return value
      // return str( randomNumberImage ) +".jpg";
      return randomNumberImage;
    } // func
    //
    void removeFromArrayList (ArrayList<Integer> myArrayList, int iToBeRemoved) {
      // removes one item iToBeRemoved.
      // With an array, we say balls.length. With an ArrayList,
      // we say balls.size(). The length of an ArrayList is dynamic.
      // Notice how we are looping through the ArrayList backwards.
      // This is because we are deleting elements from the list.
      for (int i = myArrayList.size()-1; i >= 0; i--) {
        int iFromArrayList = int ( myArrayList.get(i));
        if ( iFromArrayList==iToBeRemoved ) {
          myArrayList.remove(i);
          return;
        }
      } // for
    } // func
    //
    // Inputs -----------------------------------------------------------------
    //
    void mousePressed() {
      // switch state
      switch (state) {
      case stateGamePlay:
        if (openImages != 2) {
          // search  
          int x=-1;
          for (int x2=0; x2<TOTAL_TILES; x2++) {
            if (tiles[x2].mouseInside() && tiles[x2].exists
              && !tiles[x2].isSolved &&  !tiles[x2].isShown ) {
              x=x2;
              break;
            } // if
          } // for
          //
          // found?
          if (x>-1) {
            // when one image is open make sure that the 2nd is a different one
            if ( ((openImages == 1) && ( x != lastImage)) ||
              (openImages == 0) ) { 
              // yes?
              if (tiles[x].mouseInside()) {
                tiles[x].isShown=true;
                openImages++;
                if (openImages == 1) {
                  lastImage=x;
                }
                else
                {
                  currentImage=x;
                  timer=millis();
                } // else
              } // if
            } // if
          } // if
        } // if
        break;
      case stateGameOver:
        level=0;
    println("Blammo");
         //   initNewLevel();
      //  state = stateGamePlay;
         state = stateGameStartUp;
        timer=millis();
        break;
      default:
        // do nothing
        break;
      } // switch
      //
    } // func
    void keyPressed () {
      if (state==stateGameOver) {
        level=0;
        openImages = 0;    // counter for current move  
     lastImage = -1;    // which was the last tile? (1st tile opened)
    currentImage = -1; // which is the current tile / image? (2nd tile opened)
        state = stateGameStartUp;
        timer=millis();
      }
    }
    // -------------------------------------------------------
    // smaller tools
    //
    //
    void drawTiles() {
      // draw it
      for (int x=0; x<TOTAL_TILES; x++) {//println("X: "+x+"  TOTTILES: "+TOTAL_TILES);
        tiles[x].draw();
      }
      //
    }
    //
    void checkTwoShownTiles () {
      // after a move:
      // if two images are shown we have to check them
      if (openImages == 2) {
        // but only after a while
        if (timer + 1000 < millis()) {
          // two are shown (the user has made his move)
          openImages=0; // reset
          // check
          if ( tiles[currentImage].theImageCode == tiles[lastImage].theImageCode)
          {
            //  correct
            println ("Good");
            tiles[currentImage].isSolved=true;
            tiles[lastImage].isSolved=true;
            checkIfSolved();
          }
          else
          {
            // not correct: the are hidden again 
            tiles[currentImage].isShown=false;
            tiles[lastImage].isShown=false;
          }
        }
      }
    } // func
    //
    void checkIfSolved() {
      // check if this level is complete 
      int counter = 0;
      // Are all shown and solved?
      for (int x2=0; x2<TOTAL_TILES; x2++) {
        if (tiles[x2].isSolved) {
          counter ++;
        }
      }
      //
      if (counter==winningNumberOfTiles)
      {
        state=stateGameGoToNextLevelPhase1; // won this level -> stateGameGoToNextLevelPhase1
        println ("You won this level.");
        level++;
        timer=millis();
      }
    }
    //
    // ================================================================
    //Tile Class (one image card)
    class Tile
    {
      int imgIndex;   // the image index
      float px;     // position
      float py;
      // those three (4) could be unified to a var stateOfTile : nonExistent, withoutDuplicate, covered, shown, solved
      boolean isShown  = false;      // shown or covered?
      boolean isSolved = false;      // the duplicate is not only shown but correct and now permanently shown
      boolean exists   = true;       // does the tile exist at all?
      boolean hasDuplicate = false;  // while init not all images have a duplicate yet
      //
      int theImageCode = -1;         // the partners are identified with the same number (which is otherwise meaningless, except both have the same).
      //
      // constr
      Tile ( float px_, float py_ )
      {
        px=px_;
        py=py_;
      } // constr
      //
      void loadImageIntoTile ( int imageName_ ) {
        imgIndex  = imageName_;
      } // method
      //
      void draw()
      {
        // if it exists at all?
        if (exists) {
          // we show it.
          // uncovered or covered?
          if (isShown) {
            // open
            if (images[imgIndex]!=null){
              image(images[imgIndex], px, py,tileWidth,tileHeight);}
            else
              println ("images[imgIndex] is null");
            stroke(255);
            noFill();
            rect(px, py, tileWidth, tileHeight);
            // if tile is solved correctly
            if (isSolved)
            {
              // we show the OK sign
              textSize(34);
              fill(255);
              strokeWeight(4);
              stroke(0);
              rect(px+tileWidth-170, py+tileHeight-58, 160, 40);
              fill(2, 2, 255);
              text( "MATCH!", px+tileWidth-150, py+tileHeight-27 );
              fill(255);
            }
          }
          else
          {println("Tiles not shown");
            // not shown / covered tile with a "?" or imgBack
            image(imgBack, px, py,tileWidth,tileHeight);
            textSize(54);
            stroke(255);
            noFill();
            //fill(0);
            rect(px, py, tileWidth, tileHeight);
  10.       } // else
        } //  if (exists) {
      } // method
      //
      boolean mouseInside()
      {
        return ((px <= mouseX && mouseX <= px + tileWidth) &&
          (py <= mouseY && mouseY <= py + tileHeight));
      } // method
      //
    } // class