PandA-2024.02
main.c
Go to the documentation of this file.
1 
6 #include "plot.h"
7 #include "btn_ctrl.h"
8 #include "get_ticks.h"
9 #include "sevensegments_ctrl.h"
10 
11 // Window related defines
12 #define WINDOW_WIDTH 640
13 #define WINDOW_HEIGHT 480
14 
15 // Game related defines
16 #define FRAMES_PER_SECOND 60
17 #define FRAME_RATE 1000/FRAMES_PER_SECOND
18 
19 // RGB colors
20 #define YELLOW_COLOR 6
21 #define RED_COLOR 4
22 #define BLUE_COLOR 1
23 #define GREEN_COLOR 2
24 #define WHITE_COLOR 7
25 #define BLACK_COLOR 0
26 
27 // Locations of paddles in the game
28 #define COMPUTER_Y 30
29 #define PLAYER_Y 430
30 
31 // Dimensions of a paddle
32 #define PADDLE_WIDTH 32
33 #define PADDLE_HEIGHT 8
34 
35 // Diameter of the ball
36 #define BALL_DIAMETER 8
37 
38 // Paddle speeds
39 #define PLAYER_SPEED 2
40 #define COMPUTER_SPEED 2
41 
42 // Ball speeds
43 #define BALL_SPEED_MODIFIER 4 // divide location on paddle by this
44 #define BALL_SPEED_Y 2 // max speed of ball along y axis
45 
46 #define LEFT 0
47 #define RIGHT 1
48 #define UP 2
49 #define DOWN 3
50 
51 #define sgn(x) ((x<0)?-1:((x>0)?1:0))
52 
53 typedef struct _obj_description
54 {
55  short int x;
56  short int y;
57  short int w;
58  short int h;
60 
61 // Struct that represents an entity in our game
62 typedef struct _entity
63 {
64  obj_description screen_location; // location on screen
65  int x_speed;
66  int y_speed;
67 } entity;
68 
69 // Global data
70 entity computer; // The computer's paddle
71 entity player; // The player's paddle
72 entity ball; // The game ball
73 unsigned char computer_score; // AI's score
74 unsigned char player_score; // player's score
75 static int last_speed = 0;
76 static int decision = 3;
77 int timer; // Game timer
78 
79 // Random functions
80 //taken from http://burtleburtle.net/bob/rand/smallprng.html
81 typedef struct _random_state_t
82 {
83  unsigned int a;
84  unsigned int b;
85  unsigned int c;
86  unsigned int d;
88 
89 #define rot(x,k) (((x)<<(k))|((x)>>(32-(k))))
90 unsigned int random_number( random_state_t *x )
91 {
92  unsigned int e = x->a - rot(x->b, 27);
93  x->a = x->b ^ rot(x->c, 17);
94  x->b = x->c + x->d;
95  x->c = x->d + e;
96  x->d = e + x->a;
97  return x->d;
98 }
99 
100 void random_number_init( random_state_t *x, unsigned int seed )
101 {
102  unsigned int i;
103  x->a = 0xf1ea5eed, x->b = x->c = x->d = seed;
104  for (i=0; i<20; ++i)
105  (void)random_number(x);
106 }
107 
109 
110 unsigned char convert_char_digit_2_sseg(char c)
111 {
112  static unsigned char table[] = {63/*0*/, 6/*1*/, 91/*2*/, 79/*3*/, 102/*4*/, 109/*5*/, 125/*6*/, 7/*7*/, 127/*8*/, 111/*9*/};
113  return table[c-'0'];
114 }
115 
116 
117 void line(int x1, int y1, int x2, int y2, unsigned int color)
118 {
119  int i,dx,dy,sdx,sdy,dxabs,dyabs,x,y,px,py;
120  dx=x2-x1; /* the horizontal distance of the line */
121  dy=y2-y1; /* the vertical distance of the line */
122  dxabs=abs(dx);
123  dyabs=abs(dy);
124  sdx=sgn(dx);
125  sdy=sgn(dy);
126  x=dyabs>>1;
127  y=dxabs>>1;
128  px=x1;
129  py=y1;
130  plot(color,px,py);
131  if (dxabs>=dyabs) /* the line is more horizontal than vertical */
132  {
133  for(i=0; i<dxabs; i++)
134  {
135  y+=dyabs;
136  if (y>=dxabs)
137  {
138  y-=dxabs;
139  py+=sdy;
140  }
141  px+=sdx;
142  plot(color,px,py);
143  }
144  }
145  else /* the line is more vertical than horizontal */
146  {
147  for(i=0; i<dyabs; i++)
148  {
149  x+=dxabs;
150  if (x>=dyabs)
151  {
152  x-=dyabs;
153  px+=sdx;
154  }
155  py+=sdy;
156  plot(color,px,py);
157  }
158  }
159 }
160 
161 void rect(int left,int top, int right, int bottom, unsigned int color)
162 {
163  line(left,top,right,top,color);
164  line(left,top,left,bottom,color);
165  line(right,top,right,bottom,color);
166  line(left,bottom,right,bottom,color);
167 }
168 
169 void circle(int x0, int y0, int radius, unsigned int color)
170 {
171  int x = radius, y = 0;
172  int radiusError = 1-x;
173  while(x >= y)
174  {
175  plot(color,x + x0, y + y0);
176  plot(color,y + x0, x + y0);
177  plot(color,-x + x0, y + y0);
178  plot(color,-y + x0, x + y0);
179  plot(color,-x + x0, -y + y0);
180  plot(color,-y + x0, -x + y0);
181  plot(color,x + x0, -y + y0);
182  plot(color,y + x0, -x + y0);
183  y++;
184  if(radiusError<0)
185  radiusError+=2*y+1;
186  else
187  {
188  x--;
189  radiusError+=2*(y-x+1);
190  }
191  }
192 }
193 
194 void rect_fill(int left,int top, int right, int bottom, unsigned int color)
195 {
196  int currentline;
197  for (currentline=top; currentline<=bottom; currentline++)
198  line(left,currentline,right,currentline,color);
199 }
200 
201 
202 
204 {
205  char a, b, c, d;
206  short int low_byte = player_score;
207  short int high_byte = computer_score;
208  unsigned long long sseg_val = 0;
209  for ( b = '0' - 1; high_byte >= 0; high_byte -= 10 ) ++b;
210  a = '0' + high_byte + 10;
211  sseg_val |= ((unsigned long long)convert_char_digit_2_sseg(a))<<4*8;
212  sseg_val |= ((unsigned long long)convert_char_digit_2_sseg(b))<<5*8;
213  for ( d = '0' - 1; low_byte >= 0; low_byte -= 10 ) ++d;
214  c = '0' + low_byte + 10;
215  sseg_val |= ((unsigned long long)convert_char_digit_2_sseg(c))<<0*8;
216  sseg_val |= ((unsigned long long)convert_char_digit_2_sseg(d))<<1*8;
217  sevensegments_ctrl(sseg_val,~0ULL);
218 }
219 
220 
221 
222 // Check to see if a game object is going to hit the side of the screen
223 _Bool check_wall_collisions(entity *entity, unsigned char dir)
224 {
225  int temp_x=0; // stores the location of the entity after moving
226 
227  // Get the location of the entity after it moves
228  switch (dir)
229  {
230  case LEFT:
231  {
232  temp_x = entity->screen_location.x - entity->x_speed;
233  break;
234  }
235  case RIGHT:
236  {
237  // Notice that we have to add the entities width to get its right(->) coordinate
238  temp_x = entity->screen_location.x + entity->screen_location.w + entity->x_speed;
239  break;
240  }
241  }
242  if ( (temp_x <= 0) || (temp_x >= WINDOW_WIDTH) )
243  return 1;
244  else
245  return 0;
246 }
247 
248 // Check to see if the ball is going to hit a paddle
250 {
251  int ball_x = ball.screen_location.x;
252  int ball_y = ball.screen_location.y;
253  int ball_width = ball.screen_location.w;
254  int ball_height = ball.screen_location.h;
255  int ball_speed = ball.y_speed;
256  int paddle_x = paddle->screen_location.x;
257  int paddle_y = paddle->screen_location.y;
258  int paddle_width = paddle->screen_location.w;
259  int paddle_height = paddle->screen_location.h;
260  // Get which paddle we're checking against
261  if ( paddle->screen_location.y == PLAYER_Y)
262  {
263  // Check to see if ball is in Y range of the player's paddle.
264  // We check its speed to see if it's even moving towards the player's paddle.
265  if ( (ball_speed > 0) && (ball_y + ball_height >= paddle_y) &&
266  (ball_y + ball_height <= paddle_y + paddle_height) ) // side hit
267  {
268  // If ball is in the X range of the paddle, return true.
269  if ( (ball_x <= paddle_x + paddle_width) && (ball_x + ball_width >= paddle_x) )
270  return 1;
271  }
272  }
273  else
274  {
275  // Check to see if ball is in Y range of the computer's paddle.
276  // We check its speed to see if it's even moving towards the computer's paddle.
277  if ( (ball_speed < 0) && (ball_y >= paddle_y) &&
278  (ball_y <= paddle_y + paddle_height) )
279  {
280  // If ball is in the X range of the paddle, return true.
281  if ( (ball_x <= paddle_x + paddle_width) && (ball_x + ball_width >= paddle_x) )
282  return 1;
283  }
284  }
285  return 0;
286 }
287 
288 
289 void move_ball()
290 {
291  ball.screen_location.x += ball.x_speed;
292  ball.screen_location.y += ball.y_speed;
293  // If the ball is moving left, we see if it hits the wall. If does,
294  // we change its direction. We do the same thing if it's moving right.
295  if ( ( (ball.x_speed < 0) && check_wall_collisions(&ball, LEFT) ) ||
296  ( (ball.x_speed > 0) && check_wall_collisions(&ball, RIGHT) ) )
297  ball.x_speed = -ball.x_speed;
298 }
299 
300 // Increase the player's score, reset ball, and see if player has won.
302 {
303  // Increase score
304  player_score++;
305  // Reset ball
306  ball.x_speed = 0;
307  ball.y_speed = 0;
308  ball.screen_location.x = (WINDOW_WIDTH / 2) - (BALL_DIAMETER / 2);
309  ball.screen_location.y = (WINDOW_HEIGHT / 2) - (BALL_DIAMETER / 2);
310  // Check to see if player has won
311  if (player_score == 10)
312  {
313  computer_score = 0;
314  player_score = 0;
315  return 1;
316  }
317  return 0;
318 }
319 
320 // Increase computer's score, reset ball, and see it if computer has won.
322 {
323  // Increase score
324  computer_score++;
325  // Reset ball
326  ball.x_speed = 0;
327  ball.y_speed = 0;
328  ball.screen_location.x = (WINDOW_WIDTH / 2) - (BALL_DIAMETER / 2);
329  ball.screen_location.y = (WINDOW_HEIGHT / 2) - (BALL_DIAMETER / 2);
330  // See if computer has won
331  if (computer_score == 10)
332  {
333  computer_score = 0;
334  player_score = 0;
335  return 1;
336  }
337  return 0;
338 }
339 
340 
341 // This function initializes the game.
343 {
344  // Initialize the screen locations of two paddles and the ball
345  computer.screen_location.x = (WINDOW_WIDTH / 2) - (PADDLE_WIDTH / 2); // center screen
346  computer.screen_location.y = COMPUTER_Y;
347  computer.screen_location.w = PADDLE_WIDTH;
348  computer.screen_location.h = PADDLE_HEIGHT;
349  player.screen_location.x = (WINDOW_WIDTH / 2) - (PADDLE_WIDTH / 2); // center screen
350  player.screen_location.y = PLAYER_Y;
351  player.screen_location.w = PADDLE_WIDTH;
353  ball.screen_location.x = (WINDOW_WIDTH / 2) - (BALL_DIAMETER / 2); // center screen
354  ball.screen_location.y = (WINDOW_HEIGHT / 2) - (BALL_DIAMETER / 2); // center screen
357  // Initialize speeds
358  computer.x_speed = COMPUTER_SPEED;
359  player.x_speed = PLAYER_SPEED;
360  ball.x_speed = 0;
361  ball.y_speed = 0;
362  last_speed = 0;
363  decision = 3;
364  // Set scores to zero
365  computer_score = 0;
366  player_score = 0;
367  // Random number generator initialization
368  random_number_init(&random_state, 0);
369  // clear the screen
371  // timer initialization
372  timer = get_ticks(1);
373 }
374 
375 // This function receives player input and
376 // handles it for the main game state.
378 {
379  _Bool left_pressed = 0;
380  _Bool right_pressed = 0;
381  unsigned char button_pressed = btn_ctrl();
382  if((button_pressed & BUTTON_UP) != 0)
383  return 1;
384  if((button_pressed & BUTTON_DOWN) != 0)
385  ball.y_speed = BALL_SPEED_Y;
386  if((button_pressed & BUTTON_LEFT) != 0)
387  left_pressed = 1;
388  if((button_pressed & BUTTON_RIGHT) != 0)
389  right_pressed = 1;
390  // This is where we actually move the paddle
391  if (left_pressed)
392  {
393  if ( !check_wall_collisions(&player, LEFT) )
394  player.screen_location.x -= PLAYER_SPEED;
395  }
396  if (right_pressed)
397  {
398  if ( !check_wall_collisions(&player, RIGHT) )
399  player.screen_location.x += PLAYER_SPEED;
400  }
401  return 0;
402 }
403 
404 _Bool manage_ball()
405 {
406  // Start by moving the ball
407  move_ball();
408  if ( check_ball_collisions(&player) )
409  {
410  // Get center location of paddle
411  int paddle_center = player.screen_location.x + player.screen_location.w / 2;
412  int ball_center = ball.screen_location.x + ball.screen_location.w / 2;
413  // Find the location on the paddle that the ball hit
414  int paddle_location = ball_center - paddle_center;
415  // Increase X speed according to distance from center of paddle.
416  ball.x_speed = paddle_location / BALL_SPEED_MODIFIER;
417  ball.y_speed = -ball.y_speed;
418  }
419 
420  if ( check_ball_collisions(&computer) )
421  {
422  // Get center location of paddle
423  int paddle_center = computer.screen_location.x + computer.screen_location.w / 2;
424  int ball_center = ball.screen_location.x + ball.screen_location.w / 2;
425  // Find the location on the paddle that the ball hit
426  int paddle_location = ball_center - paddle_center;
427  // Increase X speed according to distance from center of paddle.
428  ball.x_speed = paddle_location / BALL_SPEED_MODIFIER;
429  ball.y_speed = -ball.y_speed;
430  }
431 
432  // Check to see if someone has scored
433  if (ball.screen_location.y < 0)
434  return manage_player_score();
435  if (ball.screen_location.y + ball.screen_location.h > WINDOW_HEIGHT)
436  return manage_computer_score();
437  return 0;
438 }
439 
440 // Move the computer's paddle and change its direction if necessary
441 void manage_AI()
442 {
443  int computer_x=2;
444  int ball_center = ball.screen_location.x + ball.screen_location.w / 2;
445  // See if ball has changed direction
446  if (last_speed != ball.x_speed)
447  {
448  // 0 == left side, 1 == right side, 2,3 = center
449  decision = random_number(&random_state) % 4;
450  last_speed = ball.x_speed;
451  }
452  // Determine part of paddle to hit ball with according to decision
453  switch (decision)
454  {
455  case 0:
456  {
457  computer_x = computer.screen_location.x;
458  break;
459  }
460  case 1:
461  {
462  computer_x = computer.screen_location.x + computer.screen_location.w;
463  break;
464  }
465  case 2:
466  case 3:
467  {
468  computer_x = computer.screen_location.x + computer.screen_location.w / 2;
469  break;
470  }
471  }
472  // See if ball is near computer's center. Prevents
473  // computer from rapidly moving back and forth.
474  if ( abs(computer_x - ball_center) < BALL_SPEED_Y )
475  return;
476  // Left
477  if (computer_x > ball_center)
478  {
479  if ( !check_wall_collisions(&computer, LEFT) )
480  computer.screen_location.x -= COMPUTER_SPEED;
481  }
482  // Right
483  else if (computer_x < ball_center)
484  {
485  if ( !check_wall_collisions(&computer, RIGHT) )
486  computer.screen_location.x += COMPUTER_SPEED;
487  }
488 }
489 
490 
491 // This function handles the main game. We'll control the
492 // drawing of the game as well as any necessary game logic.
494 {
495  // Here we compare the difference between the current time and the last time we
496  // handled a frame. If FRAME_RATE amount of time has, it's time for a new frame.
497  if(get_ticks(0) - timer > FRAME_RATE)
498  {
499  entity computer_saved=computer;
500  entity player_saved=player;
501  entity ball_saved=ball;
502  if(get_game_input())
503  return 0;
504  if(manage_ball())
505  return 0;
506  manage_AI();
507  // Draw the two paddles and the ball
508  rect(computer_saved.screen_location.x,computer_saved.screen_location.y, computer_saved.screen_location.x+computer_saved.screen_location.w, computer_saved.screen_location.y+computer_saved.screen_location.h, BLACK_COLOR);
509  rect(computer.screen_location.x,computer.screen_location.y, computer.screen_location.x+computer.screen_location.w, computer.screen_location.y+computer.screen_location.h, GREEN_COLOR);
510  rect(player_saved.screen_location.x,player_saved.screen_location.y, player_saved.screen_location.x+player_saved.screen_location.w, player_saved.screen_location.y+player_saved.screen_location.h, BLACK_COLOR);
512  circle(ball_saved.screen_location.x+ball_saved.screen_location.w/2,ball_saved.screen_location.y+ball_saved.screen_location.h/2, ball_saved.screen_location.w/2, BLACK_COLOR);
514  // Draw the boundary
516  // Output the computer and player scores
517  output_score();
518  // We've processed a frame so we now need to record the time at which we did it.
519  // This way we can compare this time the next time our function gets called and
520  // see if enough time has passed between iterations.
521  timer = get_ticks(0);
522  }
523  return 1;
524 }
525 
526 void main()
527 {
529  while (game_main_loop()) {}
530 }
531 
532 
#define FRAME_RATE
Definition: main.c:17
Definition: main.c:80
_Bool check_wall_collisions(entity *entity, unsigned char dir)
Definition: main.c:216
#define BALL_SPEED_MODIFIER
Definition: main.c:43
void * top(node_stack *head)
Definition: tree.c:75
#define BALL_DIAMETER
Definition: main.c:36
unsigned int get_ticks(unsigned char restart_value)
return an unsigned int which represents the elapsed processor time in milliseconds since some constan...
Definition: get_ticks.c:19
struct _random_state_t random_state_t
short int w
Definition: main.c:75
unsigned char btn_ctrl()
Definition: btn_ctrl.c:3
#define WINDOW_WIDTH
Pong game ported to the PandA framework by Fabrizio Ferrandi.
Definition: main.c:12
_Bool manage_ball()
Definition: main.c:592
_Bool manage_player_score()
Definition: main.c:301
entity computer
Definition: main.c:70
void circle(int x0, int y0, int radius, unsigned int color)
Definition: main.c:162
entity ball
Definition: main.c:96
#define GREEN_COLOR
Definition: main.c:23
short int y
Definition: main.c:74
void line(int x1, int y1, int x2, int y2, unsigned int color)
Definition: main.c:110
#define COMPUTER_Y
Definition: main.c:28
_Bool get_game_input()
Definition: main.c:394
#define LEFT
Definition: main.c:46
short int h
Definition: main.c:76
obj_description screen_location
Definition: main.c:82
static random_state_t random_state
Definition: main.c:108
void rect_fill(int left, int top, int right, int bottom, unsigned int color)
Definition: main.c:187
unsigned int random_number(random_state_t *x)
Definition: main.c:90
static int decision
Definition: main.c:76
#define PADDLE_WIDTH
Definition: main.c:32
#define BALL_SPEED_Y
Definition: main.c:44
#define rot(x, k)
Definition: main.c:89
void manage_AI()
Definition: main.c:441
void output_score()
Definition: main.c:196
#define PLAYER_SPEED
Definition: main.c:39
unsigned int a
Definition: main.c:83
#define BLUE_COLOR
Definition: main.c:22
#define RIGHT
Definition: main.c:47
#define PADDLE_HEIGHT
Definition: main.c:33
unsigned int c
Definition: main.c:85
struct _entity entity
#define BLACK_COLOR
Definition: main.c:25
void game_initialization()
Definition: main.c:366
int x_speed
Definition: main.c:83
#define YELLOW_COLOR
Definition: main.c:20
#define BUTTON_LEFT
Definition: btn_ctrl.h:6
struct _obj_description obj_description
#define WHITE_COLOR
Definition: main.c:24
#define abs(x)
Definition: main.c:3
unsigned char player_score
Definition: main.c:74
#define BUTTON_RIGHT
Definition: btn_ctrl.h:7
void move_ball()
Definition: main.c:266
#define BUTTON_DOWN
Definition: btn_ctrl.h:5
void main()
Definition: main.c:670
unsigned char computer_score
Definition: main.c:73
_Bool manage_computer_score()
Definition: main.c:321
_Bool game_main_loop()
Definition: main.c:635
void random_number_init(random_state_t *x, unsigned int seed)
Definition: main.c:100
#define BUTTON_UP
Definition: btn_ctrl.h:4
unsigned int d
Definition: main.c:86
int timer
Definition: main.c:101
unsigned int b
Definition: main.c:84
unsigned char convert_char_digit_2_sseg(char c)
Definition: main.c:103
#define sgn(x)
Definition: main.c:51
void rect(int left, int top, int right, int bottom, unsigned int color)
Definition: main.c:154
void sevensegments_ctrl(unsigned long long val, unsigned long long mask)
int y_speed
Definition: main.c:84
#define COMPUTER_SPEED
Definition: main.c:40
short int x
Definition: main.c:73
entity player
Definition: main.c:95
void plot(int color, int x, int y)
Definition: plot.c:1
static int last_speed
Definition: main.c:75
#define PLAYER_Y
Definition: main.c:29
#define WINDOW_HEIGHT
Definition: main.c:13
_Bool check_ball_collisions()
Definition: main.c:242

Generated on Mon Feb 12 2024 13:02:48 for PandA-2024.02 by doxygen 1.8.13