]> code.delx.au - pong/blob - pong.c
Optional AI, scores now reset when they hit 9
[pong] / pong.c
1 #if defined(WIN32)
2 #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
3 #include "glut.h"
4 #elif defined(__APPLE__) || defined(MACOSX)
5 #include <GLUT/glut.h>
6 #else
7 #include <GL/glut.h>
8 #endif
9
10 #include <stdio.h>
11 #include <stdlib.h>
12
13 #define SPEEDINC 1.15
14 #define PADDLESPEED 2.5
15 #define FRAME 40
16 #define PADDLESIZE 10
17 #define HEIGHT 100
18
19 static int AI = 0;
20 static int p1move = 0;
21 static int p2move = 0;
22 static int score1 = 0;
23 static int score2 = 0;
24 static GLdouble paddle1 = 0.0;
25 static GLdouble paddle2 = 0.0;
26 static GLdouble ballX = 0.0;
27 static GLdouble ballY = 0.0;
28 static GLdouble ballVecX = 0.0;
29 static GLdouble ballVecY = 0.0;
30
31
32 static void initball(void) {
33 ballX = 0.0;
34 ballY = 0.0;
35 if(ballVecX < 0)
36 ballVecX = -1.2;
37 else
38 ballVecX = 1.2;
39 ballVecY = 0.7;
40 }
41
42 static void run(void) {
43 // AI
44 if(AI) {
45 if(ballY < paddle2 - PADDLESIZE)
46 p2move = -1;
47 else if(ballY > paddle2 + PADDLESIZE)
48 p2move = 1;
49 else
50 p2move = 0;
51 }
52
53 // Move the paddles
54 paddle1 += p1move * PADDLESPEED;
55 paddle2 += p2move * PADDLESPEED;
56
57 // Check for collisions with paddles
58 if(ballVecX < 0 && ballX <= -HEIGHT + -ballVecX * 1.5) {
59 if(ballY >= paddle1 - PADDLESIZE && ballY <= paddle1 + PADDLESIZE) {
60 ballVecX *= -SPEEDINC;
61 ballVecY *= SPEEDINC;
62 }
63 }
64 if(ballVecX > 0 && ballX >= HEIGHT - ballVecX * 1.5) {
65 if(ballY >= paddle2 - PADDLESIZE && ballY <= paddle2 + PADDLESIZE) {
66 ballVecX *= -SPEEDINC;
67 ballVecY *= SPEEDINC;
68 }
69 }
70
71 // Check if it's past the top or bottom of the screen
72 if(ballY >= HEIGHT || ballY <= -HEIGHT) {
73 ballVecY = -ballVecY;
74 }
75
76 // Check if it's past the sides of the screen
77 if(ballX >= HEIGHT) {
78 ++score1;
79 initball();
80 }
81 if(ballX <= -HEIGHT) {
82 ++score2;
83 initball();
84 }
85
86 // Move the ball
87 ballX += ballVecX;
88 ballY += ballVecY;
89
90 // Check scores for winners..
91 if(score1 == 9) {
92 // Player 1 wins
93 score1 = score2 = 0;
94 }
95 if(score2 == 9) {
96 // Player 2 wins
97 score1 = score2 = 0;
98 }
99 }
100
101 static void display(void) {
102 glClear(GL_COLOR_BUFFER_BIT);
103 glColor3d(0.0, 0.0, 0.0);
104
105 // Draw the paddles
106 glLineWidth(2.0);
107 glBegin(GL_LINES);
108 glVertex2d(-HEIGHT + 1, paddle1 - PADDLESIZE);
109 glVertex2d(-HEIGHT + 1, paddle1 + PADDLESIZE);
110 glVertex2d( HEIGHT - 1, paddle2 + PADDLESIZE);
111 glVertex2d( HEIGHT - 1, paddle2 - PADDLESIZE);
112 glEnd();
113
114 // Draw the ball
115 glPointSize(5.0);
116 glBegin(GL_POINTS);
117 glVertex2d(ballX, ballY);
118 glEnd();
119
120 // Write the score
121 glRasterPos2d(-5.0, HEIGHT - 10.0);
122 glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, '0' + score1);
123 glRasterPos2d( 5.0, HEIGHT - 10.0);
124 glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, '0' + score2);
125
126 glutSwapBuffers();
127 }
128
129 static void resize(int w, int h) {
130 glViewport(0, 0, w, h);
131 glLoadIdentity();
132 glOrtho(-HEIGHT, HEIGHT, -HEIGHT, HEIGHT, -1.0, 1.0);
133 }
134
135 static void keyboard(unsigned char key, int x, int y) {
136 (void)x;(void)y;
137
138 switch(key) {
139 case 'q':
140 case 'Q':
141 case '\033':
142 exit(0);
143
144 case 'w':
145 p1move = 1;
146 break;
147 case 's':
148 p1move = -1;
149 break;
150
151 case 'i':
152 p2move = 1;
153 break;
154 case 'k':
155 p2move = -1;
156 break;
157
158 default:
159 return;
160 }
161 glutPostRedisplay();
162 }
163
164 static void keyboardUp(unsigned char key, int x, int y) {
165 (void)x;(void)y;
166
167 switch(key) {
168 case 'w':
169 case 's':
170 p1move = 0;
171 break;
172
173 case 'i':
174 case 'k':
175 p2move = 0;
176 p2move = 0;
177 break;
178 }
179 }
180
181 static void timer(int lastTime) {
182 int curTime = glutGet(GLUT_ELAPSED_TIME);
183 do {
184 lastTime += FRAME;
185 run();
186 } while(lastTime + FRAME < curTime);
187 glutPostRedisplay();
188 glutTimerFunc(FRAME - (curTime - lastTime), timer, curTime);
189 }
190
191 static void init(void) {
192 glClearColor(1.0, 1.0, 1.0, 0.0);
193 initball();
194 }
195
196 int main(int argc, char *argv[]) {
197 if(argc == 2 && *argv[1] == '1') {
198 AI = 1;
199 }
200
201 glutInitWindowPosition(100, 100);
202 glutInitWindowSize(640, 480);
203 glutInit(&argc, argv);
204 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
205 glutCreateWindow(argv[0]);
206 glutDisplayFunc(display);
207 glutReshapeFunc(resize);
208 glutKeyboardFunc(keyboard);
209 glutKeyboardUpFunc(keyboardUp);
210 glutTimerFunc(FRAME, timer, glutGet(GLUT_ELAPSED_TIME));
211 init();
212 glutMainLoop();
213 return 0;
214 }
215