123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550 |
- //
- // Breakout.cpp
- // ogamalBreakout
- //
- // Created by Osama Attia on 9/21/14.
- // ogamal@iastate.edu
- //
-
- #include "Breakout.h"
- #include <stdio.h>
-
- using namespace std;
-
- void recomputeFrame(int value);
-
- Breakout::Breakout() {
- init();
- }
-
- Breakout::~Breakout() {
-
- }
-
- void Breakout::display(void) {
-
- // Clear buffer
- glClear(GL_COLOR_BUFFER_BIT);
-
- // Set OpenGL for 2D drawing
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glDisable(GL_LIGHTING);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_TEXTURE_2D);
- glOrtho(0.0f, WINWIDTH, WINHEIGHT, 0.0f, 0.0f, 1.0f);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- // Draw my cool gradient background
- drawBackground();
-
- // Select which state of the game to display
- switch (gameState) {
- case INIT:
- // Init values
- init();
- break;
-
- case Menus:
- // TODO List menu
- break;
-
- case Gameplay:
- // Draw the game
- drawGame();
- // If no balls, player loses the game
- if (balls.size() <= 0 & lifesCount > 0) {
- newBall(-1, -1);
- lifesCount--;
- reward = 100;
- } else if (balls.size() <= 0) {
- // TODO - GAME OVER
- }
-
- // If no bricks, player wins the level
- if (bricks.size() <= 0 && level <= 2) {
- level++;
- initBricks();
- } else if (bricks.size() <= 0) {
- // TODO - PLAYER WON
- }
- break;
-
- case Scoreboard:
- // TODO
- break;
-
- default:
- break;
- }
-
- glutTimerFunc(TIMER, recomputeFrame, 0);
-
- glutSwapBuffers();
- }
-
- void recomputeFrame(int value) {
- glutPostRedisplay();
- }
-
- void Breakout::init(void) {
- // Reset game statistics
- score = 0;
- level = 1;
- reward = 100;
- lifesCount = 3;
-
- // Remove all balls
- balls.clear();
-
- // Remove all bricks
- bricks.clear();
-
- // Init bricks
- initBricks();
-
- // Add ball and paddle
- initPaddle();
- newBall(-1, -1);
-
- // Start game play
- gameState = Breakout::Gameplay;
- }
-
- void Breakout::drawBackground(void) {
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glBegin(GL_QUADS);
- // Top color
- glColor3f(0.3f, 0.3f, 0.3f);
- glVertex2f(WINWIDTH, WINHEIGHT);
- glVertex2f(-WINWIDTH, WINHEIGHT);
- // Bottom color
- glColor3f(0.0f, 0.0f, 0.0f);
- glVertex2f(0.0f, 0.0f);
- glVertex2f(0.0f, 0.0f);
- glEnd();
- }
-
- void Breakout::drawGame(void) {
- // // Draw coordinates for guidance
- // drawCoordinate();
-
- // Draw balls
- drawBalls();
-
- // Draw bricks
- drawBricks();
-
- // Draw paddle
- drawPaddle();
-
- // Draw game statistics (lifes, score)
- drawGameStats();
-
- }
-
- void Breakout::newBall(float x = -1, float y = -1) {
- Ball b1;
- if (x < 0 || y < 0) {
- b1.xpos = WINWIDTH / 2.0;
- b1.ypos = WINHEIGHT - 30.0f;
- } else {
- b1.xpos = x;
- b1.ypos = y;
- }
- if ((float) rand() / (RAND_MAX) < 0.5)
- b1.xvel = 5.0f;
- else
- b1.xvel = -5.0f;
- b1.yvel = -10.0f;
- b1.radius = BALL_RADIUS;
- b1.r = 0.4f + (float) rand() / (RAND_MAX);
- b1.g = 0.25f + (float) rand() / (RAND_MAX);
- b1.b = 0.4f + (float) rand() / (RAND_MAX);
- balls.push_back(b1);
- }
-
- void Breakout::drawBalls(void) {
- for (std::vector<Ball>::iterator it = balls.begin(); it != balls.end(); ) {
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // use GL_LINE if no fill
- glBegin(GL_POLYGON);
- glColor3f(it->r, it->g, it->b);
- for(int j = 0; j < CIRCLE_SEGMENTS; j++) {
- float const theta = 2.0f * 3.1415926f * (float)j / (float)CIRCLE_SEGMENTS;
- float const x = it->radius * cosf(theta);
- float const y = it->radius * sinf(theta);
- glVertex2f(x + it->xpos, y + it->ypos);
- }
- glEnd();
-
- // Set new position
- it->xpos += it->xvel;
- it->ypos += it->yvel;
-
- // Collision with left/right/top window sides
- if ( (it->xpos <= (2 * it->radius)) || (it ->xpos >= (WINWIDTH - 2 * it->radius)) ) {
- it->xvel *= -1;
- }
- if ( (it->ypos <= (2 * it->radius)) ) {
- it->yvel *= -1;
- }
- if (it->ypos >= (WINHEIGHT - 2 * it->radius)) {
- it = balls.erase(it);
- continue;
- }
-
- // Collission with the bricks
- for (std::vector<Brick>::iterator br = bricks.begin(); br != bricks.end(); ) {
- // Check collission between circle and vertical brick sides
- if (it->ypos >= br->ypos && it->ypos <= br->ypos + br->height) {
- // brick right edge and left point on circle
- if ((it->xpos - it->radius - br->xpos - br->width) <= 5 && (it->xpos - it->radius - br->xpos - br->width) >= 0) {
- it->xvel *= -1;
- br = hitBrick(br);
- continue;
- }
-
- // brick left edge and right point on circle
- if ((it->xpos + it->radius - br->xpos) >= -5 && (it->xpos + it->radius - br->xpos) <= 0) {
- it->xvel *= -1;
- br = hitBrick(br);
- continue;
- }
- }
-
- // Check collission between circle and horizontal brick sides
- if (it->xpos >= br->xpos && it->xpos <= br->xpos + br->width) {
- // brick bottom edge and top point on circle
- if ((it->ypos - it->radius - br->ypos - br->height) <= 10 && (it->ypos - it->radius - br->ypos - br->height) >= 0) {
- it->yvel *= -1;
- br = hitBrick(br);
- continue;
- }
-
- // brick top edge and bottom point on circle
- if ((it->ypos + it->radius - br->ypos) >= -10 && (it->ypos + it->radius - br->ypos) <= 0) {
- it->yvel *= -1;
- br = hitBrick(br);
- continue;
- }
- }
-
- GLfloat d;
- // Check collission with top left corner
- d = pow((it->xpos - br->xpos), 2.0) + pow((it->ypos - br->ypos), 2.0);
- if (d < it->radius + 5.0) {
- it->xvel *= -1;
- it->yvel *= -1;
- br = hitBrick(br);
- continue;
- }
-
- // Check collission with top right corner
- d = pow((it->xpos - br->xpos - br->width), 2.0) + pow((it->ypos - br->ypos), 2.0);
- if (d < it->radius + 5.0) {
- it->xvel *= -1;
- it->yvel *= -1;
- br = hitBrick(br);
- continue;
- }
-
- // Check collission with bottom left corner
- d = pow((it->xpos - br->xpos), 2.0) + pow((it->ypos - br->ypos - br->height), 2.0);
- if (d < it->radius + 5.0) {
- it->xvel *= -1;
- it->yvel *= -1;
- br = hitBrick(br);
- continue;
- }
-
- // Check collission with bottom right corner
- d = pow((it->xpos - br->xpos - br->width), 2.0) + pow((it->ypos - br->ypos - br->height), 2.0);
- if (d < it->radius + 5.0) {
- it->xvel *= -1;
- it->yvel *= -1;
- br = hitBrick(br);
- continue;
- }
-
- ++br; // next brick
- }
-
- // Check collission between paddle's top edge and bottom point on circle
- if (it->xpos >= paddle.xpos && it->xpos <= paddle.xpos + paddle.width) {
- if ((it->ypos + it->radius - paddle.ypos) >= -10 && (it->ypos + it->radius - paddle.ypos) <= 0) {
- it->yvel *= -1;
- reward = 100;
- score += reward;
- continue;
- }
- }
-
- ++it; // next ball
- }
- }
-
- void Breakout::initPaddle(void) {
- paddle.r = 0.2f;
- paddle.g = 0.5f;
- paddle.b = 1.0f;
- paddle.width = 150.0f;
- paddle.height = 12.0f;
- paddle.xpos = WINWIDTH / 2.0f - paddle.width / 2.0f;
- paddle.ypos = WINHEIGHT - 20.0f;
- }
-
- void Breakout::drawPaddle() {
- // Make sure paddle is larger than 25px
- if (paddle.width < 25) {
- paddle.width = 25;
- }
-
- glColor3f(paddle.r, paddle.g, paddle.b);
- glRectf(paddle.xpos, paddle.ypos, paddle.xpos + 5.0f, paddle.ypos + paddle.height);
- glRectf(paddle.xpos + 10.0f, paddle.ypos, paddle.xpos + paddle.width - 10.0f, paddle.ypos + paddle.height);
- glRectf(paddle.xpos + paddle.width - 5.0f, paddle.ypos, paddle.xpos + paddle.width, paddle.ypos + paddle.height);
- }
-
- void Breakout::drawBricks(void) {
- for (std::vector<Brick>::iterator it = bricks.begin(); it != bricks.end(); ++it) {
- glColor3f(it->r, it->g, it->b);
- glRectf(it->xpos, it->ypos, it->xpos + it->width, it->ypos + it->height);
-
- // Top cool triangle (kind of texture)
- glBegin(GL_QUADS);
- glColor3f(it->r-0.2f, it->g-0.2f, it->b-0.2f);
- glVertex2f(it->xpos, it->ypos);
- glColor3f(it->r-0.05f, it->g-0.05f, it->b-0.05f);
- glVertex2f(it->xpos + it->width, it->ypos);
- glColor3f(it->r-0.15f, it->g-0.15f, it->b-0.15f);
- glVertex2f(it->xpos + it->width, it->ypos + it->height);
- glVertex2f(it->xpos, it->ypos);
- glEnd();
- }
- }
-
- template <typename Iterator>
- Iterator Breakout::hitBrick(Iterator brick) {
- score += reward;
- reward += 25;
- // system("afpqlay ../../cartoon008.wav");
-
- // Decrease brick health
- if (brick->health > 1) {
- brick->r = 0.95f;
- brick->g = 0.95f;
- brick->b = 0.95f;
- brick->health -= 1;
- return ++brick;
- } else {
- return bricks.erase(brick);
- }
- }
-
- void Breakout::initBricks(void) {
- if (level == 1)
- bricksLevel1();
- else if (level == 2)
- bricksLevel2();
- }
-
- void Breakout::bricksLevel1(void) {
- Brick newBrick;
- newBrick.r = 0.95f;
- newBrick.g = 0.95f;
- newBrick.b = 0.95f;
- newBrick.health = 1;
- newBrick.width = (WALLWIDTH - (WALLCOLS - 2) * WALLSPACE) / WALLCOLS;
- newBrick.height = (WALLHEIGHT - (WALLROWS - 2) * WALLSPACE) / WALLROWS;
-
- for (int i = 0; i < WALLROWS; ++i) {
- for (int j = 0; j < WALLCOLS; ++j) {
- // Set stronger bricks
- if (i+1 > ceil(WALLROWS / 2.0) - 2 && i < ceil(WALLROWS / 2.0) + 2 && j+2 > ceil(WALLCOLS / 2.0) - 3 && j < ceil(WALLCOLS / 2.0) + 3) {
- newBrick.r = 1.0f;
- newBrick.g = 0.5f;
- newBrick.b = 0.5f;
- newBrick.health = 2;
- } else {
- newBrick.r = 0.95f;
- newBrick.g = 0.95f;
- newBrick.b = 0.95f;
- newBrick.health = 1;
- }
-
- newBrick.xpos = WALLX + j * newBrick.width + j * WALLSPACE;
- newBrick.ypos = WALLY + i * newBrick.height + i * WALLSPACE;
- bricks.push_back(newBrick);
- }
- }
- }
-
- void Breakout::bricksLevel2(void) {
- Brick newBrick;
- newBrick.width = (WALLWIDTH - (WALLCOLS - 2) * WALLSPACE) / WALLCOLS;
- newBrick.height = (WALLHEIGHT - (WALLROWS - 2) * WALLSPACE) / WALLROWS;
-
- for (int i = 0; i < WALLROWS; i++) {
- for (int j = 0; j < WALLCOLS; j++) {
- // Set stronger bricks
- if (i == 1 || i == WALLROWS - 2 || j == 1 || j == WALLCOLS - 2) {
- newBrick.r = 1.0f;
- newBrick.g = 0.5f;
- newBrick.b = 0.5f;
- newBrick.health = 2;
- } else {
- newBrick.r = 0.95f;
- newBrick.g = 0.95f;
- newBrick.b = 0.95f;
- newBrick.health = 1;
- }
-
- newBrick.xpos = WALLX + j * newBrick.width + j * WALLSPACE;
- newBrick.ypos = WALLY + i * newBrick.height + i * WALLSPACE;
- bricks.push_back(newBrick);
- }
- }
- }
-
- void Breakout::drawGameStats(void) {
- glBegin(GL_LINES);
- // Bottom right (red)
- glColor3f(1.0f, 0.0f, 0.0f);
- glVertex2f(20.0f, 30.0f);
- glVertex2f(WINWIDTH - 20.0f, 30.0f);
- glEnd();
-
- float offset = 25.0f;
- for (int i = 0; i < lifesCount & i < 10; ++i) {
- drawLife(35 + offset * i, 15);
- }
-
- drawScore();
- }
-
- void Breakout::drawLife(float x, float y) {
- // Scale the heart symbol
- float const scale = 0.5f;
-
- // Heart symbol equations from Walfram Mathworld: http://mathworld.wolfram.com/HeartCurve.html
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glBegin(GL_POLYGON);
- glColor3f(1.0f, 0.2f, 0.2f);
- for(int j = 0; j < CIRCLE_SEGMENTS; j++) {
- float const theta = 2.0f * 3.1415926f * (float)j / (float)CIRCLE_SEGMENTS;
- float const xx = scale * 16.0f * sinf(theta) * sinf(theta) * sinf(theta);
- float const yy = -1 * scale * (13.0f * cosf(theta) - 5.0f * cosf(2.0f * theta) - 2 * cosf(3.0f * theta) - cosf(4.0f * theta));
- glVertex2f(x + xx, y + yy);
- }
- glEnd();
- }
-
- void Breakout::drawScore(void) {
- glPushMatrix();
- // Write score word
- glColor3f(1.0f, 0.7f, 0.7f);
- glRasterPos2f(WINWIDTH - 120, 20);
- char buf[300], *p;
- p = buf;
- sprintf(buf, "Score: ");
- do glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *p); while(*(++p));
- // Print the score
- p = buf;
- sprintf(buf, " %d", score);
- glColor3f(1.0f, 0.2f, 0.2f);
- glRasterPos2f(WINWIDTH - 120, 20);
- do glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *p); while(*(++p));
- glPopMatrix();
- }
-
- void Breakout::drawCoordinate(void) {
- glBegin(GL_LINES);
- // Top left (white)
- glColor3f(1.0f, 1.0f, 1.0f);
- glVertex2f(20.0f, 10.0f);
- glVertex2f(20.0f, 30.0f);
- glVertex2f(10.0f, 20.0f);
- glVertex2f(30.0f, 20.0f);
-
- // Bottom right (red)
- glColor3f(1.0f, 0.0f, 0.0f);
- glVertex2f(WINWIDTH - 20.0f, WINHEIGHT - 10.0f);
- glVertex2f(WINWIDTH - 20.0f, WINHEIGHT - 30.0f);
- glVertex2f(WINWIDTH - 10.0f, WINHEIGHT - 20.0f);
- glVertex2f(WINWIDTH - 30.0f, WINHEIGHT - 20.0f);
- glEnd();
- }
-
- void Breakout::reshape(int width, int height) {
- if (width != WINWIDTH || height != WINHEIGHT)
- glutReshapeWindow(WINWIDTH, WINHEIGHT);
- }
-
- void Breakout::mouseClick(int button, int state, int x, int y) {
- if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
- newBall(x, y);
- }
-
- // Force redraw
- glutPostRedisplay();
- }
-
- void Breakout::mouseMove(int x, int y) {
- y = WINHEIGHT - y;
- if (x - paddle.width / 2.0f >= 0 && x + paddle.width / 2.0f <= WINWIDTH) {
- paddle.xpos = x - paddle.width / 2.0f;
- } else if (x - paddle.width / 2.0f <= 0) {
- paddle.xpos = 0;
- } else if (x + paddle.width / 2.0f >= WINWIDTH) {
- paddle.xpos = WINWIDTH - paddle.width;
- }
- glutPostRedisplay();
- }
-
- void Breakout::keyStroke(unsigned char key, int x, int y) {
- switch (key) {
- case 'q': // Exit
- exit(0);
- break;
- case 'n': // New game
- init();
- break;
- case 'h':
- lifesCount++;
- break;
- case 27: // Esc button
- exit(0);
- break;
- default:
- break;
- }
- }
-
- void Breakout::specialKeyPos(int key, int x, int y) {
- switch(key)
- {
- case GLUT_KEY_LEFT:
- if (paddle.xpos > 0) {
- paddle.xpos -= 5.0f;
- paddle.xpos -= 5.0f;
- glutPostRedisplay();
- paddle.xpos -= 5.0f;
- paddle.xpos -= 5.0f;
- glutPostRedisplay();
- }
- break;
- case GLUT_KEY_RIGHT:
- if (paddle.xpos + paddle.width < WINWIDTH) {
- paddle.xpos += 5.0f;
- paddle.xpos += 5.0f;
- glutPostRedisplay();
- paddle.xpos += 5.0f;
- paddle.xpos += 5.0f;
- glutPostRedisplay();
- }
- break;
- default:
- break;
- }
- }
|