2 * Copyright © 2011 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22 #include <ao_button.h>
25 #include "ao_pong_text.h"
27 // uint8_t ao_sensor_errors;
36 #define PADDLE_WIDTH 5
37 #define PADDLE_HEIGHT 25
38 #define PADDLE_OFFSET 20
48 static struct ao_data ao_data;
50 static int player_value[2];
51 static int player_score[2];
53 #define player_filter(old, new) (((old) * 7 + (new)) >> 3)
55 static struct rect player[2];
57 static struct rect ball;
60 static int ball_dx, ball_dy;
61 static int ball_step_x, ball_step_y;
64 intersect(struct rect *a, struct rect *b)
66 return (a->x <= b->x + b->w && b->x <= a->x + a->w &&
67 a->y <= b->y + b->h && b->y <= a->y + a->h);
77 ball.x += ball_step_x;
78 while (ball_e >= ball_dx) {
80 ball.y += ball_step_y;
87 if (ball.x >= AO_VGA_WIDTH - BALL_WIDTH)
90 /* bounce off walls */
91 if (ball.y < 0 || ball.y + ball.h > AO_VGA_HEIGHT) {
92 ball_step_y = -ball_step_y;
93 ball.y += ball_step_y;
96 /* bounce off paddles */
98 for (p = 0; p < 2; p++) {
99 if (intersect(&ball, &player[p])) {
100 int dy = 2 * (ball.y - player[p].y) + ball.h - player[p].h;
103 ball_step_x = -ball_step_x;
104 ball.x += ball_step_x;
119 #define AO_ADC_MAX 4095
122 ao_paddle_set(int p, int value)
124 int pos = value * (AO_VGA_HEIGHT - PADDLE_HEIGHT) / AO_ADC_MAX;
136 static enum pong_state pong_state;
137 static int pong_timer;
138 static int pong_server;
140 #define PONG_SERVE_WAIT 90
142 static enum pong_state
149 pong_server = ao_time() & 1;
151 for (p = 0; p < 2; p++)
157 static enum pong_state
161 if (--pong_timer > 0)
166 ball.y = (AO_VGA_HEIGHT - BALL_HEIGHT) / 2;
169 ball.x = player[1].x - BALL_WIDTH;
170 ball_step_x = -BALL_SPEED;
172 ball.x = player[0].x + PADDLE_WIDTH;
173 ball_step_x = BALL_SPEED;
177 ball.h = BALL_HEIGHT;
180 ball_dy = (seed & 7) * 10;
186 ball_step_y = BALL_SPEED;
188 ball_step_y = -BALL_SPEED;
194 static enum pong_state
197 int miss = ao_ball_step();
203 point = (miss + 1) >> 1;
204 player_score[point]++;
205 if (player_score[point] == WIN_SCORE)
209 pong_timer = PONG_SERVE_WAIT;
218 /* Paddles are always active */
219 for (p = 0; p < 2; p++) {
220 player_value[p] = player_filter(player_value[p], ao_data.adc.player[p]);
221 ao_paddle_set(p, player_value[p]);
223 switch (pong_state) {
225 pong_state = ao_pong_start();
228 pong_state = ao_pong_serve();
231 pong_state = ao_pong_volley();
239 ao_pong_rect(struct rect *r, uint32_t fill)
241 ao_rect(&ao_vga_bitmap,
242 r->x, r->y, r->w, r->h, fill, AO_COPY);
246 ao_pong_score(int p, int value, uint32_t fill)
248 int x = AO_VGA_WIDTH / 2 + (p * 2 - 1) * 50 - 24;
261 ao_pong_text(&ao_vga_bitmap, x, 30, c);
269 ao_pong_net(uint32_t fill)
276 for (n = NET_HEIGHT/2; n < AO_VGA_HEIGHT - NET_HEIGHT; n += NET_HEIGHT * 2) {
277 ao_rect(&ao_vga_bitmap,
278 (AO_VGA_WIDTH - NET_WIDTH) >> 1,
287 ao_pong_draw(uint32_t fill)
291 for (p = 0; p < 2; p++) {
292 ao_pong_rect(&player[p], fill);
293 ao_pong_score(p, player_score[p], fill);
295 if (fill == 0 || pong_state == pong_volley)
296 ao_pong_rect(&ball, fill);
313 ao_rect(&ao_vga_bitmap,
314 0, 0, AO_VGA_WIDTH, AO_VGA_HEIGHT,
318 ball.h = BALL_HEIGHT;
320 for (p = 0; p < 2; p++) {
322 player[p].x = AO_VGA_WIDTH - PADDLE_OFFSET - PADDLE_WIDTH;
324 player[p].x = PADDLE_OFFSET;
325 player[p].y = (AO_VGA_HEIGHT - PADDLE_HEIGHT) / 2;
326 player[p].w = PADDLE_WIDTH;
327 player[p].h = PADDLE_HEIGHT;
330 pong_state = pong_endgame;
333 static struct ao_task pong_task;
341 while (ao_vga_vblank == 0)
342 ao_sleep(&ao_vga_vblank);
343 ao_data = ao_data_ring[ao_data_ring_prev(ao_data_head)];
348 static struct ao_task event_task;
352 struct ao_event event;
355 ao_event_get(&event);
356 if (event.value == 0)
357 pong_state = pong_start;
368 ao_led_init(LEDS_AVAILABLE);
369 ao_led_on(AO_LED_GREEN);
370 ao_led_off(AO_LED_BLUE);
379 ao_timer_set_adc_interval(1);
384 ao_add_task(&pong_task, ao_pong, "pong");
386 ao_add_task(&event_task, ao_event, "event");
390 ao_start_scheduler();