From a0af1dc10a8ce63d7e973a17aa969ddfdf09babd Mon Sep 17 00:00:00 2001 From: Adam Greenwood-Byrne Date: Wed, 24 Mar 2021 21:06:32 +0000 Subject: [PATCH] Finished Space Invaders example game in example/wgt20.c --- part12-wgt/controller/main.js | 17 ++ part12-wgt/examples/wgt20.c | 469 ++++++++++++++++++++++++++++++++++ part12-wgt/mouse.c | 24 +- part12-wgt/wgt.h | 8 +- 4 files changed, 510 insertions(+), 8 deletions(-) create mode 100644 part12-wgt/examples/wgt20.c diff --git a/part12-wgt/controller/main.js b/part12-wgt/controller/main.js index 0c346b3..21b3244 100644 --- a/part12-wgt/controller/main.js +++ b/part12-wgt/controller/main.js @@ -37,6 +37,7 @@ var ioHook = require('iohook'); var buf = Buffer.allocUnsafe(4); var obuf = Buffer.allocUnsafe(4); +var buttbuf = Buffer.allocUnsafe(2); const scrwidth = 1440; const scrheight = 900; const divisorx = scrwidth / 320; @@ -53,4 +54,20 @@ ioHook.on( 'mousemove', event => { } }); +ioHook.on( 'mousedown', event => { + buttbuf.writeUInt8(1, 0); + buttbuf.writeUInt8(event.button, 1); + + e._value = buttbuf; + if (e._updateValueCallback) e._updateValueCallback(e._value); +}); + +ioHook.on( 'mouseup', event => { + buttbuf.writeUInt8(2, 0); + buttbuf.writeUInt8(event.button, 1); + + e._value = buttbuf; + if (e._updateValueCallback) e._updateValueCallback(e._value); +}); + ioHook.start(); diff --git a/part12-wgt/examples/wgt20.c b/part12-wgt/examples/wgt20.c new file mode 100644 index 0000000..6da5ad7 --- /dev/null +++ b/part12-wgt/examples/wgt20.c @@ -0,0 +1,469 @@ +#include "wgtspr.h" +#include "include/mem.h" +#include "include/multicore.h" + +// ######## REQUIRED FUNCTIONS ######## + +unsigned long state0 = 1000; +unsigned long state1 = 2000; + +unsigned long rand(void) +{ + unsigned long s1 = state0; + unsigned long s0 = state1; + + state0 = s0; + s1 ^= s1 << 23; + s1 ^= s1 >> 17; + s1 ^= s0; + s1 ^= s0 >> 26; + state1 = s1; + + return state0 + state1; +} + +// ######## STUB FUNCTIONS ######## + +unsigned int kb = 0; + +unsigned int kbhit(void) { + kb++; + return kb / 500; +} + +void getch(void) { + wait_msec(0x500000); + kb = 0; +} + +// ######## WGT EXAMPLES ######## + +/* Large example demonstrating many functions from WGT */ + +#define MAXEXPLOS 220 +#define MAXALIEN 170 + +void scrolldown (void); /* scrolls the screen down */ +void credits (void); +void changepalette256 (void); +void colorloop (void); +void play (void); + +block scr, scr2; +block sprites[21]; + +typedef struct { + int x, y; + int dirx, diry; + int shootx, shooty; + int power; + } spaceship; + +typedef struct { + int x, y; + int num; + } explosion; +explosion explos[MAXEXPLOS]; + +spaceship aliens[MAXALIEN]; +int numaliens, aliensleft; + +int shoot[10], sx[10], sy[10]; +int ship; /* Sprite to show */ +int shipx[MAXALIEN], shipy[MAXALIEN]; /* Ship coordinates */ +float incx, incy, yourx, youry; + +int cd; +int i, j, k; /* Loop control */ +int scrll = 1; /* scrll is a counter for the scroll offset */ +int ix = 30, iy = 0, ix2 = 251, iy2 = 199; /* coords of scrolling area */ +int speed; /* the scrolling speed */ + /* try changing speed and sign */ +int nextlevel; /* Performing level change = 1 */ +int leveltextx; /* X coordinate of next level text */ +int level; + +color palette[256]; + +void strrev(char *str) +{ + int i; + int j; + unsigned char a; + unsigned len = strlen((const char *)str); + for (i = 0, j = len - 1; i < j; i++, j--) { + a = str[i]; + str[i] = str[j]; + str[j] = a; + } +} + +int itoa(int num, char* str, int base) +{ + int sum = num; + int i = 0; + int digit; + + do { + digit = sum % base; + if (digit < 0xA) str[i++] = '0' + digit; + else str[i++] = 'A' + digit - 0xA; + sum /= base; + } while (sum); + + str[i] = '\0'; + strrev(str); + return 0; +} + +void initialize_aliens (int numaliens) +/* Sets the initial positions of the aliens when starting a level. */ +{ +int i; + + for (i = 0; i < numaliens; i++) + { + aliens[i].x = rand() % 200 + 30; + aliens[i].y = rand() % 50; + aliens[i].dirx = rand() % 8 - 4; + aliens[i].diry = rand() % 8 - 4; + aliens[i].power = numaliens / 3; + aliens[i].shootx = -1; + } +} + +void make_starfield (void) +/* Gets two virtual screens and puts the star sprites on them to make + a starfield background. */ +{ +int i; + + scr = wnewblock (0, 0, 319, 199); /* get two virtual screens */ + scr2 = wnewblock (0, 0, 319, 199); + wsetscreen (scr2); /* go to second one */ + wcls (vgapal[0]); /* clear it */ + + for (i = 1; i < 300; i++) + wputblock (rand() % 320, rand() % 200, sprites[5], 0); + /* sprite[5] is small stars */ + + for (i = 1; i < 5; i++) + wputblock (rand() % 320, rand() % 200, sprites[6], 0); + /* sprite[6] is a large star */ +} + +void play (void) +{ + scrolldown (); /* Scroll the second + screen by copying it to + a different offset on + screen one. */ + + if (but == 1) + { /* if you clicked the mouse */ + for (i = 0; i <9; i++) + if (shoot[i] == 0) /* check to see if slot available */ + { + shoot[i] = 1; /* make it unavailable */ + sx[i] = yourx + 9; /* set coords for shot */ + sy[i] = youry - 7; + break; + } + } + + for (i = 0; i < 9; i++) /* if shot is active */ + { + if (shoot[i] == 1) /* then show the sprite */ + { + wputblock (sx[i], sy[i], sprites[4], 0); /* at the right coords */ + sy[i] -= 8; /* make it go up */ + if (sy[i] < 1) /* if it is at top, */ + shoot[i] = 0; /* make it available again */ + + /* Now check to see if it hit an alien by seeing if their + rectangular regions overlap. */ + for (j = 0; j < numaliens; j++) + if ((aliens[j].x != -255) && + (sx[i] > aliens[j].x) && (sx[i] < aliens[j].x + 25) && + (sy[i] > aliens[j].y) && (sy[i] < aliens[j].y + 20)) + + { + shoot[i] = 0; /* Turn off that missile */ + + aliens[j].power--; + if (aliens[j].power == 0) + { + aliensleft--; + if (aliensleft == 0) + { + nextlevel = 1; + leveltextx = ix2 + 100; + } + for (k = 0; k < MAXEXPLOS; k++) /* Add an explosion */ + { + if (explos[k].num == 0) + { + explos[k].x = aliens[j].x; + explos[k].y = aliens[j].y; + explos[k].num = 8; + break; + } + } + aliens[j].x = -255; + } + } /* Collision */ + } /* Shot active */ + } /* for loop */ + + incx = (float)(mx - yourx) / 5.0; /* Move your spaceship according to the */ + incy = (float)(my - youry) / 5.0; /* position of the mouse. */ + yourx += incx; + youry += incy; + + /* Tilt the ship */ + if ((incx < 2) && (incx > -2)) + ship = 2; + else if (incx > 5) + ship=3; + else if (incx < 5) + ship = 1; + + wsetscreen (scr); + wputblock (yourx, youry, sprites[ship], 1); /* Put your ship on */ + + for (i = 0; i < numaliens; i++) + { + if (aliens[i].x != -255) /* Alien is still alive */ + { + aliens[i].x += aliens[i].dirx; /* Make them move */ + aliens[i].y += aliens[i].diry; + + /* Make them bounce off the walls if they go too far in one direction. */ + if (aliens[i].x <= ix) + aliens[i].dirx = rand() % 4; + else if (aliens[i].x > ix2 - 20) + aliens[i].dirx = -(rand() % 4); + + if (aliens[i].y < 0) + aliens[i].diry = rand() % 4; + else if (aliens[i].y > 150) + aliens[i].diry = -(rand() % 4); + + if ((aliens[i].shootx == -1) && (rand() % 10 == 1)) + /* 1 in 10 chance of shooting */ + { + aliens[i].shootx = aliens[i].x + 9; + aliens[i].shooty = aliens[i].y + 5; + } + + if (aliens[i].power > 0) + wputblock (aliens[i].x, aliens[i].y, sprites[7], 1); + + /* Display the alien's missile. */ + if (aliens[i].shootx != -1) + { + wputblock (aliens[i].shootx, aliens[i].shooty, sprites[8], 1); + aliens[i].shooty += 4; + if (aliens[i].shooty > 199) + aliens[i].shootx = -1; + } + } + } + + /* Now draw any explosions on the screen. */ + for (i = 0; i < MAXEXPLOS; i++) + { + if (explos[i].num > 0) + { + explos[i].num++; + if (explos[i].num > 14) + explos[i].num = 0; + else + wputblock (explos[i].x, explos[i].y, sprites[explos[i].num], 1); + } + } + + if (nextlevel == 1) + { + leveltextx -= 5; + + wouttextxy (leveltextx, 50, NULL, "LEVEL "); + + char levelstr[10]; + itoa(level + 1, levelstr, 10); + wouttextxy (leveltextx + (6 * 8), 50, NULL, levelstr); + + if (leveltextx < -100) + { + level++; + if (level > MAXALIEN) + level = MAXALIEN; + numaliens = level + 5; + aliensleft = numaliens; + initialize_aliens (numaliens); + nextlevel = 0; + } + } + + wait_msec(0x3E9F); + wcopyscreen (ix, iy, ix2, iy2, scr, ix, iy, NULL); + /* copy the first screen */ + /* to the base screen */ +} + +void scrolldown (void) +{ + wcopyscreen (ix, scrll, ix2, iy2, scr2, ix, iy, scr); + wcopyscreen (ix, iy, ix2, scrll, scr2, ix, iy2 - scrll, scr); + /* Cut the screen into two sections, then swap them vertically on the + destination page */ + + scrll += speed; + if ((scrll < iy) && (speed < 0)) + scrll = iy2 + 1 - abs (scrll); + if ((scrll > iy2) && (speed > 0)) + scrll = abs (iy2 - scrll); +} + +void credits (void) +{ + wnormscreen (); + wtextcolor (vgapal[1]); + wtextbackground (vgapal[0]); + + cd = 2; + /* draw a pattern on the screen */ + for (i = 0; i < 320; i++) + { + colorloop (); + wsetcolor (vgapal[cd]); + wfline (160, 100, i, 0); + } + for (i = 0; i < 200; i++) + { + colorloop (); + wsetcolor (vgapal[cd]); + wfline (160, 100, 319, i); + } + for (i = 319; i >= 0; i--) + { + colorloop (); + wsetcolor (vgapal[cd]); + wfline (160, 100, i, 199); + } + for (i = 199; i >= 0; i--) + { + colorloop (); + wsetcolor (vgapal[cd]); + wfline (160, 100, 0, i); + } + + + changepalette256 (); + + wouttextxy (50, 20, NULL, "Shoot 'Em Up Sprite Example"); + wouttextxy (50, 28, NULL, "Showing what YOU could do with"); + wouttextxy (50, 36, NULL, "the WordUp Graphics Toolkit!"); + wouttextxy (50, 44, NULL, "Use the mouse to move"); + wouttextxy (50, 52, NULL, "Left button shoots"); + wouttextxy (50, 60, NULL, "Right button quits"); + wouttextxy (50, 68, NULL, "Right button to start"); + wsetrgb (1, 63, 63, 63, palette); + // wfade_in (0, 255, 1, palette); + + do { + /* + wcolrotate (2, 106, 0, palette); + wsetpalette (2, 106, palette); + */ + wait_msec(0x3E9F); + } while (!but); + + noclick(); + wcls (vgapal[0]); +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* change the palette to the right colours */ +void changepalette256 (void) +{ + wsetrgb (0, 0, 0, 0, palette); + + for (i = 2; i < 54; i++) + wsetrgb (i, i, 0, 0, palette); + for (i = 54; i < 106; i++) + wsetrgb (i, 105 - i, 0, 0, palette); + + wsetrgb (253, 60, 60, 60, palette); + wsetrgb (254, 45, 45, 45, palette); + wsetrgb (255, 30, 30, 30, palette); + wsetrgb (1, 63, 63, 63, palette); +} + +void colorloop (void) +/* Simple loop for colours on credit screen */ +{ + cd++; + if (cd > 105) + cd = 2; +} + +void wgt20() +{ + set_clock_rate(get_max_clock()); + mem_init(); + vga256 (); /* Initializes WGT system */ + + start_core2(minit); // Start the comms engine (core 2) + while (!comms_up); // Wait for comms up + + credits (); + + extern unsigned char _binary_bin_space_spr_start[]; + wloadsprites (palette, &_binary_bin_space_spr_start[0], sprites, 0, 20); + /* load first 10 sprites */ + wsetpalette (0, 255, palette); + + make_starfield (); + + wnormscreen (); /* go back to normal screen */ + wcls (vgapal[0]); /* clear it */ + wbutt (0, 0, 29, 199); /* make some side panels */ + wbutt (252, 0, 319, 199); + wtextbackground (vgapal[0]); + wtextcolor (vgapal[1]); + wtexttransparent (TEXTFG); + + yourx = 128; + youry = 170; + + wsetscreen (scr); /* go to first screen */ + msetbounds (ix, 150, ix2 - 20, 179); + + speed = -4; + + nextlevel = 0; + level = 1; + numaliens = level + 5; + aliensleft = numaliens; + + initialize_aliens (numaliens); + + do { + play (); + } while (but != 2); /* until right button is pressed */ + + mdeinit (); /* Deinitialize the mouse handler */ + wfreeblock (scr); + wfreeblock (scr2); + wfreesprites (sprites, 0, 20); + + wnormscreen(); + wcls(vgapal[0]); +} + +void main() +{ + wgt20(); + while (1); +} diff --git a/part12-wgt/mouse.c b/part12-wgt/mouse.c index 57c5f8a..14aa83b 100644 --- a/part12-wgt/mouse.c +++ b/part12-wgt/mouse.c @@ -29,9 +29,9 @@ unsigned int connection_handle = 0; volatile unsigned int comms_up = 0; /* Mouse variables */ -int but; -int mx; -int my; +volatile int but; +volatile int mx; +volatile int my; /* Mouse boundaries */ int mbx1, mby1; @@ -172,9 +172,10 @@ void acl_poll() unsigned int channel = data[2] | (data[3] << 8); unsigned char opcode = data[4]; - if (thandle == connection_handle && length == 7 && opcode == 0x1b) { + if (thandle == connection_handle && opcode == 0x1b) { if (channel == 4 && data[5] == 0x2a && data[6] == 0x00) { - msetxy(data[7] | (data[8] << 8), data[9] | (data[10] << 8)); + if (length == 7) msetxy(data[7] | (data[8] << 8), data[9] | (data[10] << 8)); + if (length == 5) msetbut(data[7], data[8]); } } } @@ -198,6 +199,14 @@ void msetbounds (short x1, short y1, short x2, short y2) } } +void msetbut (short event, short bnum) { + if (event == 1) { // Mouse down + but |= bnum; + } else if (event == 2) { // Mouse up + but ^= bnum; + } +} + void msetxy (short x, short y) { if (x < mbx1) x = mbx1; @@ -210,6 +219,11 @@ void msetxy (short x, short y) my = y; } +void noclick() +{ + if (but) while (but); +} + void mdeinit() { comms_up = 0; diff --git a/part12-wgt/wgt.h b/part12-wgt/wgt.h index e2bba1e..52f3ccd 100644 --- a/part12-wgt/wgt.h +++ b/part12-wgt/wgt.h @@ -65,9 +65,9 @@ typedef struct #define OPEN_POLY 1 /* Mouse variables */ -extern int but; -extern int mx; -extern int my; +extern volatile int but; +extern volatile int mx; +extern volatile int my; /* Bluetooth control */ extern volatile unsigned int comms_up; @@ -155,4 +155,6 @@ void wbezier (tpolypoint *rawpts, short numraw, tpolypoint *curvepts, short numc void minit(); void mdeinit(); void msetxy (short x, short y); +void msetbut (short event, short bnum); void msetbounds (short x1, short y1, short x2, short y2); +void noclick();