#define VECTREX 1 #ifdef VECTREX #include <vectrex.h> #else #include <stdio.h> #include <stdlib.h> #include <math.h> #define Reset0Ref() #define Draw_Line_d(y,x) #define Moveto_d(y,x) #define Draw_VLc(x) #endif #define GRIDLOW -64 #define GRIDHIGH 63 #define PGRIDSCALE 255U #define XYGRIDSCALE 200U #define ABSSCALE 127U #define MY_Y GRIDLOW #define MEANIE_Y = GRIDHIGH // for now static inline void set_scale(unsigned int s) { #ifdef VECTREX // this should not be faster, but it is. The write to the VIA must be slow. static unsigned int last_scale = 0; if (last_scale != s) { VIA_t1_cnt_lo = last_scale = s; } #endif } int gridview = 0; // view without perspective when 1. unsigned int gridscale; int SX=0, SY=0; // screen X,Y - actual beam pos static inline void swap (int *a, int *b) { int t = *a; *a = *b; *b = t; } #ifdef VECTREX static const int perspectiveY[256] = { -107, -107, -107, -107, -107, -106, -106, -106, -106, -105, -105, -105, -105, -105, -104, -104, -104, -104, -103, -103, -103, -103, -102, -102, -102, -102, -101, -101, -101, -101, -100, -100, -100, -100, -99, -99, -99, -98, -98, -98, -98, -97, -97, -97, -96, -96, -96, -95, -95, -95, -95, -94, -94, -94, -93, -93, -92, -92, -92, -91, -91, -91, -90, -90, -90, -89, -89, -88, -88, -88, -87, -87, -86, -86, -86, -85, -85, -84, -84, -84, -83, -83, -82, -82, -81, -81, -80, -80, -79, -79, -78, -78, -77, -77, -76, -76, -75, -75, -74, -74, -73, -73, -72, -72, -71, -71, -70, -69, -69, -68, -68, -67, -66, -66, -65, -65, -64, -63, -63, -62, -61, -61, -60, -59, -59, -58, -57, -57, -56, -55, -54, -54, -53, -52, -51, -51, -50, -49, -48, -48, -47, -46, -45, -44, -43, -43, -42, -41, -40, -39, -38, -37, -36, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -18, -17, -16, -15, -14, -13, -12, -11, -9, -8, -7, -6, -5, -3, -2, -1, 0, 2, 3, 4, 6, 7, 8, 10, 11, 13, 14, 15, 17, 18, 20, 21, 23, 24, 26, 27, 29, 30, 32, 34, 35, 37, 39, 40, 42, 44, 45, 47, 49, 51, 52, 54, 56, 58, 60, 62, 64, 65, 67, 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 90, 92, 95, 97, 99, 101, 104, 106, 108, 111, 113, 116, 118, 120, 123, 125, 127, }; void init_perspective(void) { } #else double perspectiveY[256L]; // map Y=0:255 to Y'=n:255 void init_perspective(void) { long mapsto, step, Y, UY; // initialise perspective table. Can be done in rom. Needs calc using 'e' :-/ //fprintf(stdout, "Setting p[127] to 255\n"); perspectiveY[255] = (double)255; for (Y = 254L; Y >= 0L; Y--) { // top wide, bottom narrow. 16 passes UY=Y-128; perspectiveY[Y] = perspectiveY[Y+1]*0.99; //fprintf(stdout, "Setting p[%d] to %d\n", UY, (int)perspectiveY[Y]); } for (Y = 0L; Y < 256L; Y++) { // top wide, bottom narrow. 16 passes perspectiveY[Y] = round(perspectiveY[Y]); } for (Y = 0L; Y < 256L; Y++) { // top wide, bottom narrow. 16 passes perspectiveY[Y] = -(255-perspectiveY[Y] - 128); } perspectiveY[255]=127; for (Y = -128L; Y < 128L; Y++) { // top wide, bottom narrow. 16 passes fprintf(stdout, " %d,", (int)(signed char)(perspectiveY[((Y+128)&255)])); if (((Y+128)&15) == 15) fprintf(stdout, "\n"); } exit(0); } #endif static inline int PY(int Y) { if (gridview) return Y; return -perspectiveY[255-(Y+128)]-32; // -32 is just to move it down the screen // I should have built the '-' and '255-' into the table. Too lazy to go back and redo it. } static inline int PX(int X, int Y) { if (gridview) return X; typedef union { struct { unsigned int high; unsigned int low; } byte; struct { unsigned long val; } word; } var; var prod; unsigned int LY = 255U-(unsigned int)(128+PY(Y)); // convert Y from -128:127 to 0:255 prod.word.val = (long unsigned int)X * (long unsigned int)LY; return (int)(prod.byte.high); // what we do to avoid >>8 ... :-( btw <<1 causes overflow} } // These are in grid space but draw in perspective: static inline void MoveAbsXY(int x, int y) { Reset0Ref(); // SX = SY = 0; //Moveto_d(y-SY, x-SX); Moveto_d(y, x); SX = x; SY = y; } static inline void PerspectiveMove(int x, int y) { set_scale(gridscale); MoveAbsXY(PX(x,y),PY(y)); } static inline void LineAbsXY(int x, int y) { Draw_Line_d(y-SY, x-SX); // sizes are carefully chosen so this never overflows SX = x; SY = y; } static inline void PerspectiveLine(int x, int y) { set_scale(gridscale); LineAbsXY(PX(x,y),PY(y)); } #define MAX_MEANIES 3 static int meanie_x[MAX_MEANIES] = {-48, 0, 48}, meanie_y[MAX_MEANIES] = {0, -50, -16}, meanie_dx[MAX_MEANIES] = { 2, 0, 0}, meanie_dy[MAX_MEANIES] = {0, 2, 4}; static int my_x = 0; static inline void draw_me(void) { static int Me[] = {4, -9,0, 9,-9, 9,9, -9,9, -9,-9}; PerspectiveMove(my_x,GRIDLOW); set_scale(0x7f); Draw_VLc(Me); } static int missile_x, missile_y; static int firing = 0; static inline void draw_missile(void) { static int Missile[] = {4, -9,0, 9,-9, 9,9, -9,9, -9,-9}; PerspectiveMove(missile_x,missile_y); set_scale((unsigned int)PX(0x7f, missile_y)); // hacky way to apply perspective //set_scale((unsigned int)PY(missile_y)); Draw_VLc(Missile); missile_y += 8; if (missile_y >= GRIDHIGH) firing = 0; // also when it hits a target... } static inline void draw_meanie(int x, int y) { static int Meanie[] = {4, -3,0, 3,-3, 3,3, -3,3, -3,-3}; PerspectiveMove(x,y); set_scale((unsigned int)PX(0x7f, y)<<1); // hacky way to apply perspective //set_scale((unsigned int)PY(y)<<1); Draw_VLc(Meanie); } static inline void draw_meanies(void) { int m; // assumes all on screen all the time. for (m = 0; m < MAX_MEANIES; m++) { // if (((meanie_y[m] > GRIDLOW)) && ((meanie_y[m] < GRIDHIGH))) { draw_meanie(meanie_x[m], meanie_y[m]); // } } } static void draw_moving_grid(int depth) { int row, col; // adding these two lines not only costs cycles we can no longer afford, // they also mess up the display! Not sure why. //Print_Str_d(127, -60, "BEAM RIDER\x80"); //Print_Str_d(-127, -120, "L 1 R 2 VIEW 3 FIRE 4\x80"); PerspectiveMove(0, GRIDHIGH); Moveto_d(0, 64); // Horizon Draw_Line_d(0, -128); // Horizon for (col = -48; col <= 48; col += 16) { PerspectiveMove(col, GRIDLOW); // as long as gridhigh-gridlow <= 127 PerspectiveLine(col, GRIDHIGH); // draw vertical grid component } for (row = depth+32; row >= depth-64; row -= 32) { // depth is the small delta movement between gaps PerspectiveMove(-48, row); PerspectiveLine(48, row); // draw horizontal grid component } } int main(void) { int left=0, right=0, fire=0; int direction=0; int granularity = 1; // grid speed: can increase up to 4 as more speed needed later in game int depth = 0, actiontick = 0, slowmode = 1; // set slowmode to 0 when player reaches basic score that // shows he knows how the game works... init_perspective(); for (;;) { #ifdef VECTREX Wait_Recal(); Intensity_7F(); // poll buttons. Old code. Should use library calls now. asm("pshs x,y,u,dp"); asm("lda #0"); asm("jsr 0HF1B4 ; read_btns_mask":::"a","b","d"); asm("puls dp,u,y,x"); left = (*(volatile int *)(0xC80F)) & 1; right = (*(volatile int *)(0xC80F)) & 2; gridview = (*(volatile int *)(0xC80F)) & 4; // debugging aid gridscale = gridview ? XYGRIDSCALE : PGRIDSCALE; // whenever gridview changes... fire = (*(volatile int *)(0xC80F)) & 8; #endif if (left && !right) { if (my_x > -48) my_x -= 2; direction = -2; } else if (right && !left) { if (my_x < 48) my_x += 2; direction = 2; } if (my_x & 15) my_x += direction; // make sure it parks on a beam when you release if (fire && !firing) { missile_x = (int)(my_x+8)&(int)0xf0; missile_y = GRIDLOW; firing = 1; } if (firing) draw_missile(); draw_moving_grid(depth); draw_meanies(); draw_me(); if (actiontick == 0) { // update game state - enemy AI... int i; meanie_x[0] += meanie_dx[0]; if (meanie_x[0] == 64-16) meanie_dx[0] = -meanie_dx[0]; if (meanie_x[0] == -64+16) meanie_dx[0] = -meanie_dx[0]; for (i = 0; i < MAX_MEANIES; i++) { meanie_y[i] -= granularity+meanie_dy[i]; if (meanie_y[i] <= -64) meanie_y[i] = 64; } depth -= granularity; if (depth <= 0) depth = 32; } if (slowmode) actiontick = (actiontick + 1)&1; } return 0; }