]> code.delx.au - pong/blob - pong.c
4ecaa8a3664e024c3746556efc315ef90cde4e6f
[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 #include <math.h>
13
14 // Amount to increase speed by on x, y axis, and when bouncing
15 #define SPEEDXINC 1.1
16 #define SPEEDYINC 1.1
17 #define SPEEDBINC 0.15
18 #define PADDLESPEED 3.0
19 #define FRAME 40
20 #define PADDLESIZE 10
21 #define HEIGHT 100
22
23 #define STATE_UI 0
24 #define STATE_1P 1
25 #define STATE_2P 2
26
27 static char* menu = "";
28 static int state = 0;
29 static int p1move = 0;
30 static int p2move = 0;
31 static int score1 = 0;
32 static int score2 = 0;
33 static GLdouble paddle1 = 0.0;
34 static GLdouble paddle2 = 0.0;
35 static GLdouble ballX = 0.0;
36 static GLdouble ballY = 0.0;
37 static GLdouble ballVecX = 0.0;
38 static GLdouble ballVecY = 0.0;
39
40
41 static void initBall(void) {
42 ballX = 0.0;
43 ballY = 0.0;
44 if(ballVecX < 0)
45 ballVecX = -1.2;
46 else
47 ballVecX = 1.2;
48 ballVecY = 0.7;
49 }
50
51 static void run(void) {
52 // AI is on
53 if(state == STATE_1P) {
54 if(ballY < paddle2 - PADDLESIZE)
55 p2move = -1;
56 else if(ballY > paddle2 + PADDLESIZE)
57 p2move = 1;
58 else
59 p2move = 0;
60 }
61
62 // Move the paddles
63 paddle1 += p1move * PADDLESPEED;
64 paddle2 += p2move * PADDLESPEED;
65 if(paddle1 < -HEIGHT)
66 paddle1 = -HEIGHT;
67 if(paddle1 > HEIGHT)
68 paddle1 = HEIGHT;
69 if(paddle2 < -HEIGHT)
70 paddle2 = -HEIGHT;
71 if(paddle2 > HEIGHT)
72 paddle2 = HEIGHT;
73
74 // Check for collisions with paddles
75 if(ballVecX < 0 && ballX <= -HEIGHT + -ballVecX * 1.5) {
76 if(ballY >= paddle1 - PADDLESIZE && ballY <= paddle1 + PADDLESIZE) {
77 GLdouble speedChange = fmax(1.0, fabs(paddle1 - ballY) * SPEEDBINC);
78 ballVecX *= -speedChange * SPEEDXINC;
79 ballVecY *= speedChange * SPEEDYINC;
80 }
81 }
82 if(ballVecX > 0 && ballX >= HEIGHT - ballVecX * 1.5) {
83 if(ballY >= paddle2 - PADDLESIZE && ballY <= paddle2 + PADDLESIZE) {
84 GLdouble speedChange = fmax(1.0, fabs(paddle2 - ballY) * SPEEDBINC);
85 ballVecX *= -speedChange * SPEEDXINC;
86 ballVecY *= speedChange * SPEEDYINC;
87 }
88 }
89
90 // Check if it's past the top or bottom of the screen
91 if(ballY >= HEIGHT || ballY <= -HEIGHT) {
92 ballVecY = -ballVecY;
93 }
94
95 // Check if it's past the sides of the screen
96 if(ballX >= HEIGHT) {
97 ++score1;
98 initBall();
99 }
100 if(ballX <= -HEIGHT) {
101 ++score2;
102 initBall();
103 }
104
105 // Move the ball
106 ballX += ballVecX;
107 ballY += ballVecY;
108
109 // Check scores for winners..
110 if(score1 == 9) {
111 menu = "Player 1 wins!";
112 state = STATE_UI;
113 score1 = score2 = 0;
114 }
115 if(score2 == 9) {
116 menu = "Player 2 wins!";
117 state = STATE_UI;
118 score1 = score2 = 0;
119 }
120 }
121
122 static void timer(int lastTime) {
123 if(state == STATE_UI) {
124 return;
125 }
126
127 int curTime = glutGet(GLUT_ELAPSED_TIME);
128 do {
129 lastTime += FRAME;
130 run();
131 } while(lastTime + FRAME < curTime);
132 glutPostRedisplay();
133 glutTimerFunc(FRAME - (curTime - lastTime), timer, curTime);
134 }
135
136 static void startGame(void) {
137 glutTimerFunc(FRAME, timer, glutGet(GLUT_ELAPSED_TIME));
138 initBall();
139 }
140
141 static void drawText(double x, double y, char* str) {
142 glRasterPos2d(x, y);
143 while(*str) {
144 glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *str);
145 ++str;
146 }
147 }
148
149 static void menuDisplay(void) {
150 drawText(-20, 50, "Awesome PONG!");
151 drawText(-50, -50, "Press 1 for a single player game.");
152 drawText(-50, -60, "Press 2 for a multi player game.");
153 drawText(-50, -70, "Keys: w/s and i/k");
154 drawText(-20, 0, menu);
155 }
156
157 static void gameDisplay(void) {
158 // Draw the paddles
159 glLineWidth(2.0);
160 glBegin(GL_LINES);
161 glVertex2d(-HEIGHT + 1, paddle1 - PADDLESIZE);
162 glVertex2d(-HEIGHT + 1, paddle1 + PADDLESIZE);
163 glVertex2d( HEIGHT - 1, paddle2 + PADDLESIZE);
164 glVertex2d( HEIGHT - 1, paddle2 - PADDLESIZE);
165 glEnd();
166
167 // Draw the ball
168 glBegin(GL_LINES);
169 glVertex2d(ballX, ballY);
170 glVertex2d(ballX - ballVecX, ballY - ballVecY);
171 glEnd();
172
173 // Write the score
174 glRasterPos2d(-5.0, HEIGHT - 10.0);
175 glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, '0' + score1);
176 glRasterPos2d( 5.0, HEIGHT - 10.0);
177 glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, '0' + score2);
178 }
179
180 static void display(void) {
181 glClear(GL_COLOR_BUFFER_BIT);
182 glColor3d(0.0, 0.0, 0.0);
183
184 if(state == STATE_UI) {
185 menuDisplay();
186 } else {
187 gameDisplay();
188 }
189
190 glutSwapBuffers();
191 }
192
193 static void resize(int w, int h) {
194 glViewport(0, 0, w, h);
195 glLoadIdentity();
196 glOrtho(-HEIGHT, HEIGHT, -HEIGHT, HEIGHT, -1.0, 1.0);
197 }
198
199 static void menuKeyboard(unsigned char key) {
200 switch(key) {
201 case '1':
202 state = STATE_1P;
203 break;
204
205 case '2':
206 state = STATE_2P;
207 break;
208
209 default:
210 return;
211 }
212 startGame();
213 }
214
215 static void gameKeyboard(unsigned char key) {
216 switch(key) {
217 case 'w':
218 p1move = 1;
219 break;
220 case 's':
221 p1move = -1;
222 break;
223
224 case 'i':
225 p2move = 1;
226 break;
227 case 'k':
228 p2move = -1;
229 break;
230
231 default:
232 return;
233 }
234 glutPostRedisplay();
235 }
236
237 static void keyboard(unsigned char key, int x, int y) {
238 (void)x;(void)y;
239
240 switch(key) {
241 case 'q':
242 case 'Q':
243 case '\033':
244 exit(0);
245 }
246
247
248 if(state == STATE_UI) {
249 menuKeyboard(key);
250 } else {
251 gameKeyboard(key);
252 }
253 }
254
255 static void keyboardUp(unsigned char key, int x, int y) {
256 (void)x;(void)y;
257
258 switch(key) {
259 case 'w':
260 case 's':
261 p1move = 0;
262 break;
263
264 case 'i':
265 case 'k':
266 p2move = 0;
267 p2move = 0;
268 break;
269 }
270 }
271
272 int main(int argc, char *argv[]) {
273 glutInitWindowPosition(100, 100);
274 glutInitWindowSize(640, 480);
275 glutInit(&argc, argv);
276 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
277 glutCreateWindow(argv[0]);
278 glutDisplayFunc(display);
279 glutReshapeFunc(resize);
280 glutKeyboardFunc(keyboard);
281 glutKeyboardUpFunc(keyboardUp);
282 glClearColor(1.0, 1.0, 1.0, 0.0);
283 glutMainLoop();
284 return 0;
285 }
286