Sunday, 6 March 2011

_12_MoreArraysAndLoops

//Integer variables
int batX = 240;
int batY = 700;

int ballX = 240;
int ballY = 400;

int ballXspeed = 5;
int ballYspeed = -5;

int SCORE = 0;

//Constants
final int blockPoints = 10;

final int ballSize = 10;
final int screenWidth = 480;
final int screenHeight = 800;

final int batSize = 50;
final int batHeight = 25;

final int blocksPerRow = 10;
final int numRows = 4;
final int blockWidth = screenWidth / blocksPerRow;
final int blockHeight = 20;
final int firstRowYPos = 50;

//Boolean 'flags'
boolean gamePlaying = true;
boolean winner = false;

//More Arrays:

//Arrays don't have to be 'one dimensional'.  You can set them
//up to use two or more index numbers to access the values they
//contain.  For example if you want a grid of numbers 3 columns
//wide and 4 rows deep, you can set that up like this:
//
//  int [ ] [ ] theGrid = new int[ 3 ][ 4 ];
//
//The variable 'theGrid' acts a bit like a spreadsheet or a table
//in a word processor: you can access each row with the first index,
//and each number in that row with the second index.  So the bottom,
//right hand corner of the grid would be:
//
//  int bR = theGrid[ 2 ][ 3 ];
//
//( Remember array indexes start counting from zero ).  An array
//organized into 'columns' and 'rows' has two indexes and is called
//a 'two dimensional' array.
//
//To work through every value in a two dimensional array, you need to
//write _two_ loops, one *inside* the other.  When loops are put inside
//other loops, they are called 'nested' loops
int [ ] [ ] theBlocks = new int[ numRows ] [ blocksPerRow ];
//   ^   ^
//   |   |
//   R   B
//   o   l
//   w   o
//       c
//   N   k
//   u  
//   m   N
//   b   u
//   e   m
//   r   b
//       e
//       r


//===================================
void setup() {
  size( screenWidth, screenHeight );
  background( 0 );
  noCursor();
 
  setupBlockRows();
}

//
//The draw function is nice and simple
//====================================
void draw() {
  background( 0 );
 
  if( gamePlaying && !winner ) {
    drawScore();
    drawBlocks();
    moveTheBat();
    moveTheBall();
    winner = checkBlocksGone();
  }
  if( !gamePlaying ) {
    gameOver();
  }
  if( winner ) {
    gameWon();
  }
}

//This time the setupBlockRows() function
//uses 'nested' loops to count through each
//row, and then every column in that row.
//Traditionally, loop counters are often called
//'i', 'j' or 'k' especially when you have
//nested loops.
//==================================//
void setupBlockRows() {
//    |   ONE   |     TWO    | THREE |
  for( int i = 0; i < numRows;  i++  ) {  // <-------- N
                                               //      e
    for( int j = 0; j < blocksPerRow; j++ ) {  //      s
      theBlocks[ i ][ j ] = 1;                 //      t
    }                                          //      e
  }  // <--------------------------------------------- d
}

//This function has been changed to use
//the two dimensional arrays to to draw the blocks.
//
//One very important thing to notice: the drawOneRow()
//function hasn't changed; it still expects one int and
//one int array as its inputs.  Even though we are using
//a two dimensional array with rows and columns, we can
//still send it just one row of the array by only putting
//one index after the variable name.
//==================================//
void drawBlocks() {
  int rowPosition = firstRowYPos;
 
  fill( 200 );
 
  for( int i = 0; i < numRows; i++ ) {
    drawOneRow( rowPosition, theBlocks[ i ] ); // <- send just one row of the array
    rowPosition = rowPosition + blockHeight;
  }
}

//void drawOneRow( int, int[] )
//
//===================================//
void drawOneRow( int rowLevel, int[] someRow ) {
  int counter;
 
  for( counter = 0; counter < someRow.length; counter++ ) {
    if( someRow[counter] == 1 ) {
      rect( blockWidth * counter + 1, rowLevel + 1, blockWidth - 2, blockHeight - 2 );
    }
  }
}


//====================================
void moveTheBat() {
  fill( 255 );
 
  batX = mouseX;
 
  //if the bat 'hits' the left edge move it back
  if( batX < batSize ) {
    batX = batSize;
  }
 
  //if the bat 'hits' the right edge move it
  if( batX > screenWidth - batSize ) {
    batX = screenWidth - batSize;
  }
 
  rect( batX - batSize, batY, batSize * 2, batHeight );
}


//=======================================
void moveTheBall() {
  ballX = ballX + ballXspeed;
  ballY = ballY + ballYspeed;
 
  if( ballX < ballSize ) {
    ballX = ballSize;
    ballXspeed = ballXspeed * -1;
  }
 
  if( ballX > screenWidth - ballSize ) {
    ballX = screenWidth - ballSize;
    ballXspeed = ballXspeed * -1;
  }
 
  if( ballY < ballSize ) {
    ballY = ballSize;
    ballYspeed = ballYspeed * -1;
  }
 
  if( ballHitBat() ) {
    ballYspeed = ballYspeed * -1;
  }
 
  if( ballY > screenHeight ) {
    gamePlaying = false;
  }
 
  for( int i = 0; i < numRows; i++ ) {
    checkBallHitRow( theBlocks[ i ], i );
  }
 
  rect( ballX - ballSize, ballY - ballSize, ballSize * 2, ballSize * 2 );
}

//boolean checkBallHitRow(int[], int)
//
//This function works out the position of each block in
//a row, then works out if the ball is inside the block.
//If it is, the function sets the value for the block to zero in
//the array for that row.  Later on when the rows are
//drawn, the blocks which have value zero in the array
//don't get drawn so it looks like the ball has destroyed
//them.
//
//NEW: the if tests in this function check TWO things
//at once.  The first 'if' looks like this:
//
//  if( ballX > blockLeft && ballX < blockRight )
//
//In plain English it says:
//"If the value of'ballX' is greater than 'blockLeft',
//AND the value of 'ballX' is less than blockRight, then
//run the next bit of code"
//
//The two tests are being combined into one more complex
//test by the '&&' symbol.  && stands for AND.  The combined
//test is only true if BOTH the first and second test are
//true.  There are other ways of combining tests:
//
//  ||    Means OR, it is true if the first OR second test is true
//  !     (Exclamation point) means NOT - it reverses the meaning
//        of a test 'true' becomes 'false' and 'false' becomes 'true'
//
//Tests can be grouped together by putting them between parenthesis ()
//
//=================================//
boolean checkBallHitRow( int[] someRow, int rownumber ) {
  int blockLeft;
  int blockRight;
  int blockTop;
  int blockBottom;
  boolean hit = false;
 
  for( int whichblock = 0; whichblock < 10; whichblock++ ) {
    blockLeft   =          0 + blockWidth * whichblock;
    blockRight  = blockWidth + blockWidth * whichblock;
   
    blockTop    =  firstRowYPos                + blockHeight * rownumber;
    blockBottom = (firstRowYPos + blockHeight) + blockHeight * rownumber;
   
    if( ballX > blockLeft && ballX < blockRight ) {
      if( ballY > blockTop && ballY < blockBottom ) {
        if( someRow[whichblock] == 1 ) {
          someRow[whichblock] = 0;
          SCORE += blockPoints;
          hit = true;
        }
      }
    }
  }
 
  return hit;
}
//=======================================//
boolean checkBlocksGone() {
  int totalblocks = 0;
 
  for( int i = 0; i < numRows; i++ ) {
    for( int j = 0; j < blocksPerRow; j++ ) {
      totalblocks += theBlocks[ i ][ j ];
    }
  }
 
  return (totalblocks == 0);
}

//=====================================//
void drawScore() {
  fill( 255 );
  text( "Score: " + SCORE, 10, 10 );
}

//======================================//
void gameOver() {
  fill( 255 );
  text("Game Over", 200, 400);
}

//======================================//
void gameWon() {
  fill( 255 );
  text("WINNER!", 200, 400);
}
 
//======================================//
boolean ballHitBat() {
  if( ballY + ballSize >= batY ) {
    if( ballY + ballSize <= batY + ballSize * 2 ) {
      if( ballX > batX - batSize ) {
        if( ballX < batX + batSize ) {
          //the ball has hit the bat so return the answer is 'true'
          return true;
        }
      }
    }
  }
  //if we get this far then the ball hasn't hit, return the answer 'false'
  return false;
}

//mousePressed()
//
//This is another one of Processing's built in functions
//When the mouse button is pressed, Processing automatically
//calls this function so your program can react.
void mousePressed() {
  if( !gamePlaying || winner ) {
    SCORE = 0;
    gamePlaying = true;
    winner = false;
    setupBlockRows();
   
    ballX = 240;
    ballY = 400;
  }
}

No comments:

Post a Comment

Note: only a member of this blog may post a comment.