summaryrefslogtreecommitdiff
path: root/apps/plugins/pong.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pong.c')
-rw-r--r--apps/plugins/pong.c313
1 files changed, 313 insertions, 0 deletions
diff --git a/apps/plugins/pong.c b/apps/plugins/pong.c
new file mode 100644
index 0000000000..2345605995
--- /dev/null
+++ b/apps/plugins/pong.c
@@ -0,0 +1,313 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2004 Daniel Stenberg
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "plugin.h"
+
+#define PAD_HEIGHT 10
+#define PAD_WIDTH 2
+
+#define BALL_HEIGTH 2
+#define BALL_WIDTH 2
+
+#define SPEEDX 150
+#define SPEEDY 120
+
+#define RES 100
+
+static struct plugin_api* rb;
+
+struct pong {
+ int ballx; /* current X*RES position of the ball */
+ int bally; /* current Y*RES position of the ball */
+ int w_pad[2]; /* wanted current Y positions of pads */
+ int e_pad[2]; /* existing current Y positions of pads */
+ int ballspeedx; /* */
+ int ballspeedy; /* */
+
+ int score[2];
+};
+
+void singlepad(int x, int y, int set)
+{
+ if(set)
+ rb->lcd_fillrect(x, y, PAD_WIDTH, PAD_HEIGHT);
+ else
+ rb->lcd_clearrect(x, y, PAD_WIDTH, PAD_HEIGHT);
+}
+
+void pad(struct pong *p, int pad)
+{
+ static int xpos[2]={0, 112-PAD_WIDTH};
+
+ /* clear existing pad */
+ singlepad(xpos[pad], p->e_pad[pad], 0);
+
+ /* draw wanted pad */
+ singlepad(xpos[pad], p->w_pad[pad], 1);
+
+ /* existing is now the wanted */
+ p->e_pad[pad] = p->w_pad[pad];
+}
+
+bool wallcollide(struct pong *p, int pad)
+{
+ /* we have already checked for pad-collision, just check if this hits
+ the wall */
+ if(pad) {
+ /* right-side */
+ if(p->ballx > 112*RES)
+ return true;
+ }
+ else {
+ if(p->ballx < 0)
+ return true;
+ }
+ return false;
+}
+
+/* returns true if the ball has hit a pad, and then the info variable
+ will have extra angle info */
+
+bool padcollide(struct pong *p, int pad, int *info)
+{
+ int x = p->ballx/RES;
+ int y = p->bally/RES;
+
+ if((y < (p->e_pad[pad]+PAD_HEIGHT)) &&
+ (y + BALL_HEIGTH > p->e_pad[pad])) {
+ /* Y seems likely right */
+
+ /* store the delta between ball-middle MINUS pad-middle, so
+ it returns:
+ 0 when the ball hits exactly the middle of the pad
+ positive numbers when the ball is below the middle of the pad
+ negative numbers when the ball is above the middle of the pad
+
+ max number is +- PAD_HEIGHT/2
+ */
+
+ *info = (y+BALL_HEIGTH/2) - (p->e_pad[pad] + PAD_HEIGHT/2);
+
+ if(pad) {
+ /* right-side */
+ if((x + BALL_WIDTH) > (112 - PAD_WIDTH))
+ return true; /* phump */
+ }
+ else {
+ if(x <= 0)
+ return true;
+ }
+ }
+ return false; /* nah */
+}
+
+void bounce(struct pong *p, int pad, int info)
+{
+ (void)pad; /* not used right now */
+ p->ballspeedx = -p->ballspeedx;
+
+ /* info is the hit-angle into the pad */
+ if(p->ballspeedy > 0) {
+ /* downwards */
+ if(info > 0) {
+ /* below the middle of the pad */
+ p->ballspeedy += info * RES/3;
+ }
+ else if(info < 0) {
+ /* above the middle */
+ p->ballspeedy = info * RES/2;
+ }
+ }
+ else {
+ /* upwards */
+ if(info > 0) {
+ /* below the middle of the pad */
+ p->ballspeedy = info * RES/2;
+ }
+ else if(info < 0) {
+ /* above the middle */
+ p->ballspeedy -= info * RES/3;
+ }
+ }
+
+ p->ballspeedy += rb->rand()%21-10;
+
+#if 0
+ fprintf(stderr, "INFO: %d YSPEED: %d\n", info, p->ballspeedy);
+#endif
+}
+
+void score(struct pong *p, int pad)
+{
+ rb->splash(HZ/4, true, "%s scores!", pad?"right":"left");
+ rb->lcd_clear_display();
+ p->score[pad]++;
+
+ /* then move the X-speed of the ball and give it a random Y position */
+ p->ballspeedx = -p->ballspeedx;
+ p->bally = rb->rand()%(64-BALL_HEIGTH);
+
+ /* restore Y-speed to default */
+ p->ballspeedy = (p->ballspeedy > 0) ? SPEEDY : -SPEEDY;
+
+ /* set the existing pad positions to something weird to force pad
+ updates */
+ p->e_pad[0] = -1;
+ p->e_pad[1] = -1;
+}
+
+void ball(struct pong *p)
+{
+ int x = p->ballx/RES;
+ int y = p->bally/RES;
+
+ int newx;
+ int newy;
+
+ int info;
+
+ /* movement */
+ p->ballx += p->ballspeedx;
+ p->bally += p->ballspeedy;
+
+ newx = p->ballx/RES;
+ newy = p->bally/RES;
+
+ /* detect if ball hits a wall */
+ if(newy + BALL_HEIGTH > 64) {
+ /* hit floor, bounce */
+ p->ballspeedy = -p->ballspeedy;
+ newy = 64 - BALL_HEIGTH;
+ p->bally = newy * RES;
+ }
+ else if(newy < 0) {
+ /* hit ceiling, bounce */
+ p->ballspeedy = -p->ballspeedy;
+ p->bally = 0;
+ newy = 0;
+ }
+
+ /* detect if ball hit pads */
+ if(padcollide(p, 0, &info))
+ bounce(p, 0, info);
+ else if(padcollide(p, 1, &info))
+ bounce(p, 1, info);
+ else if(wallcollide(p, 0))
+ score(p, 1);
+ else if(wallcollide(p, 1))
+ score(p, 0);
+
+ /* clear old position */
+ rb->lcd_clearrect(x, y, BALL_WIDTH, BALL_HEIGTH);
+
+ /* draw the new ball position */
+ rb->lcd_fillrect(newx, newy, BALL_WIDTH, BALL_HEIGTH);
+}
+
+void padmove(int *pos, int dir)
+{
+ *pos += dir;
+ if(*pos > (64-PAD_HEIGHT))
+ *pos = (64-PAD_HEIGHT);
+ else if(*pos < 0)
+ *pos = 0;
+}
+
+bool keys(struct pong *p)
+{
+ int key;
+
+ int time = 4; /* number of ticks this function will loop reading keys */
+ int start = *rb->current_tick;
+ int end = start + time;
+
+ while(end > *rb->current_tick) {
+ key = rb->button_get_w_tmo(end - *rb->current_tick);
+
+ if(key & BUTTON_OFF)
+ return false; /* exit game NOW */
+
+ if(key & BUTTON_LEFT) /* player left goes down */
+ padmove(&p->w_pad[0], 1);
+
+ if(key & BUTTON_F1) /* player left goes up */
+ padmove(&p->w_pad[0], -1);
+
+ if(key & BUTTON_RIGHT) /* player right goes down */
+ padmove(&p->w_pad[1], 1);
+
+ if(key & BUTTON_F3) /* player right goes up */
+ padmove(&p->w_pad[1], -1);
+ }
+ return true; /* return false to exit game */
+}
+
+void showscore(struct pong *p)
+{
+ static char buffer[20];
+
+ snprintf(buffer, 20, "%d - %d", p->score[0], p->score[1]);
+ rb->lcd_puts(4, 0, buffer);
+}
+
+/* this is the plugin entry point */
+enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
+{
+ TEST_PLUGIN_API(api);
+
+ struct pong pong;
+ bool game = true;
+
+ /* init the struct with some silly values to start with */
+
+ pong.ballx = 20*RES;
+ pong.bally = 20*RES;
+
+ pong.e_pad[0] = 0;
+ pong.w_pad[0] = 7;
+ pong.e_pad[1] = 0;
+ pong.w_pad[1] = 40;
+
+ pong.ballspeedx = SPEEDX;
+ pong.ballspeedy = SPEEDY;
+
+ pong.score[0] = pong.score[1] = 0; /* lets start at 0 - 0 ;-) */
+
+ /* if you don't use the parameter, you can do like
+ this to avoid the compiler warning about it */
+ (void)parameter;
+
+ rb = api; /* use the "standard" rb pointer */
+
+ /* Clear screen */
+ rb->lcd_clear_display();
+
+ /* go go go */
+ while(game) {
+ showscore(&pong);
+ pad(&pong, 0); /* draw left pad */
+ pad(&pong, 1); /* draw right pad */
+ ball(&pong); /* move and draw ball */
+
+ rb->lcd_update();
+
+ game = keys(&pong); /* deal with keys */
+ }
+
+ return PLUGIN_OK;
+}