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;
34 #define PADDLE_WIDTH 5
35 #define PADDLE_HEIGHT 25
36 #define PADDLE_OFFSET 20
46 static struct ao_data ao_data;
48 static const int player_led[2] = { AO_LED_GREEN, AO_LED_BLUE };
49 static int player_value[2];
50 static int player_score[2];
52 #define player_filter(old, new) (((old) + (new)) >> 1)
54 static struct rect player[2];
56 static struct rect ball;
58 static int ball_speed;
60 static int ball_dx, ball_dy;
61 static int ball_step_x, ball_step_y;
63 static int volley_count;
66 intersect(struct rect *a, struct rect *b)
68 return (a->x <= b->x + b->w && b->x <= a->x + a->w &&
69 a->y <= b->y + b->h && b->y <= a->y + a->h);
79 for (s = 0; s < ball_speed; s++) {
81 ball.x += ball_step_x;
82 while (ball_e >= ball_dx) {
84 ball.y += ball_step_y;
86 /* bounce off walls */
87 if (ball.y < 0 || ball.y + ball.h > AO_VGA_HEIGHT) {
88 ball_step_y = -ball_step_y;
89 ball.y += ball_step_y;
97 if (ball.x >= AO_VGA_WIDTH - BALL_WIDTH)
100 /* bounce off paddles */
102 for (p = 0; p < 2; p++) {
103 if (intersect(&ball, &player[p])) {
107 ball_speed = 3 + volley_count / 4;
109 int dy = (2 * (ball.y - player[p].y) + ball.h - player[p].h);
112 ball_step_x = -ball_step_x;
113 ball.x += ball_step_x;
129 #define AO_ADC_MAX 4095
132 ao_paddle_set(int p, int value)
134 int pos = value * (AO_VGA_HEIGHT - PADDLE_HEIGHT) / AO_ADC_MAX;
146 static enum pong_state pong_state;
147 static int pong_timer;
148 static int pong_server;
150 #define PONG_SERVE_WAIT 90
152 static enum pong_state
159 pong_server = ao_time() & 1;
161 for (p = 0; p < 2; p++) {
162 ao_led_off(player_led[p]);
169 static enum pong_state
173 if (--pong_timer > 0)
178 ball.y = (AO_VGA_HEIGHT - BALL_HEIGHT) / 2;
184 ball.x = player[1].x - BALL_WIDTH;
187 ball.x = player[0].x + PADDLE_WIDTH;
192 ball.h = BALL_HEIGHT;
195 ball_dy = (seed & 7) * 2;
209 static enum pong_state
212 int miss = ao_ball_step();
218 point = (miss + 1) >> 1;
219 player_score[point]++;
220 if (player_score[point] == WIN_SCORE) {
221 ao_led_on(player_led[point]);
226 pong_timer = PONG_SERVE_WAIT;
235 /* Paddles are always active */
236 for (p = 0; p < 2; p++) {
237 player_value[p] = player_filter(player_value[p], ao_data.adc.player[p]);
238 ao_paddle_set(p, player_value[p]);
240 switch (pong_state) {
242 pong_state = ao_pong_start();
245 pong_state = ao_pong_serve();
248 pong_state = ao_pong_volley();
256 ao_pong_rect(struct rect *r, uint32_t fill)
258 ao_rect(&ao_vga_bitmap,
259 r->x, r->y, r->w, r->h, fill, AO_COPY);
263 ao_pong_score(int p, int value, uint32_t fill)
265 int x = AO_VGA_WIDTH / 2 + (p * 2 - 1) * 50 - 24;
278 ao_pong_text(&ao_vga_bitmap, x, 30, c);
286 ao_pong_net(uint32_t fill)
293 for (n = NET_HEIGHT/2; n < AO_VGA_HEIGHT - NET_HEIGHT; n += NET_HEIGHT * 2) {
294 ao_rect(&ao_vga_bitmap,
295 (AO_VGA_WIDTH - NET_WIDTH) >> 1,
304 ao_pong_draw(uint32_t fill)
308 for (p = 0; p < 2; p++) {
309 ao_pong_rect(&player[p], fill);
310 ao_pong_score(p, player_score[p], fill);
312 if (fill == 0 || pong_state == pong_volley)
313 ao_pong_rect(&ball, fill);
330 ao_rect(&ao_vga_bitmap,
331 0, 0, AO_VGA_WIDTH, AO_VGA_HEIGHT,
335 ball.h = BALL_HEIGHT;
337 for (p = 0; p < 2; p++) {
339 player[p].x = AO_VGA_WIDTH - PADDLE_OFFSET - PADDLE_WIDTH;
341 player[p].x = PADDLE_OFFSET;
342 player[p].y = (AO_VGA_HEIGHT - PADDLE_HEIGHT) / 2;
343 player[p].w = PADDLE_WIDTH;
344 player[p].h = PADDLE_HEIGHT;
347 pong_state = pong_endgame;
350 static struct ao_task pong_task;
358 while (ao_vga_vblank == 0)
359 ao_sleep(&ao_vga_vblank);
360 ao_data = ao_data_ring[ao_data_ring_prev(ao_data_head)];
365 static struct ao_task event_task;
369 struct ao_event event;
372 ao_event_get(&event);
373 if (event.value == 0)
374 pong_state = pong_start;
385 ao_led_init(LEDS_AVAILABLE);
386 ao_led_on(AO_LED_GREEN);
387 ao_led_off(AO_LED_BLUE);
396 ao_timer_set_adc_interval(1);
401 ao_add_task(&pong_task, ao_pong, "pong");
403 ao_add_task(&event_task, ao_event, "event");
407 ao_start_scheduler();