]> code.delx.au - pong/blobdiff - pong.c
The ball is now a slug.
[pong] / pong.c
diff --git a/pong.c b/pong.c
index 5f5ccf7c3421c59752e8e99354d0c5ace622e14c..4ecaa8a3664e024c3746556efc315ef90cde4e6f 100644 (file)
--- a/pong.c
+++ b/pong.c
 
 #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 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 = fmax(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 = fmax(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);
@@ -87,9 +165,9 @@ static void display(void) {
        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
@@ -97,6 +175,17 @@ static void display(void) {
        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();
 }
@@ -107,31 +196,36 @@ static void resize(int w, int h) {
        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:
@@ -140,19 +234,39 @@ static void keyboard(unsigned char key, int x, int y) {
        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[]) {
@@ -164,8 +278,8 @@ 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;
 }