Tuesday 8 December 2009

New Late Entry Chunk 81

CHUNK 81
TITLE Object orientation and images
DESCRIPTION In this part of the book show how you can develop a class based Processing program that manipulates images. This would be valuable revision on OO concepts.
OUTCOME

* Be able to develop an OO-based program of no more than 120 lines which manipulates images.

REFERENCE Greenberg 468--479
HINT It would do no harm to make the program the same level of complexity as that in the Greenberg extract
PROGRAM A similar program to that found in the text,

Wednesday 6 May 2009

Chunk 26 Event Handling

Event Handling

Events are an important part of any programming language. For our programs to be interactive we need to manage a user’s actions and do something in response.

Interactive programs allow the user to feel part of the application by giving them some way of manipulating their environment and making the experience unique to themselves.

Events can be broken own into two simple categories. (There are many more but for the purposes of this exploration lets ignore the others)

These categories are user interface events such as key presses or mouse clicks and program events such as a certain condition in the code that is met and so a programmatic event occurs.

User Interface Events

User interface events are the events that take place in the interface between user and computer. So for Processing we can break this down into two types and these are:

Key presses
Key presses capture anything that is typed on the keyboard. An example that this could be useful for would be a game that requires a spacebar to shoot bullets and arrow keys to move about on the screen.

We may just want to give a user greater flexibility when it comes to using our program so by giving them the chance to use a mouse or the keyboard to achieve simple tasks. This gives the user greater choice and makes our program easier to use and opens it up to a wider audience because some people prefer to use keys whilst others favour the mouse.

Keyboard Event Control

System Variables

keyPressed
This is a boolean system variable that is true if a key is pressed and false if not. This is used in conjunction with the variables key and keyCode below.

key
This variable will always contain the value of the most recent key that pressed or released. This will be in the form of an ASCII value.

keyCode
This is a useful variable since it can be used to check a key is pressed or released just like the key variable however this variables stores the key in a code so you can accessed whether the user has pressed ENTER, DELETE, LEFT RIGHT UP DOWN etc. By using this variable for keys the code can be easier to read and understand.

An example of this being used in conjunction with the keyPressed() method discussed below would be something like this:

void keyPressed()
{
if (keyCode == RIGHT)
{
// Code to Move the spaceship to the right
}
}


Methods

keyPressed()
This method is called when a key is pressed on the keyboard. As you have seen in the example above, it is used with keyCode or key to determine which key was pressed and allow the programmer to determine what action (if any) should be carried out.

Here is an example of using this method to see if the F8 key is pressed

void keyPressed()
{
if (keyCode == 119) // F8 for Drift
{
if (bulletDrift)
{
bulletDrift = false;
driftAmount = 0;
}
else bulletDrift = true;
}

In the above code the F8 key is used to toggle the Boolean variable bulletDrift and turn the driftAmount variable to 0 if the bulletDrift variable is set to false.

keyReleased()
This method is called when a key is released. Again you can use the variables keyCode and key to determine which key is released do something if it is required.


Mouse events.
Most mice I mean computer mouse devices have a left and a right click button and some have a wheel for scrolling up and down. These wheels can also be clicked. To make things a bit more complicated still is the fact that a mouse button can be clicked and held, released and it could even be dragged whilst any of the above button are held down.
So just but thinking about a simple mouse we may have to capture 11 different events by my calculations and these are:

Left mouse button clicked or released the same with the right mouse button and the scroll. (6)
Scrolling wheel moved up and down (2)
And any of the above buttons may be used whilst the user is dragging the mouse around the screen. (3)

You may think of more but you get the idea.

For most programs you may start with a few simple events and slowly add to these over time.

The fact the Processing used Java is fantastic since an object orientated approach is easily extended if you take care to follow a component based approach.


Now we examine the methods and variables we will need to manage mouse events


Mouse Event Control

System Variables

mouseButton
This is an object that you will be able to use when the mouse is clicked to see what button has been clicked
This could be equals to LEFT RIGHT or CENTER

mouseX
This is the mouse position x axis

mouseY
This is mouse position on the Y-axis

pmouseX
This is the previous mouse position so it will be slightly behind mouseX but close.

pmouseY
This is the previous mouse position so it will be slightly behind mouseY but close.


Methods

mouseDragged()
This method is to measure and handle when the mouse button is clicked and dragged across the screen this would be used with in conjunction with mouseButton mouseX mouseY pmouseX and pmouseY and mousePressed and mouseReleased.
This method is called constantly while you drag the mouse. And the position on the mouse on the x and y coordinates will be pmouseX and pmouseY respectively.

mouseMoved()
This is a methos that is called when the mouse pointer moves around in the screen. Again this method would be used in conjunction with the objects pmouseX pmouseY mouseX and mousey

mousePressed()
This method is called when a mouse button is pressed and we can see which button it is by using the mouseButton object I mentioned above.

mousePressed
This object returns a boolean value true is the mouse is pressed otherwise it returns false.

mouseReleased()
This method is called when the mouse button has been pressed and released. You can see whaqt button this is and deal with the event accordingly by using the mouseButton object as above.



Programmatic Events

These sorts of events are everywhere in programs. Here is a simple example of a programmatic event. Again using the idea of a shooting type game:


if (GAMESTATE.equals(OVER))
{
textFont(fontB, 25);
fill(255, 255, 0);
stroke(0);
text("GAME OVER", 190, 100);

if (runningTextX < 250) runningTextX = runningTextX + 10;
if (runningTextY < 150) runningTextY = runningTextY + 10;

if(enemyHits > shipHits) text("YOU WIN", runningTextX, runningTextY);
else if (enemyHits == shipHits) text("DRAW", runningTextX, runningTextY);
else text("YOU LOSE", runningTextX, runningTextY);

textFont(fontA, 15);
}


In this code the program checks to see the variable GAMESTATE and if this variable is set to the constant variable OVER then the program responds to this by displaying the text “GAME OVER” and moving the text “YOU LOSE” or “YOU WIN” to the position X = 250 and Y = 150



Putting it all together.

So we have discussed the tools at our disposal in the Processing environment and looked at a few examples of code snippets. Now it’s time to use some of those tools to create a meaningful program that covers these points.

I have created a basic “Shape Invaders” Application where the user gets to fight against a random moving enemy. The programming is basic and should give you an idea of how to use events to achieve what you like.

I have divided the screen into three sections. A Button, score and info section on the left an Enemy section at the top of the screen and a place for our Spaceship in the bottom half of the screen.

The program allows the user to use play in either keyboard or mouse mode and the buttons can be selected by mouse or the user can use the keyboard to make their selection.

Then depending on the mode of play the user can use either the keyboard or the mouse to navigate around in the Ship section or the page and shoot bullets at the Enemy Ship.

The ship design is basic and I’m sure you will have a better idea for its design, perhaps by using an external image or some other tips you may have picked up in this book.



Some key Events that these programs concerns are:
• The mouse is moved over any of the buttons
• The mouse is clicked whilst over the buttons
• The user presses any of the function keys that relate to the buttons
• The user clicks the mouse in game mode within the bounds of the ship
• The presses the arrow keys to move around in the game or presses the keyboard to fire a bullet
• The Enemy ship is hit by our Ship bullet
• Our ship is hit by the Enemy bullet
• Our score or the enemy score reaches 50
• We run out of bullets – So we force an end to the game


By adjusting the way these events are processed we effectively change the game.

Note:
This game doesn’t take account of different PC speeds so you may need to adjust the frame rate to slow the game down or speed it up.
If you have a faster pc it may be better to change the units of movement for the bullets and the Ships to make movement smoother. This can be done by adjusting the units from 10 to a smaller number.



The Program.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/**
*
*
*/
// Constants
public static final String MOUSEMODE = "MOUSEMODE";
public static final String KEYMODE = "KEYMODE";
public static final String STARTED = "STARTED";
public static final String HELP = "HELP";
public static final String OVER = "OVER";
public static final String ENEMYBULLET = "ENEMYBULLET";
public static final String SHIPBULLET = "SHIPBULLET";
public static final String WEAKR = " > ";
public static final String MIDR = " >>";
public static final String STRONGR = ">>>";
public static final String WEAKL = " < ";
public static final String MIDL = "<< ";
public static final String STRONGL = "<<<";
public static final String NODRIFT = " ";

// Class Varibles or Global variables in this context
String GAMESTATE = "NOACTION";
String driftIndicator = NODRIFT;
float x, y = 300;
float trueX, trueY, trueSX, trueSY;
boolean shipHit, enemyHit = false;
float enemyX, enemyY, shipX, shipY;
float shipPosX, shipPosY = 400;
int circleSize = 53;
int buttonX, startButtonY, helpButtonY, windButtonY, driftIndicatorY;
boolean overStartButton, overHelpButton, overWindButton, bulletDrift = false;
color circleColor, baseColor, circleHighlight, currentColor;
PFont fontA, fontB;
int runningTextX, runningTextY, enemyHits, shipHits, numBullets, driftAmount = 0;
Bullet[] bullets;
Enemy enemy;
Ship ship;

void setup()
{
// Set the font
fontA = loadFont("Arial-Black-25.vlw");
fontB = loadFont("Arial-Black-40.vlw");
textFont(fontA, 15);

size(800, 600);
smooth();
frameRate(70);
circleColor = color(0,192,0);
circleHighlight = color(255,0,0);
baseColor = color(255,0,0);
currentColor = baseColor;
buttonX = 50;
startButtonY = 300;
helpButtonY = 400;
windButtonY = 200;
driftIndicatorY = 140;
startDemo("Demo");
}

void startGame(String mode)
{
bullets = new Bullet[2000];
numBullets = 0;
enemyHits = 0;
shipHits = 0;
runningTextX = 0;
runningTextY = 0;
GAMESTATE = "STARTED";
enemy = new Enemy(false);
ship = new Ship(mode);
}

void startDemo(String mode)
{
bullets = new Bullet[2000];
numBullets = 0;
enemy = new Enemy(false);
}

void manageDrift()
{
int randomDrift = 0;
randomDrift = (int) (Math.random() * 100 + 1);
if (randomDrift >= 7) return;
else
{
switch (randomDrift)
{
case 1: driftAmount = 2; driftIndicator = WEAKR; break;
case 2: driftAmount = 6; driftIndicator = MIDR; break;
case 3: driftAmount = 10; driftIndicator = STRONGR; break;
case 4: driftAmount = -2; driftIndicator = WEAKL; break;
case 5: driftAmount = -6; driftIndicator = MIDL; break;
case 6: driftAmount = -10; driftIndicator = STRONGL; break;
}
}
}
void draw()
{
if (bulletDrift) manageDrift();
// current mouse position for buttons
updatePosition(mouseX, mouseY);
background(0);
stroke(255);
if(overWindButton) fill(circleHighlight);
else fill(circleColor);
if(bulletDrift)
{
ellipse( buttonX, windButtonY, circleSize, circleSize);
fill(0);
text("No", buttonX - 10, windButtonY - 10);
text("Drift", buttonX - 17, windButtonY + 4);
text("F8", buttonX - 10, windButtonY + 19);
textFont(fontB, 30);
fill(255);
stroke(255, 0,0);
text(driftIndicator, buttonX -30, driftIndicatorY);
stroke(255);
textFont(fontA, 15);
text("BulletDrift", buttonX -40, driftIndicatorY - 30);
fill(0);
}
else
{
ellipse( buttonX, windButtonY, circleSize, circleSize);
fill(0);
text("Drift", buttonX - 17, windButtonY + 1);
text("F8", buttonX - 10, windButtonY + 19);
}
// Start Button
if(overStartButton) fill(circleHighlight);
else fill(circleColor);
ellipse( buttonX, startButtonY, circleSize, circleSize);
fill(0);
text("Start", buttonX - 20, startButtonY + 1);
text("F1", buttonX - 10, startButtonY + 19);
// Help Button
if(overHelpButton) fill(circleHighlight);
else fill(circleColor);
ellipse( buttonX, helpButtonY, circleSize, circleSize);
fill(0);
text("Help", buttonX - 17, helpButtonY - 2);
text("F10", buttonX - 15, helpButtonY + 16);

// Stop the game when we near our array limits
if (numBullets > 1950) GAMESTATE = OVER;

if (GAMESTATE.equals("NOACTION"))
{
enemy.draw();
if (numBullets > 1999) numBullets = 0;
for (int i = 0; i < numBullets; i++)
{
if(bullets[i].update())
{
bullets[i].draw();
}
}
}
if (GAMESTATE.equals(STARTED) || GAMESTATE.equals(OVER))
{
// Score
fill(255, 0, 0);
text("Enemy Score", 8, 30);
text(shipHits, 20, 60);
fill(0,0,255);
text("Your Score", 10, 550);
text(enemyHits, 20, 580);

if (enemyHits > 49 || shipHits > 49) GAMESTATE = OVER;
}

if (GAMESTATE.equals(STARTED))
{

//line seperates button section from game section
line(120, 0, 120, height);
//line splits middle
stroke(0,192,0); // green
line(120, 300, width, 300);
stroke(255);

enemy.draw();
ship.draw();
// Manage bullets
for (int i = 0; i < numBullets; i++)
{
if(bullets[i].update())
{
bullets[i].draw();
}
}
}
else if (GAMESTATE.equals(HELP))
{
textFont(fontB, 25);
fill(255, 255, 0);
stroke(0);
text("Use the Arrow Keys to move LEFT RIGHT UP DOWN", 50, 50);
text(" SPACEBAR to shoot", 90, 90);
text(" First one to 50 points WINS! ", 90, 250);
textFont(fontA, 15);
}
else if (GAMESTATE.equals(OVER))
{
textFont(fontB, 25);
fill(255, 255, 0);
stroke(0);
text("GAME OVER", 190, 100);


if (runningTextX < 250) runningTextX = runningTextX + 10;
if (runningTextY < 150) runningTextY = runningTextY + 10;

if(enemyHits > shipHits) text("YOU WIN", runningTextX, runningTextY);
else if (enemyHits == shipHits) text("DRAW", runningTextX, runningTextY);
else text("YOU LOSE", runningTextX, runningTextY);

textFont(fontA, 15);
}
else
{
textFont(fontB, 25);
fill(255, 255, 0);
stroke(0);
text("Press F1 to play in KeyBoard Mode.. ", 100, 50);
text("or click the Start Button to begin in Mouse Mode", 90, 90);
textFont(fontA, 15);
}
}

// Check if mouse if over the button or not
void updatePosition(int x, int y)
{
if(overButton(buttonX, startButtonY, circleSize)) overStartButton = true;
else overStartButton = false;
if( overButton( buttonX, helpButtonY, circleSize)) overHelpButton = true;
else overHelpButton = false;
if( overButton( buttonX, windButtonY, circleSize / 2)) overWindButton = true;
else overWindButton = false;
}

// Shoot a bullet or press a button
void mousePressed()
{
if(overStartButton)
{
startGame(MOUSEMODE);
currentColor = circleColor;
}
if(overHelpButton)
{
GAMESTATE = HELP;
currentColor = circleColor;
}
if(overWindButton)
{
if (bulletDrift)
{
bulletDrift = false;
driftAmount = 0;
}
else bulletDrift = true;
}
if (mouseX >= 145 && mouseX <= 790 && mouseY >= 315 && mouseY <= 590)
{
bullets[numBullets] = new Bullet(mouseX, mouseY - 10, driftAmount, 10, SHIPBULLET);
numBullets++;
}
}

void keyPressed()
{
if (keyCode == 119) // F8 for Drift
{
if (bulletDrift)
{
bulletDrift = false;
driftAmount = 0;
}
else bulletDrift = true;
}
if (GAMESTATE.equals(STARTED))
{
if (keyCode == RIGHT) {
if (shipPosX < 790 )shipPosX = shipPosX + 10;
}
else if (keyCode == LEFT){
if (shipPosX > 145) shipPosX = shipPosX - 10;
}
else if (keyCode == UP) {
if (shipPosY > 315) shipPosY = shipPosY - 10;
}
else if (keyCode == DOWN) {
if (shipPosY < 590) shipPosY = shipPosY + 10;
}
else if (keyCode == 32) // SPACE BAR
{
bullets[numBullets] = new Bullet(shipPosX, shipPosY, driftAmount, 10, SHIPBULLET);
numBullets++;
}
ship.draw();
}
else
{
if (keyCode == 112) startGame(KEYMODE); // Start the Game if Keyboard Mode
if (keyCode == 121) GAMESTATE = HELP; // View the help information
}
}
/**
* Method to determine if the mouse is over a button
*/
boolean overButton(int x, int y, int diameter)
{
float disX = x - mouseX;
float disY = y - mouseY;
if(sqrt(sq(disX) + sq(disY)) < diameter/2 ) return true;
else return false;
}
/** This class handles all bullets those from the ship and enemy ship
* It also decisded if there has been a hit
*/
class Bullet
{
float bulletBeginX, bulletBeginY, tankBulletX, tankBulletY, bulletEndX, bulletEndY = 0.0;
float bulletDistX, bulletDistY, bulletDrift, bulletSpeed;
String bulletOwner;
// Contructor
Bullet(float startX, float startY, float drift, float speed, String strOwner)
{
bulletBeginX = startX;
bulletBeginY = startY;
bulletDrift = drift;
bulletSpeed = speed;
tankBulletX = startX;
tankBulletY = startY;
bulletOwner = strOwner;
}
// Custom method for updating the bullets variables
boolean update()
{
if(tankBulletY < 0 || tankBulletY > 600) return(false);
if (bulletOwner.equals(SHIPBULLET))
{
tankBulletX = tankBulletX + bulletDrift;
tankBulletY = tankBulletY - bulletSpeed;
if (tankBulletX > enemyX) trueX = tankBulletX - enemyX;
else trueX = enemyX - tankBulletX;
if (tankBulletY > enemyY) trueY = tankBulletY - enemyY;
else trueY = enemyY - tankBulletY;
if (trueX < 20 && trueY < 20)
{
enemyHit = true;
enemyHits++;
System.out.println("Enemy is hit!!!!!!!!!");
}
}
else
{
tankBulletX = tankBulletX + bulletDrift;
tankBulletY = tankBulletY + bulletSpeed;
// Check if there has there been a hit - not exanct but good enough..
if (tankBulletX > shipX) trueSX = tankBulletX - shipX;
else trueSX = shipX - tankBulletX;
if (tankBulletY > shipY) trueSY = tankBulletY - shipY;
else trueSY = shipY - tankBulletY;
if (trueSX < 20 && trueSY < 20)
{
shipHit = true;
shipHits++;
System.out.println("Ship is hit!!!!!!!!!");
}
}
return(true);
}
// method to draw the bullets
void draw()
{
noStroke();
if (bulletOwner.equals(SHIPBULLET))
{
//yellow bullets for the ship
fill(255,255,0);
ellipse(tankBulletX, tankBulletY, 5,5);
fill(0);
}
else
{
//red bullets for the enemy
fill(255,0,0);
ellipse(tankBulletX, tankBulletY, 5,5);
fill(0);
}
stroke(255);
}
}

class Enemy
{
boolean moveUp, moveDown, moveLeft, moveRight = false;
boolean randomMovement = true;

float x, y = 50;
float clicked = 0;
float c1,c2,c3 = 255;
float rndMve = 1;
int dist, currDist, fireBullet = 0;
boolean demoMode;

// Contructor (required)
Enemy(boolean demoModeSet)
{
demoMode = demoModeSet;
}

void allFalse()
{
moveUp = false;
moveDown = false;
moveLeft = false;
moveRight = false;
}
// random movement for the opposition
void randomMover()
{
dist = 0;
currDist = (int) (Math.random() * 50 + 1);
rndMve = (int) (Math.random() * 7 + 1);
allFalse();
if (rndMve == 1) moveUp = true;
else if (rndMve == 2) moveDown = true;
else if (rndMve == 3) moveLeft = true;
else if (rndMve == 4) moveRight = true;
else if (rndMve == 5){ moveRight = true; moveUp = true;}
else if (rndMve == 6){ moveRight = true; moveDown = true;}
else if (rndMve == 7){ moveLeft = true; moveUp = true;}
else if (rndMve == 8){ moveLeft = true; moveDown = true;}
}
// Custom method for drawing the object
void draw()
{
dist++;
if (currDist == 0 ) randomMover();
else if (dist == currDist) randomMover();
if (moveUp) y = y - 10;
if (moveDown) y = y + 10;
if (moveLeft) x = x - 10;
if (moveRight) x = x + 10;
if (demoMode)
{
// keep the Enemy ship in bounds
if(y > 600)
{
moveDown = false;
moveUp = true;
}
if(y < 0)
{
moveUp = false;
moveDown = true;
}
if (x < 800)
{
moveRight = false;
moveLeft = true;
}
if (x < 140)
{
moveLeft = false;
moveRight = true;
}
}
else
{
// keep the Enemy ship in bounds
if(y >= 280)
{
moveDown = false;
moveUp = true;
}
if(y <= 10)
{
moveUp = false;
moveDown = true;
}
if (x >= 775)
{
moveRight = false;
moveLeft = true;
}
if (x <= 145)
{
moveLeft = false;
moveRight = true;
}
}
fill(255, 69, 0);
ellipse(x, y, 25,25);
float tx1, ty1, tx2, ty2, tx3, ty3;
tx1 = x;
ty1 = y + 18;
tx2 = x - 20;
ty2 = y - 10;
tx3 = x + 20;
ty3 = ty2 ;
triangle(tx1,ty1, tx2, ty2, tx3, ty3);

// should the enemy fire a bullet
fireBullet = (int) (Math.random() * 3 + 1);
if (fireBullet < 3)
{
bullets[numBullets] = new Bullet(x, y, driftAmount, 10, ENEMYBULLET);
numBullets++;
}
enemyX = x;
enemyY = y;
}
}
// The object that encapsulates our ship
class Ship
{
float x = 350;
float y = 400;
boolean mouseMode = false;
// Contructor (required)
Ship(String strMode)
{
if (strMode.equals(MOUSEMODE)) mouseMode = true;
}
// Custom method for drawing the object
void draw()
{
if (mouseMode)
{
// keep the ship in bounds
if (mouseX >= 145 && mouseX <= 790 && mouseY >= 315 && mouseY <= 590)
{
x = mouseX;
y = mouseY;
}
}
else
{
x = shipPosX;
y = shipPosY;
}
// Making of the ship
fill(0,0,255);
ellipse(x, y, 25, 25);
float tx1, ty1, tx2, ty2, tx3, ty3;
tx1 = x;
ty1 = y - 18;
tx2 = x - 20;
ty2 = y + 10;
tx3 = x + 20;
ty3 = ty2 ;
float thrust1X, thrust1Y, thrust2X, thrust2Y;
thrust1X = tx2 + 10;
thrust2X = tx3 - 10;
thrust2Y = ty2;
thrust1Y = ty2;
triangle(tx1,ty1, tx2, ty2, tx3, ty3);
fill(255,255,0);
ellipse( thrust1X, thrust1Y, 5, 5);
ellipse( thrust2X, thrust2Y, 5, 5);
stroke(255);
shipX = x;
shipY = y;
}
}

Tuesday 17 February 2009

I'm doing the london Marathon this year to help raise funds for Kidney Research UK.

I know a family that are severly affected by kidney disease and Kidney Research UK do some fantastic work. Kidney disease will affect 1 in 3 people.

Please sponsor me any amount you can via justgiving's secure system Using this link
Events

CHUNK 26
TITLE Event handling
DESCRIPTION Events are an important idea within Java and within Processing. Describe some simple mouse events and show the code for them. Bring it all together in a whole program.
OUTCOMES
• Write simple code which involves mouse events.
• Understand code that contains mouse handling events
REFERENCE Greenberg 140--141
HINT Not really a difficult section if you keep to mouse handling; don't be tempted to look at other events.
PROGRAM Develop a simple program that illustrates the concepts.