5. Oktober 2012
Wir bekamen als Grundlage den rudimentären Code des Klassiker Breakout. Die Aufgabe bestand darin, eine eigene Gestaltung und ein neues Spielkonzept auf dem bestehenden Code zu auf zu bauen. Meine Idee basiert auf einer sehr simplen Geschichte. Ein Mann bekommt nach langjährigem Studium sein Diplom und geht anschliessend so richtig festen. Der Schläger der den Ball zurückgibt ist in diesem Fall sein „Abschluss Hut“. Mit jedem Brick den er getroffen/jedem Shot den er getrunken hat, wird er ein wenig mehr betrunken und fängt immer mehr an zu schwanken. So wird es mit der Zeit immer schwieriger, denn Ball aufzufangen. Lange musste ich mit random und noise herumspielen bis Max mich auf die Sinusfunktion aufmerksam machte. Für meinen Verwendungszweck perfekt. Mit jedem getroffenen Brick erhöt sich die Amplitude und der Student kann irgendwann kaum noch gerade laufen. Bricks/Shots generieren sich immer neu, so hört das Saufgelage erst auf, nachdem man aufgrund zu heftigen Schwankens den Ball nicht mehr trifft. Die Highscore entspricht den getrunkenen Shots. Einzelne Bricks fallen herunter, wenn man sie trifft. Fängt man sie auf wird man um die Hälfte weniger betrunken. Mein Fehler während der Arbeit an diesem Projekt bestand darin, das ich sehr lange Zeit an Einzelheiten herumexperimentiert habe anstatt mich dem Gesamtkonzept zu widmen. Ich fühlte mich ausserdem zuerst völlig erschlagen von dem vielen Code. Die Aufteilung in einzelne Klassen mag zwar praktisch sein, nahm mir aber die Übersicht über den sonst schon verwirrenden Code. Nach dem Abschluss des Programmiermoduls nahm ich mir dann nochmals die Zeit mein Spiel so gut als möglich fertig zu stellen. Die Grafische Umsetzung ist nun mehr bezogen auf das Spielkonzept. Ausserdem ist es durch die sich immer wieder generierenden Bricks, ein einziges Level, welches man jedoch unendlich lang spielen könnte./* -------------------------------------------------------------------------- * BreakOut * -------------------------------------------------------------------------- * prog: Max Rheiner * date: 26/09/2012 (m/d/y) * ---------------------------------------------------------------------------- */ import ddf.minim.*; Minim minim; AudioSample ballHitSnd; AudioSample ballHitSchlaegerSnd; BouncingBall ball; Racket schlaeger = null; Brick[] brickList = null; dropDown[] dropDownList = null; PImage muenze; PImage imageStart; PImage headbehind; int score=0; float dru = 0; final static int GAME_MODE_MENU = 0; final static int GAME_MODE_PLAY = 1; final static int GAME_MODE_GAMEOVER = 2; int gameMode = GAME_MODE_MENU; float alp=0; void setup() { size(displayWidth, displayHeight); ball = new BouncingBall(width/2, height/2, 7); schlaeger = new Racket(0, height - 170, 100, 15); muenze = loadImage("fuenf.png"); imageStart = loadImage("abschluss.jpeg"); headbehind=loadImage("headbehind.jpeg"); // sound init minim = new Minim(this); ballHitSnd = minim.loadSample("hit.mp3"); ballHitSchlaegerSnd = minim.loadSample("hitSchlaeger.mp3"); smooth(); noCursor(); } void initGameScene() { dru = alp = 0; // setzte die start posititon des balles ball.set(new PVector(width/2, height/2), new PVector(random(-7, 7), -7), 1); score=0; // erzeuge die ziegel int randomCount = (int)random(3, 12); brickList = new Brick[randomCount]; dropDownList = new dropDown[randomCount]; for (int i=0;i < brickList.length;i++) { brickList[i] = new Brick(200 + i * 55, 200, 50, 20); dropDownList[i] = new dropDown(200 + i * 55, 200, 50, 20); } int Zeile=13; int Spalte=24; brickList = new Brick[Zeile*Spalte]; dropDownList = new dropDown[Zeile*Spalte]; int xZ = 75; int yZ = 200; for (int a=0;a < Zeile; a++) { for (int i=0;i < brickList.length/Zeile;i++) { if(random(1)<0.2){ brickList[i+(brickList.length/Zeile*a)] = new Brick(xZ , yZ, 53, 20); dropDownList[i+(brickList.length/Zeile*a)] = new dropDown(xZ , yZ, 53, 20); } xZ += 55; } xZ = 75; yZ += 25; } } void draw() { // ghosting fill(255, 100); rect(0, 0, width, height); drawScene(); } void drawScene() { switch(gameMode) { case GAME_MODE_MENU: drawMenu(); break; case GAME_MODE_PLAY: drawGame(); break; case GAME_MODE_GAMEOVER: drawGameOver(); break; } } void drawMenu() { pushStyle(); fill(0); // text("Ready To Get Drunk?", 350, 200); image(imageStart,230,-200); // text("\'p\' : start game", 350, 230); // text("Space : stop game", 350, 250); popStyle(); } void drawGameOver() { pushStyle(); fill(0); text("Overdose, Next Time You'll Stomache More. Shots You Drank: "+score, 350, 200); popStyle(); } void drawGame() { // update die daten, berechne kollisionen updateScene(); // zeichne ziegel for (int i=0;i < brickList.length;i++) { if (brickList[i] != null) brickList[i].draw(); } for (int i=0;i < dropDownList.length;i++) { if (dropDownList[i] != null) dropDownList[i].draw(); } pushStyle(); fill(0); text(score, 30, 30); popStyle(); // zeichne den ball ball.draw(); // zeichne schlaeger schlaeger.draw(); } void keyPressed() { switch(key) { case 'p': // start game gameMode = GAME_MODE_PLAY; initGameScene(); break; case ' ': // end gameMode = GAME_MODE_MENU; break; } } void updateScene() { // test ob ball aus dem spielfeld ist if (ball._pos.y > height- ball._r) { gameMode = GAME_MODE_GAMEOVER; return; } // update schlaeger pos // schlaeger.move(schlaeger._pos.x+(mouseX-schlaeger._pos.x)*dru, mouseY); alp+=0.1; schlaeger.move(mouseX+sin(alp)*dru, mouseY); PVector hitPos = new PVector(); // 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: 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; ball._dir.x += hitV * 8; ball._dir.y *= -1; // ball soll die gleiche geschwindigkeit haben wie am anfang float speed = ball._dir.mag(); 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 -1 ; // spiele sound ballHitSchlaegerSnd.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; // entferne ziegel aus liste //brickList[i] = null; brickList[i] = new Brick(int(random(25))*55+75 , int(random(13))*25+300, 53, 20); // spiele sound score++; ballHitSnd.trigger(); break; case Brick.HIT_TOP: case Brick.HIT_BOTTOM: // aendere flugrichtung ball ball._dir.y *= -1; // entferne ziegel aus liste brickList[i] = new Brick(int(random(25))*55+75 , int(random(13))*25+300, 53, 20); score++; // spiele sound ballHitSnd.trigger(); dru = dru + 0.5; break; } if (retVal != Brick.HIT_NO) { if(i<dropDownList.length) dropDownList[i].startFall(); } } } }