Sunday, 20 March 2011

Create a Glowing Neon Effect

Here's another quick guide to making glow effects for game assets.  In this tutorial, you'll learn:

  • How to work with 'Paths' which are used to make shapes
  • What 'Layer Effects' are and how to use them
  •  Using Blending Modes to control how layers are mixed

Make a new document, 128 by 128 pixels, fill the background with black then create an empty layer.  Select the Ellipse Tool:


Drag out an ellipse in the middle of the image.  Hold the SHIFT key to make it a perfect circle.

Next, click on the Path Selection Tool


and click on the outline of the circle you've just made.  Press CMD-C to copy the outline, then CMD-V to paste a new copy straight over the first one.  Next press CMD-T to enable the Free Transform Tool.  A transform box will appear around the new copy of the outline.  Click the corner 'handle' of the transform box.  Hold down the SHIFT key to keep the outline circular and the ALT key to transform around the centre of the shape rather than the corner.


Make the inner circle about 50% smaller than the outer one.  Finally, press ENTER to finish the transform and lock the circle in place.  Then go to the Path Tool controls at the top of the window and click the 'Subtract from Shape' button.


You should end up with a hole cut out of the white circle:


Next we're going to add a red tint to the edges of the ring.  First, make a copy of the layer so we have a back up by dragging it to the 'New Layer' icon at the bottom of the Layers panel.  Make a second copy.  We will be using it later.

Rename your layers, 'Bulb', 'Glow' and 'Ring' from top to bottom then double click on the 'Bulb' layer to open the Layer Effects window:
Click on the 'Inner Glow' option from the list and make sure the box is ticked, then select the gradient option, change the gradient start colour to a light shade of red and the Blend Mode to 'Normal'.  Set the size to around 8.

You should have a white ring with a red glow to the edges.  Next select the 'Glow' layer.  Double click in the white colour swatch in the layer to open the fill colour window and set the colour to a bright red.


There is now a red ring hidden behind the white ring.  Next we're going to blur out the red ring to create the Neon glow around the bulb.  You won't be able to put a blur directly on the layer yet.  If you do, you will get an error message.


Because the ring is created using Paths, it doesn't contain actual pixels, just shaped outlines which define where the pixels will go.  To create actual pixels that can be blurred you will have to 'Rasterize' it, right click on the layer and select Rasterize Layer.


Now go up tot the Effects menu and select Blur -> Gaussian Blur and set the Radius to give a nice red glow effect that isn't too small or too transparent.  A value of around 10 should work.


For the final touches, make the black background visible.  If the glow is too weak, you can add to it just by duplicating the Glow layer.  Click on that layer and drag it down to the New Layer icon at the bottom of the Layers panel.  Because the glow is transparent, the new copy will combine with the original glow to increase the brightness.  Making a third copy will make the effect even stronger, or you could add another Gaussian Blur to spread the glow even more.


Finally you should end up with a Neon effect like this:

Quick Tip #1 -- Duplicating a Layer

The quickest way to duplicate a layer in Photoshop is to select it then drag it over the 'New Layer' button at the bottom of the Layers panel.  A new layer called 'Layer name copy' will be made just above the layer you dragged:



How To Make a Plasma Bolt

In this quick exercise, we're going to make a glowing bolt of plasma for an
in-game weapon.  You'll learn about how to set up and use Gradients.



First create a new Photoshop document 128 by 128 pixels.







Next, change the background colour to black.  Go to Edit -> Fill



Add an empty layer then select the Gradient Fill tool:


Then zoom into the image by pressing CMD +
Click in the gradient preview at the top of the document window


to open the gradient settings panel.



The gradient is controlled by two sets of markers above and below called 'stops'.  The bottom pair of stops controls the colour change along the gradient.  Sliding the stops closer together makes the colours change more quickly.  The dot between the stops is the 'midpoint'.  You can move it closer to the left or right stop to have more control over how fast the colour changes. 

Putting it closer to the right will make the gradient stay black for longer before changing to white:


Clicking between the stops adds another one and double clicking on the coloured square part of the stop opens the colour selection window.  The pair of stops above the gradient control the transparency and work exactly like the colour stops.

To make the plasma bolt we need a gradient that goes from white to light blue:


and goes from 100% solid to completely transparent:


Then push the white colour stop and the left transparency stop past the middle of the gradient so the plasma ball itself is solid white:


To bring out the edge of the ball of plasma, it helps to add in a contrasting colour.  Click to the right of the white colour stop and set the colour to a darker, purplish blue.  Finally add one more stop to the right with a bluer colour


Click OK and make sure the radial gradient option is selected in the gradient tool controls:



Finally, click in the exact centre of the image and draw a gradient out to near the edge

Wednesday, 9 March 2011

_13_Object

//Objects
//
//So far we have been using simple variables of
//either type 'int' or type 'boolean'.  These are
//called primative types because they are just raw
//data and can only store one value -- they don't
//have any other properties apart from the value
//you set them to.  Most of the time it is more useful
//to use more complex data types which have more than
//one value in them.
//
//For example, if you need to store today's date in your
//programme, you would probably make some int variables
//like this:
//
//  int day = 9;
//  int month = 3;
//  int year = 2011;
//
//This is fine if you are just handling one date but it
//gets really awkward if you need to store lots of dates,
//say for a calender programme.  Another problem is that
//the seperate variables aren't connected in any way even
//though they all belong to the same date.  A better way
//to store the numbers is to wrap them up into a new data
//type by writing a 'class':
//
//  class Date {
//    int day;
//    int month;
//    int year;
//  }
//
//When these three variable declarations are wrapped into
//a class they become a new 'complex' type.  Now we can
//make a variable which has 'Date' as its type:
//
//  Date myBirthday = new Date();
//
//The variable 'myBirthday' has three integers inside it
//with the names we gave them in the Date class.
//You can get at the individual variables like this:
//
//  myBirthday.day = 13;
//
//You write the name of the Date variable followed by a dot
//followed by the name of integer you want to access.
//Using classes is a lot neater than having lots of integer
//variables in your code.
//
//A class can have any kind of variable inside it that you
//want.

//Integer variables
int SCORE = 0;

//Constants
final int blockPoints = 10;

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

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;


int [ ] [ ] theBlocks = new int[ numRows ] [ blocksPerRow ];


class Ball {
  final int Size = 10;
 
  int X = 240;
  int Y = 400;

  int Xspeed = 5;
  int Yspeed = -5;
}


class Bat {
  final int Size = 50;
  final int Height = 25;

  int X = 240;
  int Y = 700;
}


Ball ball = new Ball();
Bat bat = new Bat();

//===================================
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++  ) { 
                                              
    for( int j = 0; j < blocksPerRow; j++ ) { 
      theBlocks[ i ][ j ] = 1;                
    }                                         
  } 
}

//==================================//
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 );
 
  bat.X = mouseX;
 
  //if the bat 'hits' the left edge move it back
  if( bat.X < bat.Size ) {
    bat.X = bat.Size;
  }
 
  //if the bat 'hits' the right edge move it
  if( bat.X > screenWidth - bat.Size ) {
    bat.X = screenWidth - bat.Size;
  }
 
  rect( bat.X - bat.Size, bat.Y, bat.Size * 2, bat.Height );
}


//=======================================
void moveTheBall() {
  ball.X = ball.X + ball.Xspeed;
  ball.Y = ball.Y + ball.Yspeed;
 
  if( ball.X < ball.Size ) {
    ball.X = ball.Size;
    ball.Xspeed = ball.Xspeed * -1;
  }
 
  if( ball.X > screenWidth - ball.Size ) {
    ball.X = screenWidth - ball.Size;
    ball.Xspeed = ball.Xspeed * -1;
  }
 
  if( ball.Y < ball.Size ) {
    ball.Y = ball.Size;
    ball.Yspeed = ball.Yspeed * -1;
  }
 
  if( ballHitBat() ) {
    ball.Yspeed = ball.Yspeed * -1;
  }
 
  if( ball.Y > screenHeight ) {
    gamePlaying = false;
  }
 
  for( int i = 0; i < numRows; i++ ) {
    checkBallHitRow( theBlocks[ i ], i );
  }
 
  rect( ball.X - ball.Size, ball.Y - ball.Size, ball.Size * 2, ball.Size * 2 );
}



//=================================//
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( ball.X > blockLeft && ball.X < blockRight ) {
      if( ball.Y > blockTop && ball.Y < 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( ball.Y + ball.Size >= bat.Y ) {
    if( ball.Y + ball.Size <= bat.Y + ball.Size * 2 ) {
      if( ball.X > bat.X - bat.Size ) {
        if( ball.X < bat.X + bat.Size ) {
          //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();
   
    ball.X = 240;
    ball.Y = 400;
  }
}


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;
  }
}

Friday, 4 March 2011

_11_Arrays

int batX = 240;
int batY = 700;

int ballX = 240;
int ballY = 400;

int ballXspeed = 5;
int ballYspeed = -5;

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

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

//
boolean gamePlaying = true;
boolean winner = false;

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

//Arrays:
//An array is like a list of data.  It could
//be a list of numbers, words, images, sounds
//or any other kind of data you can think of.
//
//There are a few important things to know
//about arrays.
//
//First, you define an array variable like an
//ordinary variable except the variable type
//is a bit different (see sketch 04 for more
//on variable types).  The type of an array
//has square brackets [] straight after the
//type of data the array should store.  To
//have a list of words, you need to store text
//data.  The type that represents text is 'String'
//so a list of words can be stored as an array of
//Strings.  To define a variable call 'theWordList'
//as an array of Strings you would write:
//
//  String[] theWordList;
//
//It looks just like a simple String variable but
//it has sqaure brackets added to the data type.
//
//The next thing to learn about arrays is that they
//are a fixed length -- once you set the size of the
//array, you can't add extra items to the list.  You
//can set the size of the array at the same time that
//you define its name like this:
//
//  String[] theWordList = new String[10];
//
//the command 'new' tells Processing to 'allocate' (which
//just means reserve) some memory to store the array.
//Next the type of data is repeated and followed by the
//length of the array in brackets.  So this line of code
//'declares' an array of Strings called 'theWordList' which
//has 10 items in it.  At the moment their aren't any
//Strings in the array -- it just has 10 empty slots where
//we can put text data.  Using an array is much easier than
//creating 10 String variables with different names.
//
//The most important thing to remember about arrays is how
//you get and set the values in it.  Once you have made a
//new array, you can get to each of the slots in it by putting
//the slot number in the brackets after the name.  So to set
//slot 3 in the array to the word "ninja" you would write:
//
//  theWordList[3] = "ninja";
//
//To print out the value in slot 6 with the println() function
//you could write:
//
//  String theValue = theWordList[6];
//  println( theValue );
//
//The one unexpected thing about slot numbers is that they
//start at ZERO.  So the _first_ slot in the array is:
//
//  theWordList[0]
//
//and, counting ten slots starting with ZERO makes the _last_ slot:
//
//  theWordList[9]
//
//There are still 10 slots its just the numbering which is
//a bit confusing.  If you try to get or set a slot which is
//outside the length of the array, you will get an error called
//an 'ArrayIndexOutOfBoundsException' and the program will stop
//so this line would crash the program:
//
//  theWordList[16] = "crash";  // <- no slot 16!
//
//You can always find out the size of an array by getting its
//'length' property:
//
//  int myArraySize = theWordList.length;
//  println("There are " + myArraySize + " slots in the array");
//
int[] rowA = new int[10];
int[] rowB = new int[10];
int[] rowC = new int[10];
int[] rowD = new int[10];

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

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

//This function sets up the arrays of ints which
//represent the rows of blocks.  It is just a loop
//which sets each slot in each array to the the
//number one.
//
//There are a couple of new ideas in this loop.
//First, the counter variable for the loop is
//called 'i'.  Also we can define the variable
//in part ONE of the for statement (see example
//_10_Loops).  In part THREE there is the expression:
//
//  i++
//
//which is a short hand way of writing:
//
//  i = i + 1
//
//==================================//
void setupBlockRows() {
//    |   ONE   |  TWO  | THREE |
  for( int i = 0; i < 10;  i++  ) {
    rowA[i] = 1;
    rowB[i] = 1;
    rowC[i] = 1;
    rowD[i] = 1;
  }
}

//This function has been changed to use
//the int arrays to to draw the blocks.
//==================================//
void drawBlocks() {
  int rowPosition = firstRowYPos;
 
  fill( 200 );
 
  drawOneRow( rowPosition, rowA );
  rowPosition = rowPosition + blockHeight;
 
  drawOneRow( rowPosition, rowB );
  rowPosition = rowPosition + blockHeight;
 
  drawOneRow( rowPosition, rowC );
  rowPosition = rowPosition + blockHeight;
 
  drawOneRow( rowPosition, rowD );
  rowPosition = rowPosition + blockHeight;
}

//void drawOneRow( int, int[] )
//
//Now this function takes two inputs, the
//position of the row in pixels, like before,
//(int rowLevel) and the int array representing
//the blocks.  This time, the loop counts upto
//the number of slots in each array.  Then it
//checks if the value in the slot equals the
//number one.  IMPORTANT: look at the 'if'
//statement.  It gets the value of a slot in
//the array with this code:
//
//  someRow[counter]
//
//as the loop repeats, counter goes up by one
//each time (see the function setupBlockRows() for
//more), then it tests if the value it got out
//of the array equals 1 like this:
//
//  slotRow[counter] == 1
//
//notice that there are TWO equals characters
//back to back here.  This is a special symbol
//which *compairs* two numbers.  One equals
//character on its own would *set* the value
//of the slot in the array to the number one
//NOT compair it to one.
//===================================//
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;
  }
 
  checkBallHitRow( rowA, 0 );
  checkBallHitRow( rowB, 1 );
  checkBallHitRow( rowC, 2 );
  checkBallHitRow( rowD, 3 );
 
  winner = checkBlocksGone();
 
  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 ) {
        someRow[whichblock] = 0;
        hit = true;
      }
    }
  }
 
  return hit;
}
//=======================================//
boolean checkBlocksGone() {
  int totalblocks = 0;
 
  for( int i = 0; i<rowA.length; i++ ) {
    totalblocks += (rowA[i] + rowB[i] + rowC[i] + rowD[i]);
  }
 
  return (totalblocks == 0);
}

//======================================//
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;
}

_10_Loops

int batX = 240;
int batY = 700;

int ballX = 240;
int ballY = 400;

int ballXspeed = 5;
int ballYspeed = -5;

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

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

//
boolean gamePlaying = true;

//
final int blocksPerRow = 10;
final int blockWidth = screenWidth / blocksPerRow;
final int blockHeight = 20;

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

//
//The draw() function is nice and simple
//====================================
void draw() {
  background( 0 );
 
  if( gamePlaying ) {
    drawBlocks();
    moveTheBat();
    moveTheBall();
  } else {
    gameOver();
  }
}

//void drawBlocks()
//
//This function introduces a few new programming
//ideas.  The first one is quite simple.  You can
//have variables _inside_ a function; called 'local'
//variables, these values are 'trapped' inside the
//function and can't be used anywhere outside it, so
//the names 'counter' and 'rowPosition' only exist
//in the drawBlocks() function.  You can store any
//number you like in them but when the function ends,
//they are forgotten.
//
//The second idea is the 'for' loop.  In programming,
//you almost always have to do something over and over
//again.  They way you can repeat a piece of code is to
//put it inside a loop.
//
//A loop is just a block of code plus a counter variable.
//The block of code runs over and over until the counter
//reaches a certain value.
//
//The 'for' loop has four separate parts:
//
//  for( ONE; TWO; THREE ) {
//    FOUR;
//  }
//
//ONE: this is the bit that sets the _starting_ value for
//the counter.
//TWO: this is the bit that checks if the counter has reached
//the final value (it is a lot like the code in an 'if' test
//THREE: this bit makes the counter count up (or down).
//FOUR: this is the block of code which gets repeated however
//many times the loop goes round.
//==================================//
void drawBlocks() {
  int counter;
  int rowPosition = 50;
 
  fill( 200 );
 
  // The parts of a for loop:
  //   |   ONE    |     TWO    |       THREE          |  //
  for( counter = 0; counter < 4; counter = counter + 1 ) {
    // FOUR
    drawOneRow( rowPosition );
    rowPosition = rowPosition + blockHeight;
  }
}

//===================================//
void drawOneRow( int rowLevel ) {
  int counter;
 
  for( counter = 0; counter < blocksPerRow; counter = 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;
  }
 
  rect( ballX - ballSize, ballY - ballSize, ballSize * 2, ballSize * 2 );
}

//======================================
void gameOver() {
  fill( 255 );
  text("Game Over", 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;
}