5. Oktober 2012
Seventh and Eighth Day: For the end of the two weeks of programming, we got to "program" the game "Breakout". The title of this blog entry practically means that we had to alter the game in a sense that it wouldn't be like the original version anymore (not only the graphics). Due to the previous 2-3 assignments, we were able to get a good head start in this task. Although I had a lot of ideas of how I wanted my game to develop into, it was difficult to convert what I had in mind into the reality because of the lack of knowledge in processing. But the problem didn't end there: There were times where altering a minor part could cause a whole chain reaction throughout the code and it would not work because of careless mistakes in the syntax. It took time to experiment as well as modify the game. For the game play: I took off the barricade from the upper side of the window and made another racket which was parallel to the first and had quite a distance from it too (a bit like a sandwich-principle). How to win: Destroy all the bars given. How to lose (not that it's hard to): When the ball flies out of the upper/bottom side of the window. If the ball hits the left/right side, it'll just bounce off, so no worries there. Surprises: If the racket sped up too fast to hit the ball, the ball might not bounce off the racket but pass through it instead (actually not intended but it's a similar problem with the previous assignment). As for the design, I came up with personifying the racket, ball and bars. The racket and the ball would be the protagonists (with knowledge of martial arts apparently) and the bars would be the minions of an evil Overlord (if there were be a boss after multiple levels). But as for now, it seems to be the other way around: Due to the missing Overlord, it seems that the protagonists are the evil ones, beating up the bars for no reason. The conclusion: I feel quite mischievous while playing the game the way it is now. The "Breakout" game:import ddf.minim.*; Minim minim; AudioSample ballHitSnd; AudioSample ballHitSchlaegerSnd; AudioSample ballHitSchlaeger2Snd; BouncingBall ball; Racket schlaeger = null; Racket schlaeger2 = null; Brick[] brickList = null; int pointCount = 0; PImage[] imageList = null; PFont font; final static int GAME_MODE_MENU = 0; //final static = can't be changed anymore final static int GAME_MODE_PLAY = 1; final static int GAME_MODE_GAMEOVER = 2; final static int GAME_MODE_WIN = 3; int gameMode = GAME_MODE_MENU; void setup() { size(800, 600); imageList = new PImage[6]; imageList[0] = loadImage("./data/RACKET.jpg"); imageList[1] = loadImage("./data/BALL.png"); imageList[2] = loadImage("./data/PLAYBACK.jpg"); imageList[3] = loadImage("./data/START.jpg"); imageList[4] = loadImage("./data/YOUWIN.jpg"); imageList[5] = loadImage("./data/GAMEOVER.jpg"); ball = new BouncingBall(width/2, height/3, 3); schlaeger = new Racket(0, height - 40, 70, 10); schlaeger2 = new Racket(0, height, 70, 10); // start den sound minim = new Minim(this); ballHitSnd = minim.loadSample("hit.mp3"); ballHitSchlaegerSnd = minim.loadSample("hitSchlaeger.mp3"); ballHitSchlaeger2Snd = minim.loadSample("hitSchlaeger.mp3"); smooth(); noCursor(); } void initGameScene() { ball.set(new PVector(width/2, height/2), new PVector(random(-7, 7), -7), 1); // erzeuge die ziegel int Zeile = 2; int Spalte = 5; brickList = new Brick[Zeile*Spalte]; int xZ = 300; int yZ = 300; for (int a = 0; a < Zeile; a++) { for (int i = 0; i < brickList.length/Zeile;i++) { brickList[i+(brickList.length/Zeile*a)] = new Brick(xZ , yZ, 50, 20); xZ += 55; } xZ = 80; yZ += 25; } } // erzeuge ziegel // brickList = new Brick[(int)random(3, 12)]; // for (int i=0;i < brickList.length;i++) // { // brickList[i] = new Brick(200 + i * 55, 200, 50, 20); //i is the distance between the bricks // } //} void draw() { // ghosting fill(0, 0, 0, 255); rect(0, 0, width, height); // update schlaeger pos schlaeger.move(mouseX, mouseY-200); schlaeger2.move(mouseX, mouseY+200);   drawScene(); } void drawScene() { switch(gameMode) { case GAME_MODE_MENU: drawMenu(); break; case GAME_MODE_PLAY: drawGame(); break; case GAME_MODE_GAMEOVER: drawGameOver(); break; case GAME_MODE_WIN: drawWin(); break; } } void drawMenu() { pushStyle(); fill(255); // text("BreakOut", 350, 200); // // text("\'s\' : start game", 350, 230); // text("Space : stop game", 350, 250); image(imageList[3], 0, 0, width, height); popStyle(); } void drawGameOver() { pushStyle(); fill(150); image(imageList[5], 0, 0, width, height); font = loadFont("AmericanTypewriter-48.vlw"); textFont(font,40); text(pointCount, width-200, height-30); popStyle(); } void drawGame() { // berechne kollisionen updateScene(); pushStyle(); fill(255); image(imageList[2], 0, 0, width, height); font = loadFont("AmericanTypewriter-48.vlw"); textFont(font,20); text("Score:" + pointCount,700,50); popStyle(); // zeichne ziegel for (int i=0;i < brickList.length;i++) { if (brickList[i] != null) brickList[i].draw(); } // zeichne den ball ball.draw(); // zeichne schlaeger schlaeger.draw(); schlaeger2.draw(); } void keyPressed() { switch(key) { case 's': // start game gameMode = GAME_MODE_PLAY; initGameScene(); pointCount = 0; break; case ' ': // end gameMode = GAME_MODE_MENU; break; } } void updateScene() { // test of ball aus der scene if (ball._pos.y > height- ball._r || ball._pos.y < 0+ ball._r) { gameMode = GAME_MODE_GAMEOVER; return; } if (pointCount == brickList.length) { gameMode = GAME_MODE_WIN; return; } // update schlaeger pos schlaeger.move(mouseX, mouseY); PVector hitPos = new PVector(); float hitV; float speed; // teste ob ball den schlaeger trifft int retVal = schlaeger.checkCollision(ball._pos.x, ball._pos.y, ball._r, ball._dir,hitPos); switch(retVal) { case Brick.HIT_LEFT: // aendere flugrichtung ball ball._dir.x *= -1; // setzte ball buendig auf den schlaeger(das er nicht im schlaeger ist) ball._pos.x = schlaeger._pos.x - schlaeger._w/2 - ball._r; // spiele sound ballHitSchlaegerSnd.trigger(); break; case Brick.HIT_RIGTH: // aendere flugrichtung ball ball._dir.x *= -1; // setzte ball buendig auf den schlaeger(das er nicht im schlaeger ist) ball._pos.x = schlaeger._pos.x + schlaeger._w/2 + ball._r; // spiele sound ballHitSchlaegerSnd.trigger(); break; case Brick.HIT_TOP: // aendere flugrichtung ball // anschnitt berechnen hitV = hitPos.x - (schlaeger._pos.x - schlaeger._w/2); hitV = 1.0 / schlaeger._w * hitV - 0.5; speed = ball._dir.mag(); ball._dir.x += hitV * 8; ball._dir.y *= -1; // ball soll die gleiche geschwindigkeit haben wie am anfang ball._dir.normalize(); ball._dir.mult(speed); // setzte ball buendig auf den schlaeger(das er nicht im schlaeger ist) ball._pos.y = schlaeger._pos.y - schlaeger._h/2 - ball._r ; // spiele sound ballHitSchlaegerSnd.trigger(); break; case Brick.HIT_BOTTOM: // aendere flugrichtung ball // anschnitt berechnen hitV = hitPos.x - (schlaeger._pos.x - schlaeger._w/2); hitV = 1.0 / schlaeger._w * hitV - 0.5; speed = ball._dir.mag(); ball._dir.x += hitV * 8; ball._dir.y *= -1; // ball soll die gleiche geschwindigkeit haben wie am anfang ball._dir.normalize(); ball._dir.mult(speed); // setzte ball buendig auf den schlaeger(das er nicht im schlaeger ist) ball._pos.y = schlaeger._pos.y + schlaeger._h/2 + ball._r ; // spiele sound ballHitSchlaegerSnd.trigger(); break; } retVal = schlaeger2.checkCollision(ball._pos.x, ball._pos.y, ball._r, ball._dir,hitPos); switch(retVal) { case Brick.HIT_LEFT: // aendere flugrichtung ball ball._dir.x *= -1; // setzte ball buendig auf den schlaeger(das er nicht im schlaeger ist) ball._pos.x = schlaeger2._pos.x - schlaeger2._w/2 - ball._r; // spiele sound ballHitSchlaeger2Snd.trigger(); break; case Brick.HIT_RIGTH: // aendere flugrichtung ball ball._dir.x *= -1; // setzte ball buendig auf den schlaeger(das er nicht im schlaeger ist) ball._pos.x = schlaeger2._pos.x + schlaeger2._w/2 + ball._r; // spiele sound ballHitSchlaeger2Snd.trigger(); break; case Brick.HIT_TOP: // aendere flugrichtung ball // anschnitt berechnen hitV = hitPos.x - (schlaeger2._pos.x - schlaeger2._w/2); hitV = 1.0 / schlaeger._w * hitV - 0.5; speed = ball._dir.mag(); ball._dir.x += hitV * 8; ball._dir.y *= -1; // ball soll die gleiche geschwindigkeit haben wie am anfang ball._dir.normalize(); ball._dir.mult(speed); // setzte ball buendig auf den schlaeger(das er nicht im schlaeger ist) ball._pos.y = schlaeger2._pos.y - schlaeger2._h/2 - ball._r ; // spiele sound ballHitSchlaeger2Snd.trigger(); break; case Brick.HIT_BOTTOM: // aendere flugrichtung ball // anschnitt berechnen hitV = hitPos.x - (schlaeger2._pos.x - schlaeger2._w/2); hitV = 1.0 / schlaeger2._w * hitV - 0.5; speed = ball._dir.mag(); ball._dir.x += hitV * 8; ball._dir.y *= -1; // ball soll die gleiche geschwindigkeit haben wie am anfang ball._dir.normalize(); ball._dir.mult(speed); // setzte ball buendig auf den schlaeger(das er nicht im schlaeger ist) ball._pos.y = schlaeger2._pos.y + schlaeger2._h/2 + ball._r ; // spiele sound ballHitSchlaeger2Snd.trigger(); break; } /* PVector hitPos = new PVector(); // teste of ball den schlaeger trifft int retVal = schlaeger.checkCollision(ball._pos.x, ball._pos.y, ball._r, ball._dir,hitPos); int retVal2 = schlaeger2.checkCollision(ball._pos.x, ball._pos.y, ball._r, ball._dir,hitPos); switch(retVal) { case Brick.HIT_LEFT: case Brick.HIT_RIGTH: // aendere flugrichtung ball ball._dir.x *= -1; // spiele sound ballHitSchlaegerSnd.trigger(); break; case Brick.HIT_TOP: case Brick.HIT_BOTTOM: // aendere flugrichtung ball // anschnitt berechnen float hitV = hitPos.x - (schlaeger._pos.x - schlaeger._w/2); hitV = 1.0 / schlaeger._w * hitV - 0.5; float speed = ball._dir.mag(); ball._dir.x += hitV * 8; ball._dir.y *= -1; ball._dir.normalize(); ball._dir.mult(speed); // spiele sound ballHitSchlaegerSnd.trigger(); break; } // teste of ball den schlaeger trifft switch(retVal2) { case Brick.HIT_LEFT: case Brick.HIT_RIGTH: // aendere flugrichtung ball ball._dir.x *= -1; // spiele sound ballHitSchlaeger2Snd.trigger(); break; case Brick.HIT_TOP: case Brick.HIT_BOTTOM: // aendere flugrichtung ball // anschnitt berechnen float hitV2 = hitPos.x - (schlaeger2._pos.x - schlaeger2._w/2); hitV2 = 1.0 / schlaeger2._w * hitV2 - 0.5; float speed = ball._dir.mag(); ball._dir.x += hitV2 * 8; ball._dir.y *= -1; ball._dir.normalize(); ball._dir.mult(speed); // spiele sound ballHitSchlaeger2Snd.trigger(); break; } */ // test ob ball einen ziegel trifft for (int i=0;i < brickList.length;i++) { if (brickList[i] != null) { retVal = brickList[i].checkCollision(ball._pos.x, ball._pos.y, ball._r, ball._dir,hitPos); switch(retVal) { case Brick.HIT_LEFT: case Brick.HIT_RIGTH: // aendere flugrichtung ball ball._dir.x *= -1; pointCount +=1; // entferne ziegel aus liste brickList[i] = null; // spiele sound ballHitSnd.trigger(); break; case Brick.HIT_TOP: case Brick.HIT_BOTTOM: // aendere flugrichtung ball ball._dir.y *= -1; pointCount +=1; // entferne ziegel aus liste brickList[i] = null; // spiele sound ballHitSnd.trigger(); break; } } } } void drawWin() { pushStyle(); fill(150); font = loadFont("AmericanTypewriter-48.vlw"); textFont(font,40); image(imageList[4], 0, 0, width, height); text(pointCount, width-550, height-72); popStyle(); }LOSING SITUATION (which happens quite often): WINNING SCENE: The bouncing ball and racket (the bricks stayed the way as they were from the beginning):
class BouncingBall { PVector _pos; PVector _dir; float _dampV; int _d; int _r; // konstruktor BouncingBall(int x,int y,int radius) { _pos = new PVector(x, y); _dir = new PVector(0,0); _dampV = 1; _r = radius; _d = _r * 3; } // setzt die neue pos + richtung + daempfung void set(PVector pos,PVector dir,float dampV) { _pos = pos.get(); _dir = dir.get(); _dampV = dampV; } // erneuert die aktuelle position void calcPos() { // aktuelle position verschieben _pos.add(_dir); // bewegungs vektor veraendert _dir.mult(_dampV); // teste horizontal if(_pos.x + _r > width) { _dir.x *= -1; _pos.x = width - _r; } else if(_pos.x - _r < 0) { _dir.x *= -1; _pos.x = _r; } // // teste vertikal // if(_pos.y - _r < 0) // { // _dir.y *= -1; // _pos.y = _r; // } } // zeichnet den ball void draw() { calcPos(); pushStyle(); fill(255); noStroke(); ellipse(_pos.x,_pos.y,_d,_d); image(imageList[1],_pos.x-16.5, _pos.y-18, 30,30); popStyle(); } }
class Racket extends Brick { Racket(int posX,int posY,int w,int h) { super(posX,posY,w,h); } void move(int x,int y) { _pos.x = x; _pos.y = y; } void draw() { pushStyle(); rectMode(CENTER); fill(255); rect(_pos.x, _pos.y, _w, _h); image(imageList[0],_pos.x-35, _pos.y-4.5,70,10); popStyle(); } }