#include <GL/glut.h>
#include<iostream>
#include<ctime>
#include<sstream>
#include<windows.h>
using namespace std;
// Game state
enum { MENU, GAME, END };
int width=800, height=600; // Window params
int gamestate = MENU; // Game state
int score1=0, score2=0; // Scores of 2 players
int winScore=10; // Score to win
bool keyStates[256] = { 0 }; // Key presses
// Board params
double board1x=20, board2x=770;
double board1y=450, board2y=450;
double boardWidth=10, boardHeight=100;
double boardSpeed = 12;
// Ball params
bool ballUp = true;
bool ballRight = true;
double ballSpeed = 8;
double ballCurSpeed = ballSpeed; //Speed just after hitting a board (fn of distance from center) Max value = 2*ballSpeed
double ballSize = 10;
double ballX = board1x + boardWidth;
double ballY = board1y - boardHeight/2;
// Misc params
time_t start;
int timePassed = 0;
bool miss1,miss2;
string self("by Max");
string text("Press RETURN to start");
string ins1("Player 1 - keys Q,A");
string ins2("Player 2 - keys P,L");
string rule("First to score 10 wins!");
string miss("MISS!");
string win1("Player 1 wins!");
string win2("Player 2 wins!");
string playagain("Play again (RETURN)");
string reset("Reset (Spacebar)");
void ball(); // Draws ball
void ballOperations(); // Moves ball
void board(double,double); // Draws boards
void cube(); // Draws cube
void drawTitle(); // Draws menu
void drawString(string,double,double); // Draws a string
void init();
void keyOperations();
void display();
void keyboardDown();
void keyboardUp();
void idle();
void resetState() {
ballUp = true;
ballRight = true;
ballSpeed = 10;
ballCurSpeed = ballSpeed;
ballSize = 10;
ballX = board1x + boardWidth;
ballY = board1y - boardHeight/2;
score1=0;
score2=0;
}
void ball() {
glColor3f(1,1,1);
glBegin(GL_POLYGON);
glVertex2d(ballX,ballY);
glVertex2d(ballX+ballSize,ballY);
glVertex2d(ballX+ballSize,ballY-ballSize);
glVertex2d(ballX,ballY-ballSize);
glEnd();
}
void board(double boardx, double boardy) {
glColor3f(1,1,1);
glBegin(GL_POLYGON);
glVertex2d(boardx,boardy);
glVertex2d(boardx+boardWidth,boardy);
glVertex2d(boardx+boardWidth,boardy-boardHeight);
glVertex2d(boardx,boardy-boardHeight);
glEnd();
}
void ballOperations() {
miss1 = false;
miss2 = false;
// Player 1 miss
if(ballX < 0) {
score2++;
ballCurSpeed = ballSpeed;
if(score2==winScore) {
gamestate = END;
return;
}
ballX = board1x + boardWidth;
ballY = board1y - boardHeight/2;
ballRight = true;
miss1 = true;
display();
Sleep(1000);
}
// Player 2 miss
if(ballX > 800) {
score1++;
ballCurSpeed = ballSpeed;
if(score1==winScore) {
gamestate = END;
return;
}
ballX = board2x - ballSize;
ballY = board2y - boardHeight/2;
ballRight = false;
miss2 = true;
display();
Sleep(1000);
}
// Board-ball collision
if(ballX < board1x+boardWidth && ballY-ballSize < board1y && ballY > board1y-100) {
ballRight = !ballRight;
ballCurSpeed = ballSpeed + ballSpeed * abs( board1y-(boardHeight/2)-ballY ) / (boardHeight/2+ballSize) ;
ballX += ballCurSpeed; // Just to be safe after a collision
}
if(ballX+ballSize > board2x && ballY-ballSize < board2y && ballY > board2y-100) {
ballRight = !ballRight;
ballCurSpeed = ballSpeed + ballSpeed * abs( board2y-(boardHeight/2)-ballY ) / (boardHeight/2+ballSize) ;
ballX -= ballCurSpeed; // Just to be safe after a collision
}
// Top-bottom collison detection
if(ballY > height) //collide top
ballUp = !ballUp;
if(ballY < ballSize) //collide bottom
ballUp = !ballUp;
// Code to move the ball
if(ballRight)
ballX += ballCurSpeed;
else
ballX -= ballCurSpeed;
if(ballUp)
ballY += ballCurSpeed;
else
ballY -= ballCurSpeed;
}
void cube(int x, int y) {
glColor3f(1,1,1);
glBegin(GL_POLYGON);
glVertex2d(x,y);
glVertex2d(x,y+20);
glVertex2d(x+20,y+20);
glVertex2d(x+20,y);
glEnd();
}
void drawTitle() {
// Dirty way to draw "PONG"
cube(200,500); cube(220,500); cube(240,500); cube(260,500); cube(260,480); cube(260,460); cube(240,460); cube(220,460);
cube(200,460); cube(200,480); cube(200,460); cube(200,440); cube(200,420);
cube(300,500); cube(320,500); cube(340,500); cube(360,500); cube(300,480); cube(300,460); cube(300,440); cube(300,420);
cube(360,480); cube(360,460); cube(360,440); cube(360,420); cube(300,420); cube(320,420); cube(340,420); cube(360,420);
cube(400,500); cube(400,480); cube(400,460); cube(400,440); cube(400,420); cube(420,480); cube(440,460); cube(460,440);
cube(480,500); cube(480,480); cube(480,460); cube(480,440); cube(480,420);
cube(520,500); cube(540,500); cube(560,500); cube(580,500); cube(520,480); cube(520,460); cube(520,440); cube(520,420);
cube(540,420); cube(560,420); cube(580,420); cube(580,440); cube(580,460); cube(560,460);
// "by Max"
drawString(self,530,400);
}
void drawString(string s, double x, double y) {
glRasterPos2f(x,y);
for(int i=0 ; i<s.length() ; i++)
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, s.at(i));
}
void init (void) {
glClearColor (0,0,0,0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,width,0,height);
}
void keyOperations() {
// 13=RETURN, 27=ESC
if(keyStates[13] && gamestate == MENU) {
resetState();
gamestate = GAME;
}
if(keyStates[27] && gamestate == MENU)
exit(0);
if(keyStates[32] && gamestate == GAME)
gamestate = MENU;
if(keyStates[32] && gamestate == END) {
resetState();
gamestate = MENU;
}
if(keyStates[13] && gamestate == END) {
resetState();
gamestate = GAME;
}
//Move boards
if(keyStates['q'])
if(board1y < 600)
board1y+=boardSpeed;
if(keyStates['a'])
if(board1y > 100)
board1y-=boardSpeed;
if(keyStates['p'])
if(board2y < 600)
board2y+=boardSpeed;
if(keyStates['l'])
if(board2y > 100)
board2y-=boardSpeed;
}
void display (void) {
glClear(GL_COLOR_BUFFER_BIT);
keyOperations();
switch(gamestate) {
case MENU:
// Draw menu
drawTitle();
drawString(ins1,300,300);
drawString(ins2,300,250);
drawString(rule,300,200);
// Blink
if(timePassed % 2 == 0)
drawString(text,290,100);
break;
case GAME:
if(miss1) drawString(miss,100,50); //if miss
if(miss2) drawString(miss,600,50);
ballOperations(); // Move ball
ball(); // Draw ball
board(board1x, board1y); // Draw boards
board(board2x, board2y);
glBegin(GL_LINES); // Center line
glVertex2i(400,0);
glVertex2i(400,600);
glEnd();
// Draw score
{
string number;
stringstream conv1;
conv1<<score1;
number = conv1.str();
drawString(number,330,550);
stringstream conv2;
conv2<<score2;
number = conv2.str();
drawString(number,450,550);
}
break;
case END:
// Draw winner
if(score1 == winScore)
drawString(win1,50,400);
else
drawString(win2,550,400);
// Draw options
drawString(playagain,300,200);
drawString(reset,300,100);
break;
}
glutSwapBuffers();
}
void keyboardDown(unsigned char key, int x, int y) {
keyStates[key] = true;
}
void keyboardUp(unsigned char key, int x, int y) {
keyStates[key] = false;
}
void idle() {
glutPostRedisplay();
timePassed = static_cast<int>(clock()-start)/CLOCKS_PER_SEC;
}
int main (int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE);
glutInitWindowSize(width, height);
glutInitWindowPosition (0, 0);
glutCreateWindow("Pong by Max");
init();
glutDisplayFunc(display);
glutIdleFunc(idle);
glutKeyboardFunc(keyboardDown);
glutKeyboardUpFunc(keyboardUp);
start = clock();
glutMainLoop();
return 0;
}