#include #include #include #include #include #include #include #include "bitmap.h" #include "sound.h" const bool SOUND_ENABLE = false; const short INIT_X = 0; const short INIT_Y = 48; const short MAX_X = 90; // number of milliseconds we refresh screen const unsigned long display_interval = 100; // number of milliseconds we refresh nunchuck info const unsigned long nunchuk_interval = 100; const unsigned int sound_tempo = 10; const int dataPin = 11; const int clockPin = 5; const int latchPin = 6; U8G2_ST7920_128X64_2_SW_SPI u8g2(U8G2_R0, /* clock=*/ 2, /* data=*/ 10, /* cs=*/ 7); //A5 A4 A3 A2 ArduinoNunchuk nunchuk = ArduinoNunchuk(); Tone tone1; // Carrot position short posX = INIT_X; short posY = INIT_Y; unsigned int nextLaneY = INIT_Y - 16; unsigned long last_display = millis(); unsigned long last_nunchuck = millis(); unsigned long last_note = millis(); unsigned long next_note = millis(); short notes_index = 0; short intro_size = sizeof(notes_intro)/sizeof(notes_intro[0]); enum FishType { FT_NORMAL, FT_LIFE, FT_BOMB}; const short NUM_FISHES = 12; short fishes[NUM_FISHES][3] = { {0,1,FT_NORMAL},{0,1, FT_NORMAL},{0,1,FT_NORMAL}, {0,16,FT_NORMAL},{0,16,FT_NORMAL},{0,16,FT_NORMAL}, {0,32,FT_NORMAL},{0,32,FT_NORMAL},{0,32,FT_NORMAL}, {0,48,FT_NORMAL},{0,48,FT_LIFE},{0,48,FT_NORMAL} }; bool game_init = true; bool jump = false; bool jumpBack = false; bool jumpInProgress = false; int score = 0; int max_score = 0; short lives = 5; int lives_leds[] = { 0b00000000, 0b00000001, 0b00000011, 0b00000111, 0b00001111, 0b00011111, 0b00111111, 0b00111111, 0b00111111, 0b00111111 }; //set A3 and A2 has +5V / GND void nunchuck_setpowerpins() { #define pwrpin PORTC3 #define gndpin PORTC2 DDRC |= _BV(pwrpin) | _BV(gndpin); PORTC &=~ _BV(gndpin); PORTC |= _BV(pwrpin); delay(100); // wait for things to stabilize } void setup(void) { //init serial for debug Serial.begin(115200); //init leds pinMode( dataPin, OUTPUT ); pinMode( clockPin, OUTPUT ); pinMode( latchPin, OUTPUT ); //init nunchuck nunchuck_setpowerpins(); nunchuk.init(); //init lcd u8g2.begin(); //init sound tone1.begin(8); //test leds for(int i = 0; i <= 9; i++){ update_lives_leds(lives_leds[i]); delay(200); } } void update_lives_leds( int value ){ digitalWrite( latchPin, LOW ); shiftOut( dataPin, clockPin, MSBFIRST,value ); digitalWrite( latchPin, HIGH ); } void play_intro(){ if(SOUND_ENABLE){ if(millis() >= next_note){ next_note = millis() + interval_intro[notes_index]; tone1.play(notes_intro[notes_index], interval_intro[notes_index]); if(notes_index < intro_size - 1){ notes_index++; } } } } void play_sound(uint16_t _note, uint32_t _duration){ if(SOUND_ENABLE){ tone1.play(_note, _duration); } } void display_welcome_page() { u8g2.setFont(u8g2_font_5x7_mf); u8g2.drawStr(0, 7, "Welcome to Carrot game!"); u8g2.drawStr(15, 25, "Press Z to start."); u8g2.drawXBMP(INIT_X, INIT_Y, 16, 16, fish); if(max_score != 0){ char num_str[] = "000"; sprintf(num_str, "%03d", max_score); u8g2.drawStr(50, 50, "Last score: "); u8g2.drawStr(110, 50, num_str); } } void display_game() { u8g2.setFont(u8g2_font_4x6_tf); u8g2.drawStr(108, 50, "SCORE:"); //u8g2.drawStr(108, 30, "LIVES:"); u8g2.drawStr(108, 10, "MAX:"); //draw score u8g2.setFont(u8g2_font_5x7_mf); char num_str[] = "000"; sprintf(num_str, "%03d", score); u8g2.drawStr(110, 62, num_str); sprintf(num_str, "%03d", max_score); u8g2.drawStr(110, 20, num_str); short y = 0; short x = 0; for(int i = 0; i < lives; i++){ //display 3 hearts per line if (i % 3 == 0){ y = y +1; x = 0; } u8g2.drawXBMP(110 + 6 * x, 20 + 6 * y, 5, 5, heart); x = x + 1; } //draw fishes for (int i = 0; i < NUM_FISHES; i++) { if(fishes[i][0] != NULL){ if(fishes[i][0] < MAX_X){ if(fishes[i][2] == FT_NORMAL){ u8g2.drawXBMP(fishes[i][0], fishes[i][1], 16, 16, fish_reverse); } else if(fishes[i][2] == FT_LIFE){ u8g2.drawXBMP(fishes[i][0], fishes[i][1], 16, 16, fish_life); } else if(fishes[i][2] == FT_BOMB){ u8g2.drawXBMP(fishes[i][0], fishes[i][1], 16, 16, fish_bomb); } } } } //draw carrot u8g2.drawXBMP(posX, posY, 16, 16, carrot); //swimelanes u8g2.drawHLine(0, 0, MAX_X + 16); //top u8g2.drawHLine(0, 16, MAX_X + 16); u8g2.drawHLine(0, 32, MAX_X + 16); u8g2.drawHLine(0, 48, MAX_X + 16); u8g2.drawHLine(0, 63, MAX_X + 16); //bottom u8g2.drawVLine(MAX_X + 16, 0, 48); } void init_game(){ Serial.print("Number of fishes: "); Serial.println(sizeof(fishes)); score = 0; max_score = 0; lives = 5; update_lives_leds(lives_leds[lives]); posX = INIT_X; posY = INIT_Y; for ( short i = 0 ; i < NUM_FISHES; i++){ fishes[i][0]= random(MAX_X + 1,255); } } void missed_or_bomb(){ score = score - 10; lives = lives - 1; update_lives_leds(lives_leds[lives]); play_sound(NOTE_B1,300); if (score <= 0 || lives == 0){ play_sound(NOTE_G1,300); play_sound(NOTE_F1,300); play_sound(NOTE_E1,300); play_sound(NOTE_D1,300); play_sound(NOTE_C1,300); game_init = true; } } void compute_fishes_position(){ short fish_step = (200 + score)/200; for (int i = 0; i < NUM_FISHES; i++) { if(fishes[i][0] != NULL){ //fish alive if(fishes[i][0] <= fish_step) { fishes[i][0] = random(MAX_X+1,255); // do not remove lives if it was a bomb if(fishes[i][2] != FT_BOMB){ missed_or_bomb(); } } //move fish to the left else{ fishes[i][0] = fishes[i][0] - fish_step; } //does carrot eat the fish if( (posX > (fishes[i][0] - 8) && posX < (fishes[i][0] + 8) ) && (posY > (fishes[i][1] - 8) && posY < (fishes[i][1] + 8) ) ){ if(fishes[i][2] == FT_BOMB){ missed_or_bomb(); } else{ play_sound(NOTE_B5,100); score = score + 10; if (score > max_score){ max_score = score; } } if(fishes[i][2] == FT_LIFE){ if(lives < 6){ lives = lives + 1; update_lives_leds(lives_leds[lives]); } } fishes[i][0] = random(MAX_X+1,255); //random type short rdm_type = random(1,100); if(rdm_type < 80){ fishes[i][2] = FT_NORMAL; } else if (rdm_type >= 80 and rdm_type < 90){ fishes[i][2] = FT_LIFE; } else{ fishes[i][2] = FT_BOMB; } } } } } void compute_cat_position() { if (game_init) { if (posX < MAX_X - 16) { posX = posX + 2; } else { posX = INIT_X; if (posY < 48) { posY = posY + 16; } else { posY = INIT_Y; } } } //game else { //compute X pos if (nunchuk.analogX < 120 && posX >= 4) { if (nunchuk.analogX < 80) { if(posX >= 8){ posX = posX - 8; }else{ posX = posX - 4; } } else { posX = posX - 4; } } if (nunchuk.analogX > 140 && posX < (MAX_X - 8)) { if (nunchuk.analogX > 180) { posX = posX + 8; } else { posX = posX + 4; } } //compute jump //detect a new jump if((nunchuk.zButton == 1 || nunchuk.analogY > 160) && !jump && !jumpBack && posY > 0){ Serial.println("jump!"); //tone1.play(NOTE_B4,500); jump = true; jumpInProgress = true; nextLaneY = posY - 16; posY = posY - 4; Serial.println(nextLaneY); } else { //continue a current jump if (jump) { if (posY > nextLaneY && jumpInProgress) { posY = posY - 4; } else { if (posY != nextLaneY){ jumpInProgress = false; posY = posY + 4; } else{ jump = false; } } } } if((nunchuk.cButton == 1 || nunchuk.analogY < 100) && !jump && !jumpBack && posY < 48){ Serial.println("jump bottom!"); //tone1.play(NOTE_B2,500); jumpBack = true; jumpInProgress = true; nextLaneY = posY + 16; posY = posY + 4; Serial.println(nextLaneY); } else { //continue a current jump if (jumpBack) { if (posY < nextLaneY && jumpInProgress) { posY = posY + 4; } else { if (posY != nextLaneY){ jumpInProgress = false; posY = posY - 4; } else{ jumpBack = false; } } } } } } void loop(void) { if(millis() - last_display >= display_interval){ u8g2.firstPage(); do { if(game_init){ display_welcome_page(); } else{ display_game(); } } while ( u8g2.nextPage() ); last_display = millis(); } if(millis() - last_nunchuck >= nunchuk_interval){ nunchuk.update(); if(init){ if(nunchuk.zButton == 1){ if(game_init){ init_game(); game_init = false; } } } last_nunchuck = millis(); if(game_init){ play_intro(); } else{ compute_cat_position(); compute_fishes_position(); } } // Serial.print(posX); // Serial.print(' '); // Serial.println(posY); // Serial.print(nunchuk.analogX, DEC); // Serial.print(' '); // Serial.println(nunchuk.analogY, DEC); // Serial.print(' '); // Serial.print(nunchuk.accelX, DEC); // Serial.print(' '); // Serial.print(nunchuk.accelY, DEC); // Serial.print(' '); // Serial.print(nunchuk.accelZ, DEC); // Serial.print(' '); // Serial.print(nunchuk.zButton, DEC); // Serial.print(' '); // Serial.println(nunchuk.cButton, DEC); //delay(interval); }