1 / 34

Das erste Spiel Teil 3 ( Scherfgen 531 - 552)

Das erste Spiel Teil 3 ( Scherfgen 531 - 552). Softwaretechnologie II (Teil 1): Simulation und 3D Programmierung Medienwiss ./Medieninformatik AM3 Visuelle Programmierung I  Referent: Janek Rudolf. Inhalt. Schritt 5: Bälle hinzufügen Schritt 6: Die Blöcke Schritt 7: Versuche

soo
Download Presentation

Das erste Spiel Teil 3 ( Scherfgen 531 - 552)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Das erste SpielTeil 3 (Scherfgen 531 - 552) Softwaretechnologie II (Teil 1): Simulation und 3D Programmierung Medienwiss./Medieninformatik AM3 Visuelle Programmierung I  Referent: Janek Rudolf

  2. Inhalt • Schritt 5: Bälle hinzufügen • Schritt 6: Die Blöcke • Schritt 7: Versuche • Schritt8: Punkte • Schritt 9: Sound für das Spiel • Schritt10: Hier spielt die Musik

  3. Schritt 5: Bälle hinzufügen • Erstellung von Klasse CBall • CGame werden 16 CBall-Variablen in einem Array hinzugefügt • U.a. BOOL m_bExists, BOOL m_bGrabbed, tbVector3 m_vPosition, tbVector3 m_vVelocity

  4. Fortbewegung und Kollisionen des Balls • Bewegung durch Methode CBall:Move • Fortbewegung des Balls: m_vVelocity x vergangene Zeit seit letztem Frame(CBall:Move) + m_vPosition

  5. Ball kann mit Wand und Schläger kollidieren • Radius des Ballmodells = 0.25 • Kollision mit der Wand tritt ein wenn: x-Koordinate des Positionsvektor +/- 0.25 in oder hinter der Wand liegt. Rechts: x=9.25, Links: x=-9.25, z=4.25 • Kollision mit dem Schläger tritt ein wenn: xBall >xSchläger-1.25 ^xBall<xSchläger +1.25^ zBall>zSchläger -0.25^zBall<zSchläger+0.25

  6. Indem die z-Komponente des Geschwindigkeitsvektors umgekehrt wird, prallt der Ball ab

  7. Verlieren des Balls • Ist m_vPosition <= -12, geht der Ball verloren • Die Variable m_bExists wird auf FALSE gesetzt • Im günstigsten Fall „klebt“ danach ein neuer Ball auf dem Schläger • Ist das der Fall, wird m_bGrabbed == TRUE und die move-Methode verlassen

  8. // Bewegt einen Ball tbResultCBall::Move(floatfTime) { // Wenn der Ball klebt: abbrechen! if(m_bGrabbed) return TB_OK; // Position verändern m_vPosition += m_vVelocity * fTime; // Wenn der Ball eine Wand berührt, prallt er ab. if(m_vPosition.x - 0.25f <= -9.25f) {bWall = TRUE; m_vVelocity.x *= -1.0f; m_vPosition.x = -9.0f;} // Linke Wand if(m_vPosition.x + 0.25f >= 9.25f) {bWall = TRUE; m_vVelocity.x *= -1.0f; m_vPosition.x = 9.0f;} // Rechte Wand if(m_vPosition.z + 0.25f >= 4.25f) {bWall = TRUE; m_vVelocity.z *= -1.0f; m_vPosition.z = 4.0f;} // Obere Wand // Auch am Schläger prallt er ab (Natürlich!). if(m_vPosition.x >= m_pGame->m_vPaddlePos.x - 1.25f && m_vPosition.x <= m_pGame->m_vPaddlePos.x + 1.25f && m_vPosition.z <= m_pGame->m_vPaddlePos.z + 0.25f && m_vPosition.z - m_vVelocity.z * fTime >= m_pGame->m_vPaddlePos.z + 0.25f) // Es gibt eine Kollision! Wir kehren die z-Komponente des Bewegungsvektors um. m_vVelocity.z *= -1.0f; if(m_vPosition.z < -12.0f) { m_bExists = FALSE; } }

  9. Rendern • Implementieren der Methode Cball::Render • tbMatrixTranslation(GetAbsPosition()) verschiebt Ballmodell an richtige Stelle • Absolute Position des Balls wird gebraucht in Translationsmatrix, sonst ist sie relativ zum Schläger • CGame::m_pBallModel->Render rendert danach den Ball

  10. Die Bälle • Erster Ball bei Eintritt ins Level, Zero Memory leert Array m_aBall • Erstellung eines Balls durch Methode CGame::CreateBall mit Parametern der Position, des Geschwindigkeitsvektors und dem Zustand, ob angeklebt oder nicht • Erster Ball: Relative Position zum Schläger(0,0, 0,25), Geschwindigkeitsvektor (0,0,0) und Zustand = Angeklebt

  11. Erstellung einer Liste in Form des Arrays CGame::m_aBall mit 16 Elementen • Mit m_bExists prüfen ob/wie viele Bälle existieren • CGame::Move geht die 16 Elemente durch, wenn die Elemente existieren, Aufruf seiner Move-Funktion und Aufruf von CBall::Render

  12. // Erstellt einen neuen Ball intCGame::CreateBall(tbVector3 vPosition, tbVector3 vVelocity, BOOL bGrabbed) { // Freien Ball suchen for(intiBall = 0; iBall < 16; iBall++) { if(!m_aBall[iBall].m_bExists) { // Freier Ball gefunden! Ausfüllen! m_aBall[iBall].m_bExists = TRUE; m_aBall[iBall].m_pGame = this; m_aBall[iBall].m_bGrabbed = bGrabbed; m_aBall[iBall].m_vPosition = vPosition; m_aBall[iBall].m_vVelocity = vVelocity; // Index des neuen Balls liefern returniBall; } } // Kein Platz mehr! return -1; }

  13. Abfeuern mit der Leertaste // Wenn die Leertaste gedrückt wurde, wird der klebende Ball // abgeworfen. if(g_pbButtons[TB_KEY_SPACE] && m_aBall[0].m_bExists && m_aBall[0].m_bGrabbed) { // Sound abspielen g_pBreakanoid->m_apSound[3]->PlayNextBuffer(); // Ball abfeuern! m_aBall[0].m_bGrabbed = FALSE; // Die Position eines klebenden Balls ist immer relativ // zum Schläger. Wir wandeln sie nun in eine absolute Position um. m_aBall[0].m_vPosition += m_vPaddlePos;

  14. // Den Bewegungsvektor des Balls berechnen wir zufällig. m_aBall[0].m_vVelocity.x = tbFloatRandom(-4.0f, 4.0f); m_aBall[0].m_vVelocity.y = 0.0f; m_aBall[0].m_vVelocity.z = tbFloatRandom(8.0f, 10.0f); // Den Bewegungsvektor des Schlägers addieren m_aBall[0].m_vVelocity += m_vPaddleVel; // Dem Ball einen kleinen "Schubs" nach vorne geben m_aBall[0].m_vPosition.z += 0.1f; }

  15. Schritt 6: Die Blöcke • Erstellen der Klasse CBlock mit der einzigen Methode Render • Variablen : m_iEnergy: Anzahl Energiepunkte • M_itype: Typ des Blocks (1 blau, 2 orange, 3 grün, 4 gelb) type= Anzahl Energiepunkte • tbVector3 m_vPosition: Position des Blocks auf dem Spielfeld • CGame* m_pGame: Kopie des CGame-Zeigers

  16. Blockreihen • Erstellen eines Arrays mit 64 CBlock-Elementen (wie bei den Bällen) • ZeroMemory setzt bei betreten des Levels alle Blöcke zurück • Level wird in Zeilen bzw. Strings unterteilt – Jedes Zeichen im String = ein Block • 1 Zeile = 9 Zeichen/Blöcke - Mehrere Zeilen = Level • Funktion CGame::CreateBlockRow um die Blockreihe zu erstellen

  17. // Erstellt eine Reihe von Blöcken tbResultCGame::CreateBlockRow(char* pcBlocks, tbVector3 vStartPos) { intiType; // Alle Zeichen im String durchgehen for(DWORD dwChar = 0; dwChar < strlen(pcBlocks); dwChar++) { // Wenn das Zeichen kein Leerzeichen ist... if(pcBlocks[dwChar] != ' ') { // Freien Block suchen for(DWORD dwBlock = 0; dwBlock < 64; dwBlock++) { if(m_aBlock[dwBlock].m_iEnergy <= 0) { // Freier Block gefunden - ausfüllen! // Zeichen im String in einen Blocktyp umwandeln. iType = 0; if(pcBlocks[dwChar] == '1') iType = 1; else if(pcBlocks[dwChar] == '2') iType = 2; else if(pcBlocks[dwChar] == '3') iType = 3; else if(pcBlocks[dwChar] == '4') iType = 4;

  18. Levels von Breakanoid // Je nach Level die Blöcke erstellen switch(iLevel) { case 1: CreateBlockRow(" 1 1 1 ", tbVector3(-8.0f, 0.0f, 2.0f)); CreateBlockRow("12 111 21", tbVector3(-8.0f, 0.0f, 1.0f)); CreateBlockRow("12 21", tbVector3(-8.0f, 0.0f, 0.0f)); CreateBlockRow(" 112 211 ", tbVector3(-8.0f, 0.0f, -1.0f)); break; case 2: CreateBlockRow(" 222 ", tbVector3(-8.0f, 0.0f, 1.0f)); CreateBlockRow(" 2 3 2 ", tbVector3(-8.0f, 0.0f, 0.0f)); CreateBlockRow(" 2 333 2 ", tbVector3(-8.0f, 0.0f, -1.0f)); CreateBlockRow("111111111", tbVector3(-8.0f, 0.0f, -2.0f)); break;

  19. Kollision zwischen Ball und Block • Prüfung in CBall::Move, ob Ball und Block kollidieren • Ist das der Fall, wird dem Block ein EP abgezogen, der Ball prallt ab • Problem: Welcher Block und welche Seite des Blocks wird getroffen • x-oder z-Komponente des Geschwindigkeitsvektors umkehren

  20. Zuerst Bedingung setzen, ob der Ball überhaupt mit dem Block kollidieren kann • Danach berechnen, wo der Ball den Block trifft, dazu die Minimalste Distanz von den 4 Blöcken zum Ball berechnen

  21. Bei links oder rechts vom Block, Vorzeichenveränderung der x-Komponente, • Bei oben oder unten vom Block, Vorzeichenveränderung der z-Komponente • nach Kollision, dem Ball einen Schub in die richtige Richtung geben

  22. // Kollision mit den Blöcken berechnen for(DWORD dwBlock = 0; dwBlock < 64; dwBlock++) { if(m_pGame->m_aBlock[dwBlock].m_iEnergy > 0) { vBlock = m_pGame->m_aBlock[dwBlock].m_vPosition; // Befindet sich der Ball im Kollisionsbereich? if(m_vPosition.x + 0.25f >= vBlock.x - 1.0f && m_vPosition.x - 0.25f <= vBlock.x + 1.0f && m_vPosition.z + 0.25f >= vBlock.z - 0.5f && m_vPosition.z - 0.25f <= vBlock.z + 0.5f) // Entfernung des Balls von allen Blockseiten berechnen fDistLeft = fabsf(m_vPosition.x + 0.25f - (vBlock.x - 1.0f)); fDistRight = fabsf(m_vPosition.x - 0.25f - (vBlock.x + 1.0f)); fDistTop = fabsf(m_vPosition.z - 0.25f - (vBlock.z + 0.5f)); fDistBottom = fabsf(m_vPosition.z + 0.25f - (vBlock.z - 0.5f));

  23. // Minimale Distanz berechnen fMinDist = TB_MIN(fDistLeft, TB_MIN(fDistRight, TB_MIN(fDistTop, fDistBottom))); // Wenn die Distanz zur linken oder rechten Seite am kleinsten ist... if(fMinDist == fDistLeft || fMinDist == fDistRight) { // Ball an der z-Achse abprallen lassen m_vVelocity.x *= -1.0f; // Dem Ball einen kleinen "Schubs" geben if(fMinDist == fDistLeft) m_vPosition.x -= 0.1f; elsem_vPosition.x += 0.1f; } else { // Ball an der x-Achse abprallen lassen m_vVelocity.z *= -1.0f; // Dem Ball einen kleinen "Schubs" geben if(fMinDist == fDistTop) m_vPosition.z += 0.1f; elsem_vPosition.z -= 0.1f; } // Dem Block einen Energiepunkt abziehen und Punkte addieren m_pGame->m_aBlock[dwBlock].m_iEnergy--; // Kollision ist immer nur mit einem einzigen Block möglich! break;

  24. Multiball • Wird ein Block zerstört (Energie =0), ermittelt tbIntRandom eine Zahl zwischen 1 und 14 • Ist es eine 7, wird ein neuer Ball mit zufälliger Flugrichtung nach unten erstellt

  25. Ende des Levels/Spiels: • Das Level ist geschafft, wenn alle Blöcke zerstört sind • Dazu wird im m_aBlock-Array die Anzahl der Blöcke mit vorhandener Energie gezählt • Sind alle Level geschafft, fängt der Spieler wieder bei Level 1 an

  26. Schritt 7: Versuche • Variable CGame::m_iNumTries wird zu Beginn des Spiels auf 5 gesetzt • In der Methode CGame:Move werden mit Hilfe einer for-Schleife die Bälle gezählt • Ist die Anzahl der Bälle 0, so wird dem Spieler mit m_iTriesLeft- - ein Versuch abgezogen und ein neuer Ball auf den Schläger „geklebt“

  27. Game Over ! • Um das Spiel bei m_iTries == 0 zu beenden, hinzufügen der Variable BOOL m_bGameOver • Bei TRUE wird in CGame::Render mit grüner und roter Schrift „Game Over!“ ausgegeben

  28. Schritt8: Punkte • Um eine Punktzahl zu speichern, wurde bereits die Variable CGame::m_iScoreerstellt • Die vergangene Zeit eine Levels wird in der Variable CGame::m_fLevelTimegespeichert • Umso weniger Zeit, desto mehr Punkte und pro Level 10000 Punkte extra • Zudem 100 Punkte bei Treffen eines Blocks, 1000-4000 bei Zerstörung

  29. // Level 1 bringt 10000 Punkte, Level 2 20000 Punkte usw.. m_iScore += m_iLevel * 10000; // Je weniger Zeit man gebraucht hat, desto mehr Extrapunkte gibt's. // Bei x benötigten Sekunden gibt es den x-ten Teil von 1000000 Punkten. m_iScore += (DWORD)(1000000.0f * (1.0f / m_fLevelTime)); // Dem Block einen Energiepunkt abziehen und Punkte addieren m_pGame->m_aBlock[dwBlock].m_iEnergy--; m_pGame->m_iScore += 100; // Wenn der Block zerstört wurde, gibt es Extrapunkte if(m_pGame->m_aBlock[dwBlock].m_iEnergy <= 0) { m_pGame->m_iScore += m_pGame->m_aBlock[dwBlock].m_iType * 1000;

  30. Schritt 9: Sound für das Spiel • Da alle Sounds schon geladen wurden, geht es nur noch um das abspielen • Die Sounds, die im Array CBreakanoid::m_apSound[11] gespeichert sind, werden gebraucht für: • CBreakanoid::m_apSound[2]: neuen Level betreten • CBreakanoid::m_apSound[3]: Ball abfeuern • CBreakanoid::m_apSound[4]: Ball geht verloren • CBreakanoid::m_apSound[5]: Ball trifft Schläger • CBreakanoid::m_apSound[6]: Extraball-Sound • CBreakanoid::m_apSound[7]: Ball prallt an Wand ab • CBreakanoid::m_apSound[8-11]: Ball trifft Block, 4 verschiedene Sounds

  31. Das Abspielen des Sounds funktioniert, indem man PlayNextBuffer auf der tbSound_klasseaufruft • Wenn der Ball einen Block berührt, wird durch Zufallsgenerator einer von 4 Tönen abgespielt: // Zufälligen "Pling"-Sound abspielen iSound= tbIntRandom(8, 11); iBuffer= g_pBreakanoid->m_apSound[iSound]->PlayNextBuffer(); if(iBuffer != -1)

  32. Schritt10: Hier spielt die Musik • Die Musik ist als MP3(MUSIC.MP3) gespeichert • Musik wird die komplette Zeit unverändert abgespielt • Dafür muss die Variable tbMusic* m_pMusic in der CBreakanoid –Klasse abgelegt werden

  33. Geladen und abgespielt wird sie in CBreakanoid::Load // Musik laden und gleich abspielen m_pMusic = newtbMusic; if(m_pMusic->Init("Data\\Music.mp3")) { // Fehler! TB_ERROR("Fehler beim Laden der Musik!", TB_ERROR); } m_pMusic->Play(); return TB_OK;

  34. Danke für eure Aufmerksamkeit!!!

More Related