#include #include #include #include #include "debugger.c" #define begin { #define end } #define ScreenTop 20 #define ScreenBot 220 // Colors #define black 0b00000000 #define green 0b00000010 #define blue 0b00000001 #define white 0b00000011 // Player position #define px 32 #define py 50 // Game states #define Game 0 #define Score 1 #define Bonus 2 #pragma regalloc- //I allocate the registers myself #pragma optsize- //optimize for speed //NOTE that v1 to v8 and i must be in registers! register char v1 @4; register char v2 @5; register char v3 @6; register char v4 @7; register char v5 @8; register char v6 @9; register char v7 @10; register char v8 @11; register int i @12; #pragma regalloc+ // methods void init(void); void update(void); int getByteLoc(char x, char y); void writePixel(char x, char y, unsigned char color); void writePlayer(unsigned char color); void writeTree(char x, char y, unsigned char color); void writePacmanA(char x, char y, unsigned char color); void writePacmanB(char x, char y, unsigned char color); void put_char(char x, char y, char c); void put_string(char x, char y, unsigned char *str); #define numObj 7 // Game variables unsigned int LineCount; unsigned char screen[1600]; unsigned char Ain; unsigned char tilt; signed int objX[numObj], objY[numObj]; signed int vxtable[5], vytable[5]; unsigned char index; unsigned int score; // score unsigned char state; // state unsigned char pactimer; unsigned char pacstate; signed int pacX; signed int pacY; unsigned int scoretimer; unsigned int collideCount; // Strings unsigned char scorestr[6]; unsigned char losestr[] = "SCORE:"; // Character bitmaps flash char smallbitmap[39][5]={ //0 0b11101110, 0b10101010, 0b10101010, 0b10101010, 0b11101110, //1 0b01000100, 0b11001100, 0b01000100, 0b01000100, 0b11101110, //2 0b11101110, 0b00100010, 0b11101110, 0b10001000, 0b11101110, //3 0b11101110, 0b00100010, 0b11101110, 0b00100010, 0b11101110, //4 0b10101010, 0b10101010, 0b11101110, 0b00100010, 0b00100010, //5 0b11101110, 0b10001000, 0b11101110, 0b00100010, 0b11101110, //6 0b11001100, 0b10001000, 0b11101110, 0b10101010, 0b11101110, //7 0b11101110, 0b00100010, 0b01000100, 0b10001000, 0b10001000, //8 0b11101110, 0b10101010, 0b11101110, 0b10101010, 0b11101110, //9 0b11101110, 0b10101010, 0b11101110, 0b00100010, 0b01100110, //: 0b00000000, 0b01000100, 0b00000000, 0b01000100, 0b00000000, //= 0b00000000, 0b11101110, 0b00000000, 0b11101110, 0b00000000, //blank 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, //A 0b11101110, 0b10101010, 0b11101110, 0b10101010, 0b10101010, //B 0b11001100, 0b10101010, 0b11101110, 0b10101010, 0b11001100, //C 0b11101110, 0b10001000, 0b10001000, 0b10001000, 0b11101110, //D 0b11001100, 0b10101010, 0b10101010, 0b10101010, 0b11001100, //E 0b11101110, 0b10001000, 0b11101110, 0b10001000, 0b11101110, //F 0b11101110, 0b10001000, 0b11101110, 0b10001000, 0b10001000, //G 0b11101110, 0b10001000, 0b10001000, 0b10101010, 0b11101110, //H 0b10101010, 0b10101010, 0b11101110, 0b10101010, 0b10101010, //I 0b11101110, 0b01000100, 0b01000100, 0b01000100, 0b11101110, //J 0b00100010, 0b00100010, 0b00100010, 0b10101010, 0b11101110, //K 0b10001000, 0b10101010, 0b11001100, 0b11001100, 0b10101010, //L 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b11101110, //M 0b10101010, 0b11101110, 0b11101110, 0b10101010, 0b10101010, //N 0b00000000, 0b11001100, 0b10101010, 0b10101010, 0b10101010, //O 0b01000100, 0b10101010, 0b10101010, 0b10101010, 0b01000100, //P 0b11101110, 0b10101010, 0b11101110, 0b10001000, 0b10001000, //Q 0b01000100, 0b10101010, 0b10101010, 0b11101110, 0b01100110, //R 0b11101110, 0b10101010, 0b11001100, 0b11101110, 0b10101010, //S 0b11101110, 0b10001000, 0b11101110, 0b00100010, 0b11101110, //T 0b11101110, 0b01000100, 0b01000100, 0b01000100, 0b01000100, //U 0b10101010, 0b10101010, 0b10101010, 0b10101010, 0b11101110, //V 0b10101010, 0b10101010, 0b10101010, 0b10101010, 0b01000100, //W 0b10101010, 0b10101010, 0b11101110, 0b11101110, 0b10101010, //X 0b00000000, 0b10101010, 0b01000100, 0b01000100, 0b10101010, //Y 0b10101010, 0b10101010, 0b01000100, 0b01000100, 0b01000100, //Z 0b11101110, 0b00100010, 0b01000100, 0b10001000, 0b11101110 }; /************EXTERNAL INTERRUPT***************/ #pragma warn- // The external interrupt 0 triggers from PORT D.2 (V1 from the ELM304) interrupt [EXT_INT0] void ext0(void) begin // Wait 4.7 us during the backporch phase for the second sync pulse from V2 #asm ; wait for 75 cycles at the start of HBLANK (~4.7us) - 3 cycles/iteration = 25 iterations ; one cycle is 0.0625 us or 62.5 ns ldi r19,25 hwait: dec r19 brne hwait #endasm // If D.3 (V2 from the ELM304) is high, this means we triggered on a horizontal sync if (PIND.3 == 1) begin if (LineCount >= 20 && LineCount < 220) { //compute byte index for beginning of the next line //left-shift 4 would be individual lines // <<3 means line-double the pixels //The 0xfff8 truncates the odd line bit //i=(LineCount-ScreenTop)<<3 & 0xfff8; // #asm push r16 lds r12, _LineCount lds r13, _LineCount+1 ldi r16, 20 sub r12, r16 ldi r16, 0 sbc r13, r16 lsl r12 rol r13 lsl r12 rol r13 lsl r12 rol r13 mov r16, r12 andi r16, 0xf0 mov r12, r16 pop r16 #endasm //load 16 registers with screen info #asm push r14 push r15 push r16 push r17 push r18 push r19 push r26 push r27 ldi r26,low(_screen) ;base address of screen ldi r27,high(_screen) add r26,r12 ;offset into screen (add i) adc r27,r13 ld r4,x+ ;load 16 registers and inc pointer ld r5,x+ ld r6,x+ ld r7,x+ ld r8,x+ ld r9,x+ ld r10,x+ ld r11,x+ ld r12,x+ ld r13,x+ ld r14,x+ ld r15,x+ ld r16,x+ ld r17,x+ ld r18,x+ ld r19,x pop r27 pop r26 #endasm // macro to output the 4 pixels in a byte serially to TV #asm ; need to use IN R30, 0x15 to clear PortC before using this macro ; but first a macro to make the code shorter ; the macro takes a register number as a parameter ; and dumps its bits serially to portD.6 ; the nop can be eliminated to make the display narrower .macro blastit ;regnum BST @0,7 BLD R30,1 BST @0,6 BLD R30,0 nop nop nop OUT 0x15,R30 BST @0,5 BLD R30,1 BST @0,4 BLD R30,0 nop nop nop OUT 0x15,R30 BST @0,3 BLD R30,1 BST @0,2 BLD R30,0 nop nop nop OUT 0x15,R30 BST @0,1 BLD R30,1 BST @0,0 BLD R30,0 nop nop nop OUT 0x15,R30 .endm #endasm //print all 16 bytes of the line #asm IN R30, 0x15 blastit r4 ;video line -- byte 1 blastit r5 ;byte 2 blastit r6 ;byte 3 blastit r7 ;byte 4 blastit r8 ;byte 5 blastit r9 ;byte 6 blastit r10 ;byte 7 blastit r11 ;byte 8 blastit r12 ;byte 9 blastit r13 ;byte 10 blastit r14 ;byte 11 blastit r15 ;byte 12 blastit r16 ;byte 13 blastit r17 ;byte 14 blastit r18 ;byte 15 blastit r19 ;byte 16 clt ;clear video after the last pixel on the line IN R30,0x15 BLD R30,1 BLD R30,0 OUT 0x15,R30 pop r19 pop r18 pop r17 pop r16 pop r15 pop r14 #endasm } //update the curent scanline number LineCount++; end // Else D.3 is low, meaning that we are triggering on vertical blanking (vertical sync also occurs during this time) else begin LineCount = 1; end end // interrupt end #pragma warn+ /************MAIN LOOP************************************/ void main(void) begin init(); //The following loop executes once/video line during lines //220-20, then does all of the frame-end processing while(1) begin //stall here until next line starts //sleep enable; mode=idle //use sleep to make entry into sync ISR uniform time #asm ("sleep"); //The following code executes during the vertical blanking //Code here can be as long as //a total of 60 lines x 63.5 uSec/line x 8 cycles/uSec if (LineCount==220) begin // If player hasn't lost yet if (state == Game || state == Bonus) { //get the sample Ain = ADCH; //start another conversion ADCSR.6=1; if (collideCount != 0) collideCount--; //if the player has not recently crashed, update movement if (collideCount < 25) { // Translate accelerometer controls // Turning left if (Ain < 135) // old: 128 { index = 1; // Fast turning from right to left if ((tilt) > 70) { tilt -= 3; } // Else turning from center to the left - turn at normal speed else if (tilt > 1) { tilt--; } } // Going straight else if (Ain < 148) // old : 158 { index = 2; } // Turning right else { index = 3; // Fast turning from left to right if ((tilt) < 50) { tilt += 3; } // Else turning from the center to the right - turn at normal speed else if (tilt < 121) { tilt++; } } // Changes the orientation of the player based on tilt value if (tilt == 0) // horizontal state { index = 0; } else if (tilt == 122) // horizontal state { index = 4; } else if (tilt < 50) // -45 orientation is from 1-49 { index = 1; } else if (tilt < 70) // 0 orientation is from 50-69 { index = 2; } else // +45 orientation is from 70-121 { index = 3; } } // if collideCount // Draw player to screen writePlayer(white); // Update tree positions and draw them to screen update(); // Update the score score++; // Pacman animation if (state == Bonus && collideCount == 0) { // Pacman with open mouth if (pactimer == 0 && pacstate == 0) { // Clear previous pacman writePacmanB(pacX >> 8, pacY >> 8, black); pacX += 1150; // Draw new pacman writePacmanA(pacX >> 8, pacY >> 8, blue); pactimer = 5; pacstate = 1; } // Pacman with closed mouth else if (pactimer == 0 && pacstate == 1) { // Clear previous pacman writePacmanA(pacX >> 8, pacY >> 8, black); pacY += 2000; // This is when pacman intercepts the player, switch to score state if ((pacY >> 8)>= 45) { state = Score; // Destroy the player avatar writePlayer(black); } // Draw new pacman writePacmanB(pacX >> 8, pacY >> 8, blue); pactimer = 5; pacstate = 0; } pactimer--; } // if state == Bonus } // if state == Game // Else in the scoring state else if (state == Score) { if (scoretimer == 0) { // Write numerical score to screen sprintf(scorestr, "%05d", score); put_string(40,90,scorestr); } else if (scoretimer == 30) { // Write "SCORE:" to screen put_string(0,90,losestr); scoretimer--; } else { scoretimer--; } } // if state == Score end //line 221 end //while end //main /************INITIALIZATION************************************/ void init(void) begin // Port D.2 and D.3 are inputs for synch signals V1 and V2 from the ELM, respectively DDRD = 0b11110011; // Port C.2, C.1, and C.0 are RGB outputs, respectively DDRC = 0x07; PORTC = 0; //initialize synch constants LineCount = 1; MCUCR |= 0b10000011; // interupt on edge of external interupts and enable sleep mode GICR = 0b01000000;// enable external interupt //init the A to D converter //channel zero/ left adj /EXTERNAL Aref //!!!CONNECT Aref jumper!!!! ADMUX = 0b00100000; //enable ADC and set prescaler to 1/128*16MHz=125,000 //and clear interupt enable //and start a conversion ADCSR = 0b11000111; // Initialize game variables tilt = 60; index = 3; state = Game; score = 0; collideCount = 0; scoretimer = 50; pactimer = 0; pacstate = 0; pacX = -256; pacY = -256; // Initialize velocity table // -90 vxtable[0] = 0; vytable[0] = 0; // -45 vxtable[1] = 128; vytable[1] = 256; // 0 vxtable[2] = 0; vytable[2] = 256; // +45 vxtable[3] = -128; vytable[3] = 256; // +90 vxtable[4] = 0; vytable[4] = 0; // Set up the tree array initially to be empty (denoted by -1) for (i = 0; i < numObj; i++) { objY[i] = -1; } // Turn on interrupts #asm ("sei"); end // Update function happens every scanline void update(void) { unsigned char i; // Iterate through tree array for (i = 0; i < numObj; i++) { // If a tree exists at this index, and if it is within bounds, if (objY[i] != -1 && (char)(objX[i] >> 8) > -12 && (char)(objX[i] >> 8) < 76) { // Clear old object writeTree((char)(objX[i] >> 8), (char)(objY[i] >> 8), black); // Update object if it isn't out of y-bounds if (objY[i] + vytable[index] < (100 << 8)) { // Position update of tree objX[i] += vxtable[index]; objY[i] += vytable[index]; // Collision detection between player and tree if (((char)(objX[i]>>8)) >= px - 3 && ((char)(objX[i]>>8)) <= px + 2 && ((char)(objY[i]>>8)) == py - 2) { if (index < 3) { index = 0; tilt = 0; } else { index = 4; tilt = 122; } if (state == Game) { state = Bonus; collideCount = 50; } } // Draw tree at new position writeTree((char)(objX[i] >> 8), (char)(objY[i] >> 8), green); } // Else it has passed the bottom of the screen, erase it by setting it to -1 else { objY[i] = -1; } } // A tree doesn't exist at this index, so there is a possibility of a new random // tree at a random position from the top of the screen else { int m; m = rand() % 100; if (m < 3) { objX[i] = ((rand() % 88) - 12) << 8; objY[i] = 0; } } } } /************DISPLAY FUNCTIONS***************/ // Upper left corner of the screen is x,y coordinates (0,0) int getByteLoc(char x, char y) { unsigned int byteLocation; // store the actual location of the pixel in memory // find the memory location, given the x,y coordinates return byteLocation = ((unsigned int)((unsigned int)y<<4) + (x>>2)); } // Method to write a single pixel to the screen array void writePixel(char x, char y, unsigned char color) { unsigned char localPixel; unsigned char temp; unsigned char modR; localPixel = color; temp = screen[getByteLoc(x,y)]; modR = x%4; // Checks to make sure pixel location is within bounds if (x >= 0 && x < 64 && y >= 0 && y < 100) { // Determines which 2 bits of the byte are written, since 1 pixel = 2 bits switch (modR) { case 0: screen[getByteLoc(x,y)] = (temp & 0x3f) | ((localPixel << 6) & 0xc0); break; case 1: screen[getByteLoc(x,y)] = (temp & 0xcf) | ((localPixel << 4) & 0x30); break; case 2: screen[getByteLoc(x,y)] = (temp & 0xf3) | ((localPixel << 2) & 0x0c); break; case 3: screen[getByteLoc(x,y)] = (temp & 0xfc) | ((localPixel) & 0x03); break; } } } // Method for drawing the player avatar void writePlayer(unsigned char color) { // clear the old image writePixel(px+0,py+0,black); writePixel(px+1,py+0,black); writePixel(px+2,py+0,black); writePixel(px+0,py+1,black); writePixel(px+1,py+1,black); writePixel(px+2,py+1,black); writePixel(px+0,py+2,black); writePixel(px+1,py+2,black); writePixel(px+2,py+2,black); // Draw based on player's orientation switch(index) { /* horizontal case 000 111 000 */ case 0: case 4: writePixel(px+0, py+1, color); writePixel(px+1, py+1, color); writePixel(px+2, py+1, color); break; /* vertical case 010 010 010 */ case 2: writePixel(px+1, py+0, color); writePixel(px+1, py+1, color); writePixel(px+1, py+2, color); break; /* -45 100 010 001 */ case 1: writePixel(px+0, py+0, color); writePixel(px+1, py+1, color); writePixel(px+2, py+2, color); break; /* +45 001 010 100 */ case 3: writePixel(px+2, py+0, color); writePixel(px+1, py+1, color); writePixel(px+0, py+2, color); break; } } // Method to draw a tree on screen void writeTree(char x, char y, unsigned char color) { /* 00100 01110 11111 00100 */ writePixel(x+2, y+0, color); writePixel(x+1, y+1, color); writePixel(x+2, y+1, color); writePixel(x+3, y+1, color); writePixel(x+0, y+2, color); writePixel(x+1, y+2, color); writePixel(x+2, y+2, color); writePixel(x+3, y+2, color); writePixel(x+4, y+2, color); writePixel(x+2, y+3, color); } // Method to draw pacman with its mouth open void writePacmanA(char x, char y, unsigned char color) { /* 000111000 001000100 010001000 010010000 010001000 001000100 000111000 */ writePixel(x+3, y+0, color); writePixel(x+4, y+0, color); writePixel(x+5, y+0, color); writePixel(x+2, y+1, color); writePixel(x+6, y+1, color); writePixel(x+1, y+2, color); writePixel(x+5, y+2, color); writePixel(x+1, y+3, color); writePixel(x+4, y+3, color); writePixel(x+1, y+4, color); writePixel(x+5, y+4, color); writePixel(x+2, y+5, color); writePixel(x+6, y+5, color); writePixel(x+3, y+6, color); writePixel(x+4, y+6, color); writePixel(x+5, y+6, color); } // Method to draw pacman with its mouth closed void writePacmanB(char x, char y, unsigned char color) { /* 000111000 001000100 010000010 010011110 010000010 001000100 000111000 */ writePixel(x+3, y+0, color); writePixel(x+4, y+0, color); writePixel(x+5, y+0, color); writePixel(x+2, y+1, color); writePixel(x+6, y+1, color); writePixel(x+1, y+2, color); writePixel(x+7, y+2, color); writePixel(x+1, y+3, color); writePixel(x+4, y+3, color); writePixel(x+5, y+3, color); writePixel(x+6, y+3, color); writePixel(x+1, y+4, color); writePixel(x+7, y+4, color); writePixel(x+2, y+5, color); writePixel(x+6, y+5, color); writePixel(x+3, y+6, color); writePixel(x+4, y+6, color); writePixel(x+5, y+6, color); } // Method to draw a single char to screen void put_char(char x, char y, char c) { v7 = x; for (v6=0;v6<5;v6++) { v1 = smallbitmap[c][v6]; v8 = y+v6; writePixel(v7, v8, (v1 >> 7) & blue); writePixel(v7+1, v8, (v1 >> 6) & blue); writePixel(v7+2, v8, (v1 >> 5) & blue); } } // Method to put a string on screen void put_string(char x, char y, unsigned char *str) { char k ; for (k=0; str[k]!=0; k++) { if (str[k]>=0x30 && str[k]<=0x3a) put_char(x,y,str[k]-0x30); else put_char(x,y,str[k]-0x40+12); x = x+6; } }