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