#include <stdio.h>
#include <stdlib.h>
+#include <math.h>
-enum {
- FRAME=40,
- HEIGHT=100,
- PADDLESIZE=10
-};
+// Amount to increase speed by on x, y axis, and when bouncing
+#define SPEEDXINC 1.1
+#define SPEEDYINC 1.1
+#define SPEEDBINC 0.15
+#define PADDLESPEED 3.0
+#define FRAME 40
+#define PADDLESIZE 10
+#define HEIGHT 100
-static int score1;
-static int score2;
-static GLdouble paddle1;
-static GLdouble paddle2;
-static GLdouble ballX;
-static GLdouble ballY;
-static GLdouble ballVecX;
-static GLdouble ballVecY;
+#define STATE_UI 0
+#define STATE_1P 1
+#define STATE_2P 2
+static char* menu = "";
+static int state = 0;
+static int p1move = 0;
+static int p2move = 0;
+static int score1 = 0;
+static int score2 = 0;
+static GLdouble paddle1 = 0.0;
+static GLdouble paddle2 = 0.0;
+static GLdouble ballX = 0.0;
+static GLdouble ballY = 0.0;
+static GLdouble ballVecX = 0.0;
+static GLdouble ballVecY = 0.0;
-static void initball(void) {
+
+static inline double myfmax(double a, double b) {
+ return a > b ? a : b;
+}
+
+static void initBall(void) {
ballX = 0.0;
ballY = 0.0;
if(ballVecX < 0)
- ballVecX = -1.0;
+ ballVecX = -1.2;
else
- ballVecX = 1.0;
- ballVecY = 1.0;
+ ballVecX = 1.2;
+ ballVecY = 0.7;
}
static void run(void) {
+ // AI is on
+ if(state == STATE_1P) {
+ if(ballY < paddle2 - PADDLESIZE)
+ p2move = -1;
+ else if(ballY > paddle2 + PADDLESIZE)
+ p2move = 1;
+ else
+ p2move = 0;
+ }
+
+ // Move the paddles
+ paddle1 += p1move * PADDLESPEED;
+ paddle2 += p2move * PADDLESPEED;
+ if(paddle1 < -HEIGHT)
+ paddle1 = -HEIGHT;
+ if(paddle1 > HEIGHT)
+ paddle1 = HEIGHT;
+ if(paddle2 < -HEIGHT)
+ paddle2 = -HEIGHT;
+ if(paddle2 > HEIGHT)
+ paddle2 = HEIGHT;
+
// Check for collisions with paddles
if(ballVecX < 0 && ballX <= -HEIGHT + -ballVecX * 1.5) {
if(ballY >= paddle1 - PADDLESIZE && ballY <= paddle1 + PADDLESIZE) {
- ballVecX *= -1.15;
- ballVecY *= 1.15;
+ GLdouble speedChange = myfmax(1.0, fabs(paddle1 - ballY) * SPEEDBINC);
+ ballVecX *= -speedChange * SPEEDXINC;
+ ballVecY *= speedChange * SPEEDYINC;
}
}
if(ballVecX > 0 && ballX >= HEIGHT - ballVecX * 1.5) {
if(ballY >= paddle2 - PADDLESIZE && ballY <= paddle2 + PADDLESIZE) {
- ballVecX *= -1.15;
- ballVecY *= 1.15;
+ GLdouble speedChange = myfmax(1.0, fabs(paddle2 - ballY) * SPEEDBINC);
+ ballVecX *= -speedChange * SPEEDXINC;
+ ballVecY *= speedChange * SPEEDYINC;
}
}
// Check if it's past the top or bottom of the screen
if(ballY >= HEIGHT || ballY <= -HEIGHT) {
- ballVecY *= -1;
+ ballVecY = -ballVecY;
}
// Check if it's past the sides of the screen
if(ballX >= HEIGHT) {
++score1;
- initball();
- return;
+ initBall();
}
if(ballX <= -HEIGHT) {
++score2;
- initball();
- return;
+ initBall();
}
// Move the ball
ballX += ballVecX;
ballY += ballVecY;
+
+ // Check scores for winners..
+ if(score1 == 9) {
+ menu = "Player 1 wins!";
+ state = STATE_UI;
+ score1 = score2 = 0;
+ }
+ if(score2 == 9) {
+ menu = "Player 2 wins!";
+ state = STATE_UI;
+ score1 = score2 = 0;
+ }
}
-static void display(void) {
- glClear(GL_COLOR_BUFFER_BIT);
- glColor3d(0.0, 0.0, 0.0);
+static void timer(int lastTime) {
+ if(state == STATE_UI) {
+ return;
+ }
+
+ int curTime = glutGet(GLUT_ELAPSED_TIME);
+ do {
+ lastTime += FRAME;
+ run();
+ } while(lastTime + FRAME < curTime);
+ glutPostRedisplay();
+ glutTimerFunc(FRAME - (curTime - lastTime), timer, curTime);
+}
+
+static void startGame(void) {
+ glutTimerFunc(FRAME, timer, glutGet(GLUT_ELAPSED_TIME));
+ initBall();
+}
+static void drawText(double x, double y, char* str) {
+ glRasterPos2d(x, y);
+ while(*str) {
+ glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *str);
+ ++str;
+ }
+}
+
+static void menuDisplay(void) {
+ drawText(-20, 50, "Awesome PONG!");
+ drawText(-50, -50, "Press 1 for a single player game.");
+ drawText(-50, -60, "Press 2 for a multi player game.");
+ drawText(-50, -70, "Keys: w/s and i/k");
+ drawText(-20, 0, menu);
+}
+
+static void gameDisplay(void) {
// Draw the paddles
glLineWidth(2.0);
glBegin(GL_LINES);
glEnd();
// Draw the ball
- glPointSize(5.0);
- glBegin(GL_POINTS);
+ glBegin(GL_LINES);
glVertex2d(ballX, ballY);
+ glVertex2d(ballX - ballVecX, ballY - ballVecY);
glEnd();
// Write the score
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, '0' + score1);
glRasterPos2d( 5.0, HEIGHT - 10.0);
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, '0' + score2);
+}
+
+static void display(void) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColor3d(0.0, 0.0, 0.0);
+
+ if(state == STATE_UI) {
+ menuDisplay();
+ } else {
+ gameDisplay();
+ }
glutSwapBuffers();
}
glOrtho(-HEIGHT, HEIGHT, -HEIGHT, HEIGHT, -1.0, 1.0);
}
-static void keyboard(unsigned char key, int x, int y) {
- (void)x;(void)y;
-
+static void menuKeyboard(unsigned char key) {
switch(key) {
- case 'q':
- case 'Q':
- case '\033':
- exit(0);
+ case '1':
+ state = STATE_1P;
+ break;
+
+ case '2':
+ state = STATE_2P;
+ break;
+ default:
+ return;
+ }
+ startGame();
+}
+
+static void gameKeyboard(unsigned char key) {
+ switch(key) {
case 'w':
- if(paddle1 + PADDLESIZE < HEIGHT)
- paddle1 += PADDLESIZE;
+ p1move = 1;
break;
case 's':
- if(paddle1 - PADDLESIZE > -HEIGHT)
- paddle1 -= PADDLESIZE;
+ p1move = -1;
break;
case 'i':
- if(paddle2 + PADDLESIZE < HEIGHT)
- paddle2 += PADDLESIZE;
+ p2move = 1;
break;
case 'k':
- if(paddle2 - PADDLESIZE > -HEIGHT)
- paddle2 -= PADDLESIZE;
+ p2move = -1;
break;
default:
glutPostRedisplay();
}
-static void timer(int lastTime) {
- int curTime = glutGet(GLUT_ELAPSED_TIME);
- do {
- lastTime += FRAME;
- run();
- } while(lastTime + FRAME < curTime);
- glutPostRedisplay();
- glutTimerFunc(FRAME - (curTime - lastTime), timer, curTime);
+static void keyboard(unsigned char key, int x, int y) {
+ (void)x;(void)y;
+
+ switch(key) {
+ case 'q':
+ case 'Q':
+ case '\033':
+ exit(0);
+ }
+
+
+ if(state == STATE_UI) {
+ menuKeyboard(key);
+ } else {
+ gameKeyboard(key);
+ }
}
-static void init(void) {
- glClearColor(1.0, 1.0, 1.0, 0.0);
- initball();
+static void keyboardUp(unsigned char key, int x, int y) {
+ (void)x;(void)y;
+
+ switch(key) {
+ case 'w':
+ case 's':
+ p1move = 0;
+ break;
+
+ case 'i':
+ case 'k':
+ p2move = 0;
+ p2move = 0;
+ break;
+ }
}
int main(int argc, char *argv[]) {
glutDisplayFunc(display);
glutReshapeFunc(resize);
glutKeyboardFunc(keyboard);
- glutTimerFunc(FRAME, timer, glutGet(GLUT_ELAPSED_TIME));
- init();
+ glutKeyboardUpFunc(keyboardUp);
+ glClearColor(1.0, 1.0, 1.0, 0.0);
glutMainLoop();
return 0;
}