├── esp12e Arudboy.fzz ├── ESP12E Arduboy .jpg ├── ESP8266 Arduboy.fzz ├── ESP8266 Arduboy.jpg ├── ESP8266 Arduboy Video.jpg ├── extras ├── assets │ ├── arduboy_logo.png │ └── arduboy_screen.png └── docs │ └── FILE_DESCRIPTIONS.md ├── examples ├── ESP8266_Buttons │ ├── README.md │ └── ESP8266_Buttons.ino ├── ESP8266_PlayTune │ ├── README.md │ └── ESP8266_PlayTune.ino ├── trafficlight │ ├── Credentials.h │ └── trafficlight.ino ├── ESP8266_Mystic_Balloon │ ├── vec2.h │ ├── elements.h │ ├── ESP8266_Mystic_Balloon.ino │ ├── inputs.h │ ├── menu.h │ ├── globals.h │ ├── game.h │ ├── enemies.h │ └── player.h ├── ESP8266_ShadowRunner │ ├── game.h │ ├── globals.h │ ├── runner.h │ ├── menu.h │ ├── items.h │ ├── ESP8266_ShadowRunner.ino │ └── playfield.h ├── ESP8266_ArduBOYNG │ └── README.md ├── ESP8266_HelloWorld │ └── ESP8266_HelloWorld.ino ├── ESP8266_Sirene │ ├── globals.h │ ├── inputs.h │ ├── ESP8266_Sirene.ino │ ├── menu.h │ ├── elements.h │ ├── game.h │ └── player.h ├── ESP8266_VidTest │ └── ESP8266_VidTest.ino ├── ESP8266_picovaders │ └── pitches.h ├── ESP8266_Picovaders_Paddle │ └── pitches.h ├── ESP8266_evade │ ├── globals.h │ ├── bullet.h │ ├── letters.h │ ├── messagecatalog.h │ └── enemy.h ├── ESP8266_BeepDemo │ └── ESP8266_BeepDemo.ino └── ESP8266_PaddleTest │ └── ESP8266_PaddleTest.ino ├── Schematic_ESP8266-game-console_ESP8266-Game-Console_20190804224816.pdf ├── src ├── SpritesCommon.h ├── Arduboy2Audio.cpp ├── EEPROM.h ├── Arduboy2Beep.cpp ├── ab_logo.c ├── SpritesB.h ├── EEPROM.cpp ├── Arduboy2Audio.h ├── SpritesB.cpp └── glcdfont.c ├── library.json ├── library.properties ├── eepromNote.txt ├── EEPROM.h ├── keywords.txt ├── EEPROM.cpp ├── LICENSE.txt └── README.md /esp12e Arudboy.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheungbx/esp8266_arduboy2/HEAD/esp12e Arudboy.fzz -------------------------------------------------------------------------------- /ESP12E Arduboy .jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheungbx/esp8266_arduboy2/HEAD/ESP12E Arduboy .jpg -------------------------------------------------------------------------------- /ESP8266 Arduboy.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheungbx/esp8266_arduboy2/HEAD/ESP8266 Arduboy.fzz -------------------------------------------------------------------------------- /ESP8266 Arduboy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheungbx/esp8266_arduboy2/HEAD/ESP8266 Arduboy.jpg -------------------------------------------------------------------------------- /ESP8266 Arduboy Video.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheungbx/esp8266_arduboy2/HEAD/ESP8266 Arduboy Video.jpg -------------------------------------------------------------------------------- /extras/assets/arduboy_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheungbx/esp8266_arduboy2/HEAD/extras/assets/arduboy_logo.png -------------------------------------------------------------------------------- /extras/assets/arduboy_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheungbx/esp8266_arduboy2/HEAD/extras/assets/arduboy_screen.png -------------------------------------------------------------------------------- /examples/ESP8266_Buttons/README.md: -------------------------------------------------------------------------------- 1 | Buttons 2 | ======= 3 | 4 | An example that demonstrates how to capture input from the buttons. 5 | -------------------------------------------------------------------------------- /Schematic_ESP8266-game-console_ESP8266-Game-Console_20190804224816.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheungbx/esp8266_arduboy2/HEAD/Schematic_ESP8266-game-console_ESP8266-Game-Console_20190804224816.pdf -------------------------------------------------------------------------------- /src/SpritesCommon.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file SpritesCommon.h 3 | * \brief 4 | * Common header file for sprite functions 5 | */ 6 | 7 | #ifndef SpritesCommon_h 8 | #define SpritesCommon_h 9 | 10 | #define SPRITE_MASKED 1 11 | #define SPRITE_UNMASKED 2 12 | #define SPRITE_OVERWRITE 2 13 | #define SPRITE_PLUS_MASK 3 14 | #define SPRITE_IS_MASK 250 15 | #define SPRITE_IS_MASK_ERASE 251 16 | #define SPRITE_AUTO_MODE 255 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Arduboy2", 3 | "keywords": "arduboy, game", 4 | "description": "An alternative library for content creation on the Arduboy miniature gaming platform", 5 | "repository": 6 | { 7 | "type": "git", 8 | "url": "https://github.com/MLXXXp/Arduboy2.git" 9 | }, 10 | "version": "5.2.0", 11 | "export": 12 | { 13 | "exclude": "extras" 14 | }, 15 | "frameworks": "arduino", 16 | "platforms": "atmelavr" 17 | } 18 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Arduboy2 2 | version=5.2.0 3 | author=Chris J. Martinez, Kevin Bates, Josh Goebel, Scott Allen, Ross O. Shoger 4 | maintainer=billy cheung (port to esp8266), original authors above. 5 | sentence=An alternative library for use with the ESP8266 Arduboy-like game system. 6 | paragraph=This is a fork of the Arduboy library for ESP8266 Arduboy-like machines 7 | category=Other 8 | url=https://github.com/cheungbx/esp8266_arduboy2 9 | architectures=esp8266,esp32 10 | includes=Arduboy2.h 11 | -------------------------------------------------------------------------------- /examples/ESP8266_PlayTune/README.md: -------------------------------------------------------------------------------- 1 | # PlayTune 2 | 3 | Play a musical composition using the Arduboy. 4 | 5 | Demonstrates playing music in the background while the "real" sketch code runs in the foreground. 6 | 7 | The ArduboyPlaytune library must be installed to use this sketch 8 | 9 | https://github.com/Arduboy/ArduboyPlayTune 10 | 11 | A small composition is stored by `byte PROGMEM score`. The score is started in the sketch loop using `playScore(score)`. 12 | 13 | D-Pad buttons will move the text and play a tone. 14 | 15 | The A button mutes the sound. The screen is inverted when sound is muted. 16 | 17 | The B button will turn sound back on if it's muted. 18 | 19 | -------------------------------------------------------------------------------- /examples/trafficlight/Credentials.h: -------------------------------------------------------------------------------- 1 | #define WIFIssid "BILLYWIFI" 2 | #define WIFIpassword "Xolmem13" 3 | 4 | #define OTA_password "Xolmem18" 5 | 6 | 7 | #define IO_USERNAME "dwong" 8 | #define IO_KEY "a52d93d0a1aa42e09850009bcb472012" 9 | #define MQTT_SERVER "io.adafruit.com" 10 | #define MQTT_SERVERPORT 1883 11 | #define MQTT_LUX "dwong/feeds/lux" 12 | #define MQTT_EC "dwong/feeds/ec" 13 | #define MQTT_AirTemp "dwong/feeds/airtemp" 14 | #define MQTT_Humidity "dwong/feeds/humidity" 15 | #define MQTT_Led "dwong/feeds/led" 16 | #define MQTT_LedOnHour "dwong/feeds/ledonhour" 17 | #define MQTT_LedOffHour "dwong/feeds/ledoffhour" 18 | #define MQTT_Pump "dwong/feeds/pump" 19 | #define MQTT_PumpOnInterval "dwong/feeds/pumponmin" 20 | #define MQTT_PumpOffInterval "dwong/feeds/pumpoffmin" 21 | #define MQTT_Upgrade "dwong/feeds/upgrade" 22 | -------------------------------------------------------------------------------- /examples/trafficlight/trafficlight.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Author: Billy Cheung 3 | 4 | Traffic LIght Demonstration 5 | 6 | */ 7 | 8 | #define red D6 // D6 LED output pin - left 9 | #define yellow D5 // D5 - LED output pin - up 10 | #define green D7 // D6 LED output pin - Right 11 | 12 | void light ( bool R, bool Y, bool G, int delaySecond) 13 | { 14 | if (R) digitalWrite(red, LOW); else digitalWrite(red, HIGH); 15 | if (Y) digitalWrite(yellow, LOW); else digitalWrite(yellow, HIGH); 16 | if (G) digitalWrite(green, LOW); else digitalWrite(green, HIGH); 17 | delay ( delaySecond * 1000); 18 | } 19 | 20 | 21 | void setup() { 22 | Serial.begin(115200); 23 | Serial.println(); 24 | Serial.print("Traffic LIght Demo Started"); 25 | 26 | pinMode(red, OUTPUT); 27 | pinMode(yellow, OUTPUT); 28 | pinMode(green, OUTPUT); 29 | 30 | light (0,0,0, 1 ); 31 | 32 | } 33 | 34 | 35 | 36 | 37 | void loop() { 38 | 39 | // R Y G Seconds 40 | light (0,0,1, 5); 41 | light (0,1,0, 2); 42 | light (1,0,0, 5); 43 | light (1,1,0, 2); 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /examples/ESP8266_Mystic_Balloon/vec2.h: -------------------------------------------------------------------------------- 1 | #ifndef _VEC2_ 2 | #define _VEC2_ 3 | 4 | struct vec2 5 | { 6 | int x; 7 | int y; 8 | 9 | vec2() : x(0), y(0) {} 10 | vec2(int vx, int vy) : x(vx), y(vy) {} 11 | 12 | vec2 &operator+=(const vec2 &rhs) 13 | { 14 | x += rhs.x; 15 | y += rhs.y; 16 | return *this; 17 | } 18 | 19 | vec2 &operator-=(const vec2 &rhs) 20 | { 21 | x -= rhs.x; 22 | y -= rhs.y; 23 | return *this; 24 | } 25 | 26 | vec2 &operator=(const vec2 &rhs) 27 | { 28 | x = rhs.x; 29 | y = rhs.y; 30 | return *this; 31 | } 32 | }; 33 | 34 | vec2 operator+(vec2 lhs, const vec2 &rhs) 35 | { 36 | //vec2 t = lhs; 37 | //t += rhs; 38 | return (lhs += rhs); 39 | } 40 | 41 | vec2 operator-(vec2 lhs, const vec2 &rhs) 42 | { 43 | //vec2 t = lhs; 44 | //t -= rhs; 45 | return (lhs -= rhs); 46 | } 47 | 48 | vec2 operator<<(vec2 lhs, const int &rhs) 49 | { 50 | lhs.x <<= rhs; 51 | lhs.y <<= rhs; 52 | return lhs; 53 | } 54 | 55 | vec2 operator>>(vec2 lhs, const int &rhs) 56 | { 57 | lhs.x >>= rhs; 58 | lhs.y >>= rhs; 59 | return lhs; 60 | } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /examples/ESP8266_ShadowRunner/game.h: -------------------------------------------------------------------------------- 1 | #ifndef GAME_H 2 | #define GAME_H 3 | 4 | #include 5 | #include "globals.h" 6 | #include "items.h" 7 | #include "playfield.h" 8 | 9 | void stateGameInitLevel() 10 | { 11 | runnerX = 0; 12 | runnerY = 28; 13 | scorePlayer = 0; 14 | nextLevelAt = 1000; 15 | lifePlayer = 128; 16 | level = 0; 17 | showitems = B00000000; 18 | gameState = STATE_GAME_PLAYING ; 19 | }; 20 | 21 | 22 | 23 | void stateGamePlaying() 24 | { 25 | drawBackGround(); 26 | drawFence(); 27 | drawItems(); 28 | drawRunner(); 29 | drawForGround(); 30 | drawScoreAndLive(); 31 | 32 | checkItems(); 33 | checkRunner(); 34 | checkCollisions(); 35 | checkScoreAndLevel(); 36 | checkInputs(); 37 | }; 38 | 39 | void stateGamePause() 40 | { 41 | sprites.drawSelfMasked(35, 4, pause, 0); 42 | drawCandle(56, 8); 43 | if (arduboy.justPressed(UP_BUTTON | DOWN_BUTTON | RIGHT_BUTTON)) gameState = STATE_GAME_PLAYING ; 44 | }; 45 | 46 | void stateGameOver() 47 | { 48 | sprites.drawSelfMasked(31, 16, gameOver, 0); 49 | drawScore(27, 44); 50 | if (arduboy.justPressed(A_BUTTON | B_BUTTON)) gameState = STATE_MENU_MAIN; 51 | }; 52 | 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /examples/ESP8266_ArduBOYNG/README.md: -------------------------------------------------------------------------------- 1 | # ArduBOYNG 2 | A simple game with two paddles and a ball BOYINGing around... 3 | 4 | Written for the awesome Arduboy by Kevin Bates. 5 | 6 | ## Installation 7 | Download, compile in Arduino, upload to Arduboy, enjoy. 8 | 9 | ## Instructions 10 | ###Menu 11 | - Directional keys to navigate and select 12 | - A or B to start the game 13 | 14 | ### Game 15 | - Up/down to steer the left paddle 16 | - A/B to steer the right paddle (in 2 players mode) 17 | 18 | ### Settings 19 | - Mode - who plays against whom 20 | - 1 player - left paddle controlled by a human, right paddle by Arduboy (default) 21 | - 2 players - both paddles controlled by humans 22 | - demo - both paddles controlled by Arduboy 23 | - Speed - initial veolocity of the ball 24 | - slow, normal (default), fast, insane 25 | - Points - points needed to win the game 26 | - 3, 5, 7, 9 27 | - AI - strength of Arduboy's play 28 | - dumb - Arduboy misses the ball every now and then 29 | - normal - Arduboy plays quite well (default) 30 | - smart - Arduboy plays pretty good 31 | - 100% - Arduboy never misses 32 | - Acceleration - speed increase at every paddle hit in % of initial speed 33 | - 0%, 1% (default), 3%, 5% 34 | -------------------------------------------------------------------------------- /extras/docs/FILE_DESCRIPTIONS.md: -------------------------------------------------------------------------------- 1 | # File Descriptions 2 | 3 | Documentation for files contained in this repository which aren't self explanatory. 4 | 5 | ### /library.properties 6 | 7 | Provides information so that this library can be installed and updated in the Arduino IDE using the [Library Manager](https://www.arduino.cc/en/Guide/Libraries#toc3). 8 | 9 | The value of *version* must be set to the latest stable tagged release. This should be changed and commited just before tagging the new release. 10 | 11 | See the [Arduino IDE 1.5: Library specification](https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification) for details. 12 | 13 | ### /library.json 14 | 15 | This JSON file is a manifest used by the [PlatformIO IDE](http://platformio.org/) to make this library available in its [Library Manager](http://docs.platformio.org/en/latest/librarymanager/index.html). 16 | 17 | The value of *version* must be set to the latest stable tagged release. This should be changed and commited just before tagging the new release. 18 | 19 | See the [PlatformIO library.json](http://docs.platformio.org/en/latest/librarymanager/config.html) documentation for details. 20 | 21 | ### /extras/assets/arduboy_logo.png
/extras/assets/arduboy_screen.png 22 | 23 | Templates used to create the ARDUBOY logo used in the *bootLogo()* function. 24 | 25 | ---------- 26 | 27 | -------------------------------------------------------------------------------- /src/Arduboy2Audio.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Arduboy2Audio.cpp 3 | * \brief 4 | * The Arduboy2Audio class for speaker and sound control. 5 | */ 6 | 7 | #include "Arduboy2.h" 8 | #include "Arduboy2Audio.h" 9 | 10 | bool Arduboy2Audio::audio_enabled = false; 11 | 12 | void Arduboy2Audio::on() 13 | { 14 | #ifndef ESP8266 15 | // fire up audio pins by seting them as outputs 16 | #ifdef ARDUBOY_10 17 | bitSet(SPEAKER_1_DDR, SPEAKER_1_BIT); 18 | bitSet(SPEAKER_2_DDR, SPEAKER_2_BIT); 19 | #else 20 | bitSet(SPEAKER_1_DDR, SPEAKER_1_BIT); 21 | #endif 22 | #endif 23 | audio_enabled = true; 24 | } 25 | 26 | void Arduboy2Audio::off() 27 | { 28 | audio_enabled = false; 29 | // shut off audio pins by setting them as inputs 30 | #ifndef ESP8266 31 | #ifdef ARDUBOY_10 32 | bitClear(SPEAKER_1_DDR, SPEAKER_1_BIT); 33 | bitClear(SPEAKER_2_DDR, SPEAKER_2_BIT); 34 | #else 35 | bitClear(SPEAKER_1_DDR, SPEAKER_1_BIT); 36 | #endif 37 | #endif 38 | } 39 | 40 | void Arduboy2Audio::toggle() 41 | { 42 | if (audio_enabled) 43 | off(); 44 | else 45 | on(); 46 | } 47 | 48 | void Arduboy2Audio::saveOnOff() 49 | { 50 | EEPROM.update(EEPROM_AUDIO_ON_OFF, audio_enabled); 51 | #ifndef ESP8266 52 | EEPROM.committ(); 53 | #endif 54 | } 55 | 56 | void Arduboy2Audio::begin() 57 | { 58 | if (EEPROM.read(EEPROM_AUDIO_ON_OFF)) 59 | if (true) 60 | on(); 61 | else 62 | off(); 63 | } 64 | 65 | bool Arduboy2Audio::enabled() 66 | { 67 | return audio_enabled; 68 | } 69 | -------------------------------------------------------------------------------- /eepromNote.txt: -------------------------------------------------------------------------------- 1 | Either replace the EEPROM.ccp and EEPROM.h files in 2 | windows - C:\Users\*your username*\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.6.3\libraries\EEPROM 3 | Mac - /Users/*your username*/Library/Adruino15/packages/esp8266/hardware/esp8266/2.6.3/libraries/EEPROM 4 | 5 | Or, change it by this step 6 | 1. go to your eeprom lib, on my win10 system the path looks like this: 7 | 8 | windows - C:\Users\*your username*\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.6.3\libraries\EEPROM 9 | Mac - /Users/*your username*/Library/Adruino15/packages/esp8266/hardware/esp8266/2.6.3/libraries/EEPROM 10 | 11 | 2. add something like this to your EEPROM.cpp : 12 | 13 | void EEPROMClass::update(int const address, uint8_t const value) { 14 | if (address < 0 || (size_t)address >= _size) 15 | return; 16 | if(!_data) 17 | return; 18 | 19 | // get data from eeprom 20 | uint8_t storedData = read(address); 21 | 22 | // check if the same 23 | if (storedData == value) 24 | return; 25 | 26 | // call of write() because it is different 27 | write(address, value); 28 | } 29 | 30 | and the coresponding header prototype to your EEPROM.h: 31 | 32 | void update(int const address, uint8_t const val); 33 | 34 | 3. now your code will compile, but It will still not work, the problem is you need to call: 35 | 36 | EEPROM.begin(*needed bytes of eeprom*); 37 | 38 | and 39 | 40 | EEPROM.commit(); 41 | 42 | after everytime you wrote data via update/put... functions. 43 | 44 | -------------------------------------------------------------------------------- /examples/ESP8266_ShadowRunner/globals.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOBALS_H 2 | #define GLOBALS_H 3 | 4 | #include 5 | #include 6 | // #include 7 | const unsigned int FRAME_RATE = 40; // Frame rate in frames per second 8 | #include "bitmaps.h" 9 | 10 | //define menu states (on main menu) 11 | #define STATE_MENU_INTRO 0 12 | #define STATE_MENU_MAIN 1 13 | #define STATE_MENU_HELP 2 14 | #define STATE_MENU_PLAY 3 15 | #define STATE_MENU_INFO 4 16 | #define STATE_MENU_SOUNDFX 5 17 | 18 | //define game states (on main menu) 19 | #define STATE_GAME_INIT_LEVEL 6 20 | #define STATE_GAME_PLAYING 7 21 | #define STATE_GAME_PAUSE 8 22 | #define STATE_GAME_OVER 9 23 | 24 | #define LEVEL_TO_START_WITH 0 25 | 26 | Arduboy2Base arduboy; 27 | Sprites sprites; 28 | // ArduboyTones sound(arduboy.audio.enabled); 29 | BeepPin1 beep; 30 | 31 | void sound(byte tone, byte duration) { 32 | if (arduboy.audio.enabled()) { 33 | beep.tone(beep.freq(tone), duration *2 ); 34 | } 35 | } 36 | 37 | //determines the state of the game 38 | byte gameState = STATE_MENU_INTRO; // start the game with the TEAM a.r.g. logo 39 | //generic variable to store menuSelection (on screens) 40 | byte menuSelection = STATE_MENU_PLAY; // PLAY menu item is pre-selected 41 | byte globalCounter = 0; 42 | 43 | // These are all getting a value in STATE_GAME_INIT 44 | int lifePlayer; 45 | unsigned long scorePlayer; 46 | unsigned long nextLevelAt; 47 | byte level = LEVEL_TO_START_WITH; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /examples/ESP8266_HelloWorld/ESP8266_HelloWorld.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Hello, World! example 3 | June 11, 2015 4 | Copyright (C) 2015 David Martinez 5 | All rights reserved. 6 | This code is the most basic barebones code for writing a program for Arduboy. 7 | 8 | This library is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU Lesser General Public 10 | License as published by the Free Software Foundation; either 11 | version 2.1 of the License, or (at your option) any later version. 12 | */ 13 | 14 | #include 15 | 16 | // make an instance of arduboy used for many functions 17 | Arduboy2 arduboy; 18 | 19 | 20 | // This function runs once in your game. 21 | // use it for anything that needs to be set only once in your game. 22 | void setup() { 23 | // initiate arduboy instance 24 | arduboy.begin(); 25 | 26 | // here we set the framerate to 15, we do not need to run at 27 | // default 60 and it saves us battery life 28 | arduboy.setFrameRate(15); 29 | } 30 | 31 | 32 | // our main game loop, this runs once every cycle/frame. 33 | // this is where our game logic goes. 34 | void loop() { 35 | // pause render until it's time for the next frame 36 | if (!(arduboy.nextFrame())) 37 | return; 38 | 39 | // first we clear our screen to black 40 | arduboy.clear(); 41 | 42 | // we set our cursor 5 pixels to the right and 10 down from the top 43 | // (positions start at 0, 0) 44 | arduboy.setCursor(4, 9); 45 | 46 | // then we print to screen what is in the Quotation marks "" 47 | arduboy.print(F("Hello, world!")); 48 | 49 | // then we finaly we tell the arduboy to display what we just wrote to the display 50 | arduboy.display(); 51 | } 52 | -------------------------------------------------------------------------------- /examples/ESP8266_Sirene/globals.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOBALS_H 2 | #define GLOBALS_H 3 | 4 | #include 5 | #include 6 | // #include 7 | #include "bitmaps.h" 8 | 9 | 10 | 11 | const unsigned int FRAME_RATE = 40; 12 | 13 | //define menu states (on main menu) 14 | #define STATE_MENU_INTRO 0 15 | #define STATE_MENU_MAIN 1 16 | #define STATE_MENU_HELP 2 17 | #define STATE_MENU_PLAY 3 18 | #define STATE_MENU_INFO 4 19 | #define STATE_MENU_SOUNDFX 5 20 | 21 | //define game states (on main menu) 22 | #define STATE_GAME_NEXT_STAGE 6 23 | #define STATE_GAME_PLAYING 7 24 | #define STATE_GAME_PAUSE 8 25 | #define STATE_GAME_OVER 9 26 | #define STATE_GAME_ENDED 10 27 | 28 | #define GAME_TOP 0 29 | #define GAME_BOTTOM 64 30 | #define GAME_LEFT 0 31 | #define GAME_RIGHT 128 32 | 33 | #define STAGE_TO_START_WITH 1 34 | #define PLAYER_CAN_DIE 1 35 | 36 | #define SCORE_SMALL_FONT 0 37 | #define SCORE_BIG_FONT 1 38 | 39 | #define MAX_ONSCREEN_ENEMIES 9 40 | #define MAX_ENEMY_BULLETS 3 41 | #define MAX_BOSS_BULLETS 6 42 | 43 | Arduboy2Base arduboy; 44 | Sprites sprites; 45 | // ArduboyTones sound(arduboy.audio.enabled); 46 | BeepPin1 beep; 47 | void sound(byte tone, byte duration) { 48 | if (arduboy.audio.enabled()) { 49 | beep.tone(beep.freq(tone), duration/6); 50 | } 51 | } 52 | 53 | byte gameState = STATE_MENU_INTRO; // start the game with the TEAM a.r.g. logo 54 | byte menuSelection = STATE_MENU_PLAY; // PLAY menu item is pre-selected 55 | byte globalCounter = 0; 56 | byte stage = STAGE_TO_START_WITH -1; 57 | unsigned long scorePlayer; 58 | byte backgroundIsVisible; 59 | byte gameOverAndStageFase; 60 | byte currentWave; 61 | byte previousWave; 62 | int leftX; 63 | byte rightX; 64 | byte powerUpSelectorY = 0; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /examples/ESP8266_ShadowRunner/runner.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_H 2 | #define RUNNER_H 3 | 4 | #include 5 | #include "globals.h" 6 | 7 | //define runner states 8 | #define RUNNER_RUNNING 0 9 | #define RUNNER_JUMPING 8 10 | #define RUNNER_DUCKING 9 11 | 12 | int runnerX = -127; 13 | int runnerY = 0; 14 | byte runnerFrame = RUNNER_RUNNING; 15 | bool jumping = false; 16 | bool ducking = false; 17 | byte leap[] = {19, 13, 8, 6, 8, 13, 19}; 18 | 19 | byte eyeX[] = {14, 14, 14, 14, 16, 16, 20, 18, 12, 10}; 20 | byte eyeY[] = {7, 8, 9, 8, 7, 8, 9, 8, 6, 5}; 21 | byte eyeFrame[] = {0, 0, 0, 0, 1, 1, 2, 2, 1, 1}; 22 | 23 | void drawRunner() 24 | { 25 | if (arduboy.everyXFrames(4)) 26 | { 27 | runnerFrame++; 28 | } 29 | 30 | if (jumping) 31 | { 32 | ducking = false; 33 | runnerY = leap[runnerFrame - RUNNER_JUMPING]; 34 | if (runnerFrame > 14) 35 | { 36 | runnerY = 28; 37 | jumping = false; 38 | runnerFrame = RUNNER_RUNNING; 39 | } 40 | sprites.drawErase(runnerX, runnerY, shadowRunner, 8); 41 | sprites.drawSelfMasked(runnerX + eyeX[8], runnerY + eyeY[8], shadowRunnerEyes, eyeFrame[8]); 42 | } 43 | 44 | else if (ducking) 45 | { 46 | jumping = false; 47 | runnerY = 38; 48 | if (runnerFrame > 14) 49 | { 50 | runnerY = 28; 51 | ducking = false; 52 | runnerFrame = RUNNER_RUNNING; 53 | } 54 | sprites.drawErase(runnerX, runnerY, shadowRunner, 9); 55 | sprites.drawSelfMasked(runnerX + eyeX[9], runnerY + eyeY[9], shadowRunnerEyes, eyeFrame[9]); 56 | } 57 | 58 | else { 59 | if (runnerFrame > 7)runnerFrame = RUNNER_RUNNING; 60 | 61 | sprites.drawErase(runnerX, runnerY, shadowRunner, runnerFrame); 62 | sprites.drawSelfMasked(runnerX + eyeX[runnerFrame], runnerY + eyeY[runnerFrame], shadowRunnerEyes, eyeFrame[runnerFrame]); 63 | } 64 | } 65 | 66 | void checkRunner() 67 | { 68 | if (lifePlayer < 0) 69 | { 70 | gameState = STATE_GAME_OVER; 71 | delay(1000L); 72 | } 73 | } 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /examples/ESP8266_Sirene/inputs.h: -------------------------------------------------------------------------------- 1 | #ifndef INPUTS_H 2 | #define INPUTS_H 3 | 4 | #include 5 | #include "globals.h" 6 | #include "player.h" 7 | 8 | void checkInputs() 9 | { 10 | if (arduboy.pressed(DOWN_BUTTON) && (mermaid.y < GAME_BOTTOM - 12)) 11 | { 12 | mermaid.y++; 13 | } 14 | if (arduboy.pressed(LEFT_BUTTON) && (mermaid.x > GAME_LEFT)) 15 | { 16 | mermaid.x--; 17 | } 18 | if (arduboy.pressed(UP_BUTTON) && (mermaid.y > GAME_TOP)) 19 | { 20 | mermaid.y--; 21 | } 22 | if (arduboy.pressed(RIGHT_BUTTON) && (mermaid.x < GAME_RIGHT - 16)) 23 | { 24 | mermaid.x++; 25 | } 26 | 27 | if (arduboy.justPressed(A_BUTTON)) 28 | { 29 | gameState = STATE_GAME_PAUSE; 30 | } 31 | 32 | if (arduboy.justPressed(B_BUTTON) && (coolDown[mermaid.weaponType] == coolDownMax[mermaid.weaponType])) 33 | { 34 | 35 | if (mermaid.weaponType == WEAPON_TYPE_TRIDENT) 36 | { 37 | coolDown[mermaid.weaponType]--; 38 | shootWeapon(); 39 | } 40 | if ((mermaid.weaponType == WEAPON_TYPE_SEASHELL)) 41 | { 42 | { 43 | coolDown[mermaid.weaponType]--; 44 | for (byte i = 0; i < 3; i++) 45 | { 46 | shootWeapon(); 47 | } 48 | } 49 | } 50 | } 51 | if (arduboy.pressed(B_BUTTON)) 52 | { 53 | if ((mermaid.weaponType == WEAPON_TYPE_BUBBLES) && (coolDown[WEAPON_TYPE_BUBBLES] == coolDownMax[WEAPON_TYPE_BUBBLES])) 54 | { 55 | coolDown[mermaid.weaponType]--; 56 | shootWeapon(); 57 | } 58 | if (mermaid.weaponType == WEAPON_TYPE_MAGIC) 59 | { 60 | mermaid.magicCharging = true; 61 | if (arduboy.everyXFrames(30)) mermaid.chargeBarFrame ++; 62 | if (mermaid.chargeBarFrame > 4) mermaid.chargeBarFrame = 4; 63 | } 64 | } 65 | if (arduboy.notPressed(B_BUTTON) && (mermaid.weaponType == WEAPON_TYPE_MAGIC) && (mermaid.magicCharging == true)) 66 | { 67 | mermaid.magicCharging = false; 68 | coolDown[mermaid.weaponType]--; 69 | shootWeapon(); 70 | mermaid.chargeBarFrame = 0; 71 | } 72 | } 73 | 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /examples/ESP8266_VidTest/ESP8266_VidTest.ino: -------------------------------------------------------------------------------- 1 | /* 2 | */ 3 | int frameRate = 30; 4 | #include 5 | 6 | // make an instance of arduboy used for many functions 7 | Arduboy2 arduboy; 8 | 9 | 10 | unsigned long lastSetFrameTime = 0; // the last time the LCD display happened. 11 | const unsigned long SetFrameInterval = 1000; // the display delay time in ms; increase if the output flickers 12 | 13 | 14 | // This function runs once in your game. 15 | // use it for anything that needs to be set only once in your game. 16 | void setup() { 17 | // initiate arduboy instance 18 | arduboy.begin(); 19 | 20 | // here we set the framerate to 15, we do not need to run at 21 | // default 60 and it saves us battery life 22 | arduboy.setFrameRate(frameRate); 23 | 24 | } 25 | 26 | 27 | // our main game loop, this runs once every cycle/frame. 28 | // this is where our game logic goes. 29 | void loop() { 30 | static uint8_t fcnt = 0; 31 | static uint8_t dtime = 0; 32 | 33 | // pause render until it's time for the next frame 34 | if (!(arduboy.nextFrame())) 35 | return; 36 | 37 | // first we clear our screen to black 38 | arduboy.clear(); 39 | 40 | // we set our cursor 5 pixels to the right and 10 down from the top 41 | // (positions start at 0, 0) 42 | arduboy.setCursor(4, 9); 43 | 44 | 45 | // then we print to screen what is in the Quotation marks "" 46 | arduboy.print(F("VidTest: ")); 47 | arduboy.print(fcnt>>4); 48 | 49 | arduboy.print(F("\nms/frame: ")); 50 | arduboy.print(dtime); 51 | 52 | arduboy.print(F("\nfps: ")); 53 | arduboy.print(frameRate); 54 | 55 | fcnt++; 56 | if(fcnt & 0x0f == 0x0f) { 57 | arduboy.invert((fcnt & 0x10)); 58 | arduboy.allPixelsOn((fcnt & 0x20)); 59 | arduboy.flipVertical((fcnt & 0x40)); 60 | arduboy.flipHorizontal((fcnt & 0x80)); 61 | 62 | } 63 | 64 | 65 | // then we finaly we tell the arduboy to display what we just wrote to the display 66 | arduboy.display(); 67 | 68 | 69 | if (abs((millis() - lastSetFrameTime) > SetFrameInterval)) { 70 | lastSetFrameTime = millis(); 71 | frameRate = min(60, frameRate +1); 72 | arduboy.setFrameRate(frameRate); 73 | } 74 | 75 | 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /examples/ESP8266_picovaders/pitches.h: -------------------------------------------------------------------------------- 1 | /************************************************* 2 | * Public Constants 3 | *************************************************/ 4 | 5 | #define NOTE_B0 31 6 | #define NOTE_C1 33 7 | #define NOTE_CS1 35 8 | #define NOTE_D1 37 9 | #define NOTE_DS1 39 10 | #define NOTE_E1 41 11 | #define NOTE_F1 44 12 | #define NOTE_FS1 46 13 | #define NOTE_G1 49 14 | #define NOTE_GS1 52 15 | #define NOTE_A1 55 16 | #define NOTE_AS1 58 17 | #define NOTE_B1 62 18 | #define NOTE_C2 65 19 | #define NOTE_CS2 69 20 | #define NOTE_D2 73 21 | #define NOTE_DS2 78 22 | #define NOTE_E2 82 23 | #define NOTE_F2 87 24 | #define NOTE_FS2 93 25 | #define NOTE_G2 98 26 | #define NOTE_GS2 104 27 | #define NOTE_A2 110 28 | #define NOTE_AS2 117 29 | #define NOTE_B2 123 30 | #define NOTE_C3 131 31 | #define NOTE_CS3 139 32 | #define NOTE_D3 147 33 | #define NOTE_DS3 156 34 | #define NOTE_E3 165 35 | #define NOTE_F3 175 36 | #define NOTE_FS3 185 37 | #define NOTE_G3 196 38 | #define NOTE_GS3 208 39 | #define NOTE_A3 220 40 | #define NOTE_AS3 233 41 | #define NOTE_B3 247 42 | #define NOTE_C4 262 43 | #define NOTE_CS4 277 44 | #define NOTE_D4 294 45 | #define NOTE_DS4 311 46 | #define NOTE_E4 330 47 | #define NOTE_F4 349 48 | #define NOTE_FS4 370 49 | #define NOTE_G4 392 50 | #define NOTE_GS4 415 51 | #define NOTE_A4 440 52 | #define NOTE_AS4 466 53 | #define NOTE_B4 494 54 | #define NOTE_C5 523 55 | #define NOTE_CS5 554 56 | #define NOTE_D5 587 57 | #define NOTE_DS5 622 58 | #define NOTE_E5 659 59 | #define NOTE_F5 698 60 | #define NOTE_FS5 740 61 | #define NOTE_G5 784 62 | #define NOTE_GS5 831 63 | #define NOTE_A5 880 64 | #define NOTE_AS5 932 65 | #define NOTE_B5 988 66 | #define NOTE_C6 1047 67 | #define NOTE_CS6 1109 68 | #define NOTE_D6 1175 69 | #define NOTE_DS6 1245 70 | #define NOTE_E6 1319 71 | #define NOTE_F6 1397 72 | #define NOTE_FS6 1480 73 | #define NOTE_G6 1568 74 | #define NOTE_GS6 1661 75 | #define NOTE_A6 1760 76 | #define NOTE_AS6 1865 77 | #define NOTE_B6 1976 78 | #define NOTE_C7 2093 79 | #define NOTE_CS7 2217 80 | #define NOTE_D7 2349 81 | #define NOTE_DS7 2489 82 | #define NOTE_E7 2637 83 | #define NOTE_F7 2794 84 | #define NOTE_FS7 2960 85 | #define NOTE_G7 3136 86 | #define NOTE_GS7 3322 87 | #define NOTE_A7 3520 88 | #define NOTE_AS7 3729 89 | #define NOTE_B7 3951 90 | #define NOTE_C8 4186 91 | #define NOTE_CS8 4435 92 | #define NOTE_D8 4699 93 | #define NOTE_DS8 4978 94 | -------------------------------------------------------------------------------- /examples/ESP8266_Picovaders_Paddle/pitches.h: -------------------------------------------------------------------------------- 1 | /************************************************* 2 | * Public Constants 3 | *************************************************/ 4 | 5 | #define NOTE_B0 31 6 | #define NOTE_C1 33 7 | #define NOTE_CS1 35 8 | #define NOTE_D1 37 9 | #define NOTE_DS1 39 10 | #define NOTE_E1 41 11 | #define NOTE_F1 44 12 | #define NOTE_FS1 46 13 | #define NOTE_G1 49 14 | #define NOTE_GS1 52 15 | #define NOTE_A1 55 16 | #define NOTE_AS1 58 17 | #define NOTE_B1 62 18 | #define NOTE_C2 65 19 | #define NOTE_CS2 69 20 | #define NOTE_D2 73 21 | #define NOTE_DS2 78 22 | #define NOTE_E2 82 23 | #define NOTE_F2 87 24 | #define NOTE_FS2 93 25 | #define NOTE_G2 98 26 | #define NOTE_GS2 104 27 | #define NOTE_A2 110 28 | #define NOTE_AS2 117 29 | #define NOTE_B2 123 30 | #define NOTE_C3 131 31 | #define NOTE_CS3 139 32 | #define NOTE_D3 147 33 | #define NOTE_DS3 156 34 | #define NOTE_E3 165 35 | #define NOTE_F3 175 36 | #define NOTE_FS3 185 37 | #define NOTE_G3 196 38 | #define NOTE_GS3 208 39 | #define NOTE_A3 220 40 | #define NOTE_AS3 233 41 | #define NOTE_B3 247 42 | #define NOTE_C4 262 43 | #define NOTE_CS4 277 44 | #define NOTE_D4 294 45 | #define NOTE_DS4 311 46 | #define NOTE_E4 330 47 | #define NOTE_F4 349 48 | #define NOTE_FS4 370 49 | #define NOTE_G4 392 50 | #define NOTE_GS4 415 51 | #define NOTE_A4 440 52 | #define NOTE_AS4 466 53 | #define NOTE_B4 494 54 | #define NOTE_C5 523 55 | #define NOTE_CS5 554 56 | #define NOTE_D5 587 57 | #define NOTE_DS5 622 58 | #define NOTE_E5 659 59 | #define NOTE_F5 698 60 | #define NOTE_FS5 740 61 | #define NOTE_G5 784 62 | #define NOTE_GS5 831 63 | #define NOTE_A5 880 64 | #define NOTE_AS5 932 65 | #define NOTE_B5 988 66 | #define NOTE_C6 1047 67 | #define NOTE_CS6 1109 68 | #define NOTE_D6 1175 69 | #define NOTE_DS6 1245 70 | #define NOTE_E6 1319 71 | #define NOTE_F6 1397 72 | #define NOTE_FS6 1480 73 | #define NOTE_G6 1568 74 | #define NOTE_GS6 1661 75 | #define NOTE_A6 1760 76 | #define NOTE_AS6 1865 77 | #define NOTE_B6 1976 78 | #define NOTE_C7 2093 79 | #define NOTE_CS7 2217 80 | #define NOTE_D7 2349 81 | #define NOTE_DS7 2489 82 | #define NOTE_E7 2637 83 | #define NOTE_F7 2794 84 | #define NOTE_FS7 2960 85 | #define NOTE_G7 3136 86 | #define NOTE_GS7 3322 87 | #define NOTE_A7 3520 88 | #define NOTE_AS7 3729 89 | #define NOTE_B7 3951 90 | #define NOTE_C8 4186 91 | #define NOTE_CS8 4435 92 | #define NOTE_D8 4699 93 | #define NOTE_DS8 4978 94 | -------------------------------------------------------------------------------- /examples/ESP8266_Sirene/ESP8266_Sirene.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | Ported from ATmega32u4 Arduboy to ESP8266 Arduboy by cheungbx using the ESP8266 Arduboy2 library ported by hartmann1301 and modified ported by by cheungbx to suit the 5 | game board designed by cheungbx using 1 buzzer, 6 push buttons and 1 I2C OLED. 6 | 7 | list of modificaitons to port to ESP8266 8 | 9 | * change "#include arduboy.h" to "#include arduboy2.h" 10 | * add "BeepPin1 beep;" 11 | * add "sound() function" 12 | * comment to remove // #include 13 | * comment to remove // ArduboyTones sound(arduboy.audio.enabled); 14 | * change all "sound.tone" to "playTone" 15 | * chnage all "pgm_read_word" to "pgm_read_dword" 16 | * add beep.begin() after arduboy.begin(); 17 | * if EEPROM is used by the game to keep configs/high scores, 18 | * add EEPROM.begin(100) at setup() 19 | * add EEPROM.commit() after the last EEPROM.put(), 20 | * EEPORM.write() and EEPROM.update() of each blocks of code. 21 | * 22 | *** original comments of the author below ****** 23 | * 24 | * 25 | * 26 | * 27 | 28 | SIRÈNE: http://www.team-arg.org/srn-manual.html 29 | 30 | Arduboy version 1.2.2: http://www.team-arg.org/srn-downloads.html 31 | 32 | MADE by TEAM a.r.g. : http://www.team-arg.org/more-about.html 33 | 34 | 2016 - JO3RI - JUSTIN_CYR 35 | 36 | License: MIT : https://opensource.org/licenses/MIT 37 | 38 | */ 39 | 40 | //determine the game 41 | #define GAME_ID 42 42 | 43 | #include "globals.h" 44 | #include "menu.h" 45 | #include "game.h" 46 | #include "inputs.h" 47 | #include "player.h" 48 | #include "enemies.h" 49 | #include "elements.h" 50 | #include "stages.h" 51 | 52 | typedef void (*FunctionPointer) (); 53 | 54 | const FunctionPointer PROGMEM mainGameLoop[] = { 55 | stateMenuIntro, 56 | stateMenuMain, 57 | stateMenuHelp, 58 | stateMenuPlay, 59 | stateMenuInfo, 60 | stateMenuSoundfx, 61 | stateGameNextStage, 62 | stateGamePlaying, 63 | stateGamePause, 64 | stateGameOver, 65 | stateGameEnded, 66 | }; 67 | 68 | 69 | void setup() { 70 | arduboy.begin(); 71 | arduboy.setFrameRate(FRAME_RATE); 72 | arduboy.initRandomSeed(); 73 | beep.begin(); 74 | arduboy.audio.on(); 75 | 76 | } 77 | 78 | 79 | void loop() { 80 | if (!(arduboy.nextFrame())) return; 81 | arduboy.pollButtons(); 82 | arduboy.clear(); 83 | 84 | ((FunctionPointer) pgm_read_dword (&mainGameLoop[gameState]))(); 85 | 86 | 87 | arduboy.display(); 88 | 89 | 90 | } 91 | -------------------------------------------------------------------------------- /examples/ESP8266_ShadowRunner/menu.h: -------------------------------------------------------------------------------- 1 | #ifndef MENU_H 2 | #define MENU_H 3 | 4 | #include 5 | #include "globals.h" 6 | #include "runner.h" 7 | 8 | byte flameid = 0; 9 | boolean showRunner = false; 10 | 11 | void drawCandle (byte x, byte y) 12 | { 13 | if (arduboy.everyXFrames(4)) 14 | { 15 | flameid = random(0, 24); 16 | } 17 | sprites.drawSelfMasked(x, y + 34, candleTip, 0); 18 | sprites.drawSelfMasked(x + 4, y + 18, candleFlame, flameid); 19 | 20 | } 21 | 22 | void stateMenuIntro() 23 | { 24 | globalCounter++; 25 | sprites.drawSelfMasked(34, 4, T_arg, 0); 26 | if (globalCounter > 180) 27 | { 28 | globalCounter = 0; 29 | gameState = STATE_MENU_MAIN; 30 | } 31 | }; 32 | 33 | void stateMenuMain() 34 | { 35 | runnerY = 0; 36 | if (arduboy.everyXFrames(4)) runnerX += 4; 37 | if (runnerX > 127) 38 | { 39 | runnerX = -127; 40 | showRunner = !showRunner; 41 | } 42 | sprites.drawSelfMasked(16, 0, menuTitle, 0); 43 | sprites.drawSelfMasked(49, 26, menuItems, 0); 44 | sprites.drawSelfMasked(89, 50, menuYesNo, arduboy.audio.enabled()); 45 | drawCandle(29, (menuSelection - 2) * 8); 46 | for (byte i = 2; i < 6; i++) 47 | { 48 | if (menuSelection != i) { 49 | sprites.drawErase(49, (i * 8) + 10, menuShade, 0); 50 | sprites.drawErase(82, (i * 8) + 10, menuShade, 0); 51 | } 52 | } 53 | if (showRunner) 54 | { 55 | sprites.drawSelfMasked(runnerX, -2, spotLight, 0); 56 | drawRunner(); 57 | } 58 | if (arduboy.justPressed(UP_BUTTON) && (menuSelection > 2)) menuSelection--; 59 | else if (arduboy.justPressed(DOWN_BUTTON) && (menuSelection < 5)) menuSelection++; 60 | else if (arduboy.justPressed(A_BUTTON | B_BUTTON)) 61 | { 62 | if (menuSelection != 5) gameState = menuSelection; 63 | else 64 | { 65 | if (arduboy.audio.enabled()) arduboy.audio.off(); 66 | else arduboy.audio.on(); 67 | arduboy.audio.saveOnOff(); 68 | } 69 | } 70 | 71 | } 72 | 73 | void stateMenuHelp() 74 | { 75 | sprites.drawSelfMasked(32, 0, qrcode, 0); 76 | if (arduboy.justPressed(A_BUTTON | B_BUTTON)) gameState = STATE_MENU_MAIN; 77 | } 78 | 79 | void stateMenuInfo() 80 | { 81 | sprites.drawSelfMasked(16, 0, menuTitle, 0); 82 | sprites.drawSelfMasked(15, 25, menuInfo, 0); 83 | if (arduboy.justPressed(A_BUTTON | B_BUTTON)) gameState = STATE_MENU_MAIN; 84 | } 85 | 86 | void stateMenuSoundfx() 87 | { 88 | // placeHolder 89 | } 90 | 91 | 92 | void stateMenuPlay() 93 | { 94 | gameState = STATE_GAME_INIT_LEVEL; 95 | } 96 | 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /examples/ESP8266_Sirene/menu.h: -------------------------------------------------------------------------------- 1 | #ifndef MENU_H 2 | #define MENU_H 3 | 4 | #include 5 | #include "globals.h" 6 | byte hairFrame = 0; 7 | byte eyesFrame = 0; 8 | byte eyesSequence[] = {0, 1, 2, 3, 3, 3, 1}; 9 | 10 | void drawTitleScreen() 11 | { 12 | byte eyesFrame2; 13 | if (arduboy.everyXFrames(10)) hairFrame++; 14 | if (arduboy.everyXFrames(2)) eyesFrame++; 15 | if (eyesFrame > 60)eyesFrame = 0; 16 | eyesFrame2 = eyesFrame; 17 | if (eyesFrame2 > 6) eyesFrame2 = 0; 18 | if (hairFrame > 3) hairFrame = 0; 19 | sprites.drawSelfMasked(36, 1, mermaidTitle, 0); 20 | sprites.drawSelfMasked(59, 21, mermaidTrident, 0); 21 | sprites.drawSelfMasked(62, 48, mermaidFin, 0); 22 | sprites.drawSelfMasked(4, 46, mermaidBody, 0); 23 | sprites.drawSelfMasked(3, 14, mermaidHair, hairFrame); 24 | sprites.drawSelfMasked(10, 24, mermaidBlink, eyesSequence[eyesFrame2]); 25 | } 26 | 27 | void stateMenuIntro() 28 | { 29 | globalCounter++; 30 | sprites.drawSelfMasked(34, 4, T_arg, 0); 31 | if (globalCounter > 180) 32 | { 33 | globalCounter = 0; 34 | gameState = STATE_MENU_MAIN; 35 | } 36 | } 37 | 38 | void stateMenuMain() 39 | { 40 | drawTitleScreen(); 41 | for (byte i = 0; i < 4; i++) 42 | { 43 | sprites.drawSelfMasked(108, 32 +(i*8), menuText, i); 44 | } 45 | sprites.drawSelfMasked(92, 32 + 8*(menuSelection-2), trident, 0); 46 | if (arduboy.justPressed(DOWN_BUTTON) && (menuSelection < 5)) menuSelection++; 47 | if (arduboy.justPressed(UP_BUTTON) && (menuSelection > 2)) menuSelection--; 48 | if (arduboy.justPressed(B_BUTTON)) gameState = menuSelection; 49 | } 50 | 51 | void stateMenuHelp() 52 | { 53 | sprites.drawSelfMasked(32, 0, qrcode, 0); 54 | if (arduboy.justPressed(A_BUTTON | B_BUTTON)) gameState = STATE_MENU_MAIN; 55 | } 56 | 57 | 58 | void stateMenuInfo() 59 | { 60 | sprites.drawSelfMasked(33, 10, mermaidTitle, 0); 61 | sprites.drawSelfMasked(36, 31, madeBy, 0); 62 | if (arduboy.justPressed(A_BUTTON | B_BUTTON)) gameState = STATE_MENU_MAIN; 63 | } 64 | 65 | void stateMenuSoundfx() 66 | { 67 | drawTitleScreen(); 68 | for (byte i = 0; i < 3; i++) 69 | { 70 | sprites.drawSelfMasked(108, 40 +(i*8), menuText, i+4); 71 | } 72 | sprites.drawSelfMasked(92, 48 + 8*arduboy.audio.enabled(), trident, 0); 73 | if (arduboy.justPressed(DOWN_BUTTON)) arduboy.audio.on(); 74 | if (arduboy.justPressed(UP_BUTTON)) arduboy.audio.off(); 75 | if (arduboy.justPressed(A_BUTTON | B_BUTTON)) 76 | { 77 | arduboy.audio.saveOnOff(); 78 | gameState = STATE_MENU_MAIN; 79 | } 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /EEPROM.h: -------------------------------------------------------------------------------- 1 | /* 2 | EEPROM.cpp - esp8266 EEPROM emulation 3 | 4 | Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. 5 | This file is part of the esp8266 core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | #ifndef EEPROM_h 23 | #define EEPROM_h 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | class EEPROMClass { 30 | public: 31 | EEPROMClass(uint32_t sector); 32 | EEPROMClass(void); 33 | 34 | void begin(size_t size); 35 | uint8_t read(int const address); 36 | void write(int const address, uint8_t const val); 37 | void update(int const address, uint8_t const val); 38 | bool commit(); 39 | void end(); 40 | 41 | uint8_t * getDataPtr(); 42 | uint8_t const * getConstDataPtr() const; 43 | 44 | template 45 | T &get(int const address, T &t) { 46 | if (address < 0 || address + sizeof(T) > _size) 47 | return t; 48 | 49 | memcpy((uint8_t*) &t, _data + address, sizeof(T)); 50 | return t; 51 | } 52 | 53 | template 54 | const T &put(int const address, const T &t) { 55 | if (address < 0 || address + sizeof(T) > _size) 56 | return t; 57 | if (memcmp(_data + address, (const uint8_t*)&t, sizeof(T)) != 0) { 58 | _dirty = true; 59 | memcpy(_data + address, (const uint8_t*)&t, sizeof(T)); 60 | } 61 | 62 | return t; 63 | } 64 | 65 | size_t length() {return _size;} 66 | 67 | uint8_t& operator[](int const address) {return getDataPtr()[address];} 68 | uint8_t const & operator[](int const address) const {return getConstDataPtr()[address];} 69 | 70 | protected: 71 | uint32_t _sector; 72 | uint8_t* _data; 73 | size_t _size; 74 | bool _dirty; 75 | }; 76 | 77 | #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_EEPROM) 78 | extern EEPROMClass EEPROM; 79 | #endif 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /src/EEPROM.h: -------------------------------------------------------------------------------- 1 | /* 2 | EEPROM.cpp - esp8266 EEPROM emulation 3 | 4 | Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. 5 | This file is part of the esp8266 core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | #ifndef EEPROM_h 23 | #define EEPROM_h 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | class EEPROMClass { 30 | public: 31 | EEPROMClass(uint32_t sector); 32 | EEPROMClass(void); 33 | 34 | void begin(size_t size); 35 | uint8_t read(int const address); 36 | void write(int const address, uint8_t const val); 37 | void update(int const address, uint8_t const val); 38 | bool commit(); 39 | void end(); 40 | 41 | uint8_t * getDataPtr(); 42 | uint8_t const * getConstDataPtr() const; 43 | 44 | template 45 | T &get(int const address, T &t) { 46 | if (address < 0 || address + sizeof(T) > _size) 47 | return t; 48 | 49 | memcpy((uint8_t*) &t, _data + address, sizeof(T)); 50 | return t; 51 | } 52 | 53 | template 54 | const T &put(int const address, const T &t) { 55 | if (address < 0 || address + sizeof(T) > _size) 56 | return t; 57 | if (memcmp(_data + address, (const uint8_t*)&t, sizeof(T)) != 0) { 58 | _dirty = true; 59 | memcpy(_data + address, (const uint8_t*)&t, sizeof(T)); 60 | } 61 | 62 | return t; 63 | } 64 | 65 | size_t length() {return _size;} 66 | 67 | uint8_t& operator[](int const address) {return getDataPtr()[address];} 68 | uint8_t const & operator[](int const address) const {return getConstDataPtr()[address];} 69 | 70 | protected: 71 | uint32_t _sector; 72 | uint8_t* _data; 73 | size_t _size; 74 | bool _dirty; 75 | }; 76 | 77 | #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_EEPROM) 78 | extern EEPROMClass EEPROM; 79 | #endif 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /examples/ESP8266_Mystic_Balloon/elements.h: -------------------------------------------------------------------------------- 1 | #ifndef ELEMENTS_H 2 | #define ELEMENTS_H 3 | 4 | #include 5 | #include "globals.h" 6 | 7 | #define FONT_TINY 0 8 | #define FONT_SMALL 1 9 | #define FONT_BIG 2 10 | 11 | #define DATA_TIMER 0 12 | #define DATA_SCORE 1 13 | #define DATA_LEVEL 2 14 | 15 | void drawBalloonLives() 16 | { 17 | for (byte i = 0; i < kid.balloons; ++i) 18 | { 19 | sprites.drawOverwrite((i * 7) + 2, 0, elementsHUD, 10); 20 | } 21 | } 22 | 23 | void drawCoinHUD() 24 | { 25 | //for (byte i = 0; i < MAX_PER_TYPE; ++i) 26 | for (byte i = MAX_PER_TYPE-1; i < MAX_PER_TYPE; --i) 27 | { 28 | if (i >= MAX_PER_TYPE - coinsActive) 29 | sprites.drawOverwrite(40 + (i * 6), 0, elementsHUD, 11); 30 | else 31 | sprites.drawOverwrite(40 + (i * 6), 0, elementsHUD, 12); 32 | } 33 | } 34 | 35 | void drawNumbers(byte numbersX, byte numbersY, byte fontType, byte data) 36 | { 37 | char buf[10]; 38 | char charLen; 39 | char pad; 40 | switch (data) 41 | { 42 | case DATA_SCORE: 43 | ltoa(scorePlayer, buf, 10); 44 | charLen = strlen(buf); 45 | pad = 6 - charLen; 46 | sprites.drawSelfMasked(numbersX - 2, numbersY - 2, numbersBigMask, 0); 47 | //for (byte i = 0; i < 6; i++) 48 | for (byte i = 5; i <= 5; --i) 49 | sprites.drawSelfMasked(numbersX + (7 * i), numbersY - 2, numbersBigMask01, 0); 50 | sprites.drawSelfMasked(numbersX + 41, numbersY - 2, numbersBigMask, 1); 51 | break; 52 | case DATA_LEVEL: 53 | itoa(level + 1, buf, 10); 54 | charLen = strlen(buf); 55 | pad = 2 - charLen; 56 | sprites.drawSelfMasked(numbersX-2, numbersY - 9, badgeLevel, 0); 57 | break; 58 | } 59 | 60 | //draw 0 padding 61 | for (byte i = 0; i < pad; i++) 62 | { 63 | switch (fontType) 64 | { 65 | case FONT_SMALL: 66 | sprites.drawOverwrite(numbersX + (6 * i), numbersY, elementsHUD, 0); 67 | break; 68 | case FONT_BIG: 69 | sprites.drawSelfMasked(numbersX + (7 * i), numbersY, numbersBig, 0); 70 | break; 71 | } 72 | } 73 | 74 | for (byte i = 0; i < charLen; i++) 75 | { 76 | char digit = buf[i]; 77 | if (digit <= 48) 78 | { 79 | digit = 0; 80 | } 81 | else { 82 | digit -= 48; 83 | if (digit > 9) digit = 0; 84 | } 85 | switch (fontType) 86 | { 87 | case FONT_SMALL: 88 | sprites.drawOverwrite(numbersX + (pad * 6) + (6 * i), numbersY, elementsHUD, digit); 89 | break; 90 | case FONT_BIG: 91 | sprites.drawSelfMasked(numbersX + (pad * 7) + (7 * i), numbersY, numbersBig, digit); 92 | break; 93 | } 94 | } 95 | } 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /src/Arduboy2Beep.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Arduboy2Beep.cpp 3 | * \brief 4 | * Classes to generate simple square wave tones on the Arduboy speaker pins. 5 | */ 6 | 7 | #include 8 | #include "Arduboy2Beep.h" 9 | #include "Arduboy2Core.h" 10 | 11 | uint8_t BeepPin1::duration = 0; 12 | 13 | void BeepPin1::begin() 14 | { 15 | #ifndef ESP8266 16 | TCCR3A = 0; 17 | TCCR3B = (bit(WGM32) | bit(CS31)); // CTC mode. Divide by 8 clock prescale 18 | #endif 19 | } 20 | 21 | void BeepPin1::tone(uint16_t count) 22 | { 23 | #ifdef ESP8266 24 | ::tone(PIN_SPEAKER_1, count); 25 | #else 26 | tone(count, 0); 27 | #endif 28 | } 29 | 30 | void BeepPin1::tone(uint16_t count, uint8_t dur) 31 | { 32 | #ifdef ESP8266 33 | ::tone(PIN_SPEAKER_1, count, dur); 34 | #else 35 | duration = dur; 36 | TCCR3A = bit(COM3A0); // set toggle on compare mode (which connects the pin) 37 | OCR3A = count; // load the count (16 bits), which determines the frequency 38 | #endif 39 | } 40 | 41 | void BeepPin1::timer() 42 | { 43 | #ifndef ESP8266 44 | if (duration && (--duration == 0)) { 45 | TCCR3A = 0; // set normal mode (which disconnects the pin) 46 | } 47 | #endif 48 | } 49 | 50 | void BeepPin1::noTone() 51 | { 52 | #ifdef ESP8266 53 | ::noTone(PIN_SPEAKER_1); 54 | #else 55 | duration = 0; 56 | TCCR3A = 0; // set normal mode (which disconnects the pin) 57 | #endif 58 | } 59 | 60 | 61 | // Speaker pin 2, Timer 4A, Port C bit 7, Arduino pin 13 62 | 63 | uint8_t BeepPin2::duration = 0; 64 | 65 | void BeepPin2::begin() 66 | { 67 | #ifndef ESP8266 68 | TCCR4A = 0; // normal mode. Disable PWM 69 | TCCR4B = bit(CS43); // divide by 128 clock prescale 70 | TCCR4D = 0; // normal mode 71 | TC4H = 0; // toggle pin at count = 0 72 | OCR4A = 0; // " 73 | #endif 74 | } 75 | 76 | void BeepPin2::tone(uint16_t count) 77 | { 78 | #ifdef ESP8266 79 | ::tone(PIN_SPEAKER_2, count); 80 | #else 81 | tone(count, 0); 82 | #endif 83 | } 84 | 85 | void BeepPin2::tone(uint16_t count, uint8_t dur) 86 | { 87 | #ifdef ESP8266 88 | ::tone(PIN_SPEAKER_2, count, dur); 89 | #else 90 | duration = dur; 91 | TCCR4A = bit(COM4A0); // set toggle on compare mode (which connects the pin) 92 | TC4H = highByte(count); // load the count (10 bits), 93 | OCR4C = lowByte(count); // which determines the frequency 94 | #endif 95 | } 96 | 97 | void BeepPin2::timer() 98 | { 99 | #ifndef ESP8266 100 | if (duration && (--duration == 0)) { 101 | TCCR4A = 0; // set normal mode (which disconnects the pin) 102 | } 103 | #endif 104 | } 105 | 106 | void BeepPin2::noTone() 107 | { 108 | #ifdef ESP8266 109 | ::noTone(PIN_SPEAKER_2); 110 | #else 111 | duration = 0; 112 | TCCR4A = 0; // set normal mode (which disconnects the pin) 113 | #endif 114 | } -------------------------------------------------------------------------------- /examples/ESP8266_Mystic_Balloon/ESP8266_Mystic_Balloon.ino: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | * 5 | Ported from ATmega32u4 Arduboy to ESP8266 Arduboy by cheungbx using the ESP8266 Arduboy2 library ported by hartmann1301 and modified ported by by cheungbx to suit the 6 | game board designed by cheungbx using 1 buzzer, 6 push buttons and 1 I2C OLED. 7 | 8 | list of modificaitons to port to ESP8266 9 | 10 | * change "#include arduboy.h" to "#include arduboy2.h" 11 | * add "BeepPin1 beep;" 12 | * add "sound() function" 13 | * comment to remove // #include 14 | * comment to remove // ArduboyTones sound(arduboy.audio.enabled); 15 | * change all "sound.tone" to "playTone" 16 | * chnage all "pgm_read_word" to "pgm_read_dword" 17 | * add beep.begin() after arduboy.begin(); 18 | * if EEPROM is used by the game to keep configs/high scores, 19 | * add EEPROM.begin(100) at setup() 20 | * add EEPROM.commit() after the last EEPORM.write() and EEPROM.update() 21 | 22 | 23 | *** original comments of the author below ****** 24 | */ 25 | 26 | 27 | /* 28 | Mystic Balloon: http://www.team-arg.org/mybl-manual.html 29 | 30 | Arduboy version 1.7.2: http://www.team-arg.org/mybl-downloads.html 31 | 32 | MADE by TEAM a.r.g. : http://www.team-arg.org/more-about.html 33 | 34 | 2016-2018 - GAVENO - CastPixel - JO3RI - Martian220 35 | 36 | Game License: MIT : https://opensource.org/licenses/MIT 37 | 38 | */ 39 | 40 | //determine the game 41 | #define GAME_ID 34 42 | 43 | #include "globals.h" 44 | #include "menu.h" 45 | #include "game.h" 46 | #include "inputs.h" 47 | #include "player.h" 48 | #include "enemies.h" 49 | #include "elements.h" 50 | #include "levels.h" 51 | 52 | 53 | typedef void (*FunctionPointer) (); 54 | 55 | const FunctionPointer PROGMEM mainGameLoop[] = { 56 | stateMenuIntro, 57 | stateMenuMain, 58 | stateMenuHelp, 59 | stateMenuPlaySelect, 60 | stateMenuInfo, 61 | stateMenuSoundfx, 62 | stateGameNextLevel, 63 | stateGamePlaying, 64 | stateGamePause, 65 | stateGameOver, 66 | stateMenuPlayContinue, 67 | stateMenuPlayNew, 68 | }; 69 | 70 | void setup() 71 | { 72 | Serial.begin(74880); 73 | arduboy.begin(); // begin with the boot logo en setting up the device to work 74 | beep.begin(); 75 | 76 | arduboy.bootLogoSpritesSelfMasked(); 77 | arduboy.setFrameRate(60); // set the frame rate of the game at 60 fps 78 | loadSetEEPROM(); 79 | arduboy.audio.on(); 80 | } 81 | 82 | void loop() { 83 | if (!(arduboy.nextFrame())) return; 84 | if (gameState < STATE_GAME_NEXT_LEVEL && arduboy.everyXFrames(10))sparkleFrames = (++sparkleFrames) % 5; 85 | arduboy.pollButtons(); 86 | arduboy.clear(); 87 | ((FunctionPointer) pgm_read_dword (&mainGameLoop[gameState]))(); 88 | arduboy.display(); 89 | } 90 | -------------------------------------------------------------------------------- /examples/ESP8266_evade/globals.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOBALS_H 2 | #define GLOBALS_H 3 | 4 | /* 5 | * File: globals.h 6 | * Purpose: Global artifacts for Evade game. 7 | * Author: Modus Create 8 | */ 9 | 10 | // Button debounce 11 | #define DEBOUNCE_DELAY 100 12 | 13 | // Number of lives the player starts with 14 | #define MAX_LIVES 4 15 | 16 | // How many entries in high score table, and fake position used 17 | // to determine player didn't get a new high score 18 | #define NUM_HIGH_SCORES 3 19 | #define NOT_NEW_HI_SCORE 5 20 | 21 | // Number of stars comprising the starfield background 22 | #define NUM_STARS 15 23 | 24 | // Define limits that player movement is bounded by 25 | #define MIN_PLAYER_Y 8 26 | #define MAX_PLAYER_Y 48 27 | #define MIN_PLAYER_X 0 28 | #define MAX_PLAYER_X 27 // allows 16 for ship width 29 | #define PLAYER_SIZE 16 30 | #define MAX_GUN_CHARGE 40 31 | #define GUN_SHOT_COST 12 32 | 33 | // Define limits that enemy ship movement is bounded by 34 | #define MIN_ENEMY_SHIP_X 92 35 | #define MAX_ENEMY_SHIP_X 112 36 | 37 | // Max bullets and enemies allowed in play 38 | #define MAX_PLAYER_BULLETS 4 39 | #define MAX_BOSS_BULLETS 2 40 | #define MAX_ENEMIES 3 41 | 42 | // Minimum number of enemies kills needed to spawn next box 43 | #define BOSS1_MIN_KILLS 20 44 | #define BOSS2_MIN_KILLS 25 45 | #define BOSS3_MIN_KILLS 30 46 | 47 | // Time before title screen flips to high score screen 48 | #define ATTRACT_MODE_TIMEOUT 400000 49 | 50 | // Title screen outcomes 51 | #define TITLE_CREDITS 0 52 | #define TITLE_PLAY_GAME 1 53 | #define TITLE_SETTINGS 2 54 | #define TITLE_TIMEOUT 3 55 | 56 | // Settings screen outcomes 57 | #define SETTINGS_SOUND 0 58 | #define SETTINGS_RESET_HIGH_SCORE 1 59 | #define SETTINGS_EXIT 2 60 | 61 | // Arduboy library object 62 | Arduboy2 arduboy; 63 | 64 | // Used to count frames 65 | unsigned long inGameFrame; 66 | 67 | // Current player attributes 68 | byte playerX, 69 | playerY, 70 | playerFrame, 71 | playerDying, 72 | playerGunCharge, 73 | livesRemaining = MAX_LIVES, 74 | currentKills = 0; // Used to determine when bosses appear 75 | 76 | // Star field attributes 77 | float starX[NUM_STARS], 78 | starSpeed[NUM_STARS]; 79 | 80 | byte starY[NUM_STARS], 81 | starWidth[NUM_STARS]; 82 | 83 | // Initial high score table contents 84 | char highScoreTable[] = "AAA000300BBB000200CCC000100"; 85 | 86 | // Used to print letters from bitmap font 87 | const unsigned char *alphabet[29]; 88 | 89 | // Track button presses for debounce, frame last death was in, player score 90 | unsigned long inGameAButtonLastPress, 91 | inGameBButtonLastPress, 92 | inGameLastDeath, 93 | score; 94 | 95 | // Game state booleans 96 | bool isBossAlive, 97 | isInitialTitleScreen = true, 98 | soundOn = true; 99 | 100 | // Which tune is currently playing 101 | byte currentSong = 255; 102 | 103 | // General purpose text buffer for string concatenation and read from progmem 104 | char textBuf[23]; 105 | 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /examples/ESP8266_ShadowRunner/items.h: -------------------------------------------------------------------------------- 1 | #ifndef ITEMS_H 2 | #define ITEMS_H 3 | 4 | #include 5 | #include "globals.h" 6 | 7 | #define ITEM_STONE_ONE 0 8 | #define ITEM_STONE_TWO 1 9 | #define ITEM_BIRD_ONE 2 10 | #define ITEM_BIRD_TWO 3 11 | #define ITEM_EXTRA_LIFE 4 12 | 13 | #define STONES_Y 36 14 | #define BIRDS_Y 16 15 | #define HEART_Y 4 16 | 17 | 18 | byte showitems = B00000000; // this byte holds all the items the player runs into during the game 19 | // | |||| 20 | // | |||└-> stone1 21 | // | ||└--> stone2 22 | // | |└---> bird1 23 | // | └----> bird2 24 | // | 25 | // └------> extra life 26 | 27 | byte birdFrame = 0; 28 | boolean heartFrame = 0; 29 | 30 | int itemX[5] = { -64, 96, 48, 128, 128}; 31 | 32 | 33 | void checkItems() 34 | { 35 | if (arduboy.everyXFrames(1)) 36 | { 37 | itemX[ITEM_STONE_ONE] -= 2; 38 | if (itemX[ITEM_STONE_ONE] < -127) 39 | { 40 | // random set bit 0 to 0 or 1 (false or true) 41 | bitWrite(showitems, ITEM_STONE_ONE, random(0, 2)); 42 | itemX[ITEM_STONE_ONE] = 128; 43 | } 44 | 45 | 46 | itemX[ITEM_STONE_TWO] -= 2; 47 | if (itemX[ITEM_STONE_TWO] < -127) 48 | { 49 | // random set bit 1 to 0 or 1 (false or true) 50 | bitWrite(showitems, ITEM_STONE_TWO, random(0, 2)); 51 | itemX[ITEM_STONE_TWO] = 128; 52 | } 53 | 54 | 55 | itemX[ITEM_BIRD_ONE] -= 2; 56 | if (itemX[ITEM_BIRD_ONE] < -127) 57 | { 58 | // random set bit 2 to 0 or 1 (false or true) 59 | bitWrite(showitems, ITEM_BIRD_ONE, random(0, 2)); 60 | itemX[ITEM_BIRD_ONE] = 128; 61 | } 62 | 63 | 64 | itemX[ITEM_BIRD_TWO] -= 2; 65 | if (itemX[ITEM_BIRD_TWO] < -127) 66 | { 67 | // random set bit 3 to 0 or 1 (false or true) 68 | bitWrite(showitems, ITEM_BIRD_TWO, random(0, 2)); 69 | if ((showitems & B00001010) == B00001010) showitems ^= B00001000; // if stone2 no Bird2 70 | itemX[ITEM_BIRD_TWO] = 128; 71 | } 72 | 73 | 74 | if (showitems & B00100000) 75 | { 76 | itemX[ITEM_EXTRA_LIFE] -= 2; 77 | if (itemX[ITEM_EXTRA_LIFE] < -24) 78 | { 79 | showitems ^= B00100000; 80 | itemX[ITEM_EXTRA_LIFE] = 128; 81 | } 82 | } 83 | } 84 | 85 | if (arduboy.everyXFrames(6)) 86 | { 87 | birdFrame++; 88 | heartFrame = !heartFrame; 89 | } 90 | if (birdFrame > 7) birdFrame = 0; 91 | } 92 | 93 | 94 | 95 | void drawItems() 96 | { 97 | if (showitems & B00000001) sprites.drawPlusMask(itemX[ITEM_STONE_ONE], 36, stone_plus_mask, 0); 98 | if (showitems & B00000010) sprites.drawPlusMask(itemX[ITEM_STONE_TWO], 36, stone_plus_mask, 0); 99 | if (showitems & B00000100) sprites.drawErase(itemX[ITEM_BIRD_ONE], 16, bird, birdFrame); 100 | if (showitems & B00001000) sprites.drawErase(itemX[ITEM_BIRD_TWO], 16, bird, birdFrame); 101 | if (showitems & B00100000) sprites.drawErase(itemX[ITEM_EXTRA_LIFE], 4, heart, heartFrame); 102 | } 103 | 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /examples/ESP8266_evade/bullet.h: -------------------------------------------------------------------------------- 1 | #ifndef BULLET_H 2 | #define BULLET_H 3 | 4 | /* 5 | * File: bullet.h 6 | * Purpose: Deals with player and enemy bullet logic for Evade game. 7 | * Author: Modus Create 8 | */ 9 | 10 | #include "globals.h" 11 | #include "bitmaps.h" 12 | 13 | #define A_BULLET_DAMAGE 75 // First button, Fireball 14 | #define B_BULLET_DAMAGE 40 // Second button, small laser 15 | 16 | struct Bullet { 17 | public: 18 | float x, 19 | speedX; 20 | byte y, 21 | damage, 22 | // Visibility (0), Direction (1), Laser Beam (2) 23 | options; 24 | unsigned long inGameFireFrame; 25 | 26 | // Initialize a bullet in a given position. 27 | void set(byte _x, byte _y, bool firedByPlayer, byte _damage, float _speedX, bool isLaserBeam) { 28 | x = _x; 29 | y = _y; 30 | damage = _damage; 31 | speedX = _speedX; 32 | 33 | options &= ~(1 << 1); 34 | options &= ~(1 << 2); 35 | 36 | options |= 1 << 0; 37 | options |= firedByPlayer << 1; 38 | options |= isLaserBeam << 2; 39 | 40 | inGameFireFrame = inGameFrame; 41 | draw(); 42 | } 43 | 44 | // Update bullet, if still visible. 45 | void update() { 46 | if (isVisible()) { 47 | move(); 48 | draw(); 49 | } 50 | } 51 | 52 | // Move the bullet across the screen. 53 | void move() { 54 | x += isMovingRight() ? speedX : -speedX; 55 | if (x > 128) { 56 | hide(); 57 | } 58 | if (x <= -30) { 59 | hide(); 60 | } 61 | } 62 | 63 | // Draw bullet on the screen. 64 | void draw() { 65 | if (isMovingRight()) { 66 | const bool isBulletA = (damage == A_BULLET_DAMAGE); 67 | playTone(isBulletA ? 600 - (x + 2) : 900 - (x * 2 + 3), 10); 68 | drawBitmap(x, y, (isBulletA ? playerBulletA : playerBulletB), 0); 69 | } else if (!isLaserBeam()) { 70 | drawBitmap(x, y, enemyBullet, 0); 71 | } else { 72 | arduboy.fillRect(x, y, min((inGameFrame, inGameFireFrame), 30), 2, 1); 73 | } 74 | } 75 | 76 | // Determine whether or not the bullet is hitting something. 77 | bool isHittingObject(byte objectX, byte objectY, byte objectWidth, byte objectHeight) { 78 | if ((isVisible()) && 79 | ((isLaserBeam() && (x >= (objectX - 30))) || (!isLaserBeam() && (x >= objectX))) && 80 | (x <= (objectX + objectWidth)) && 81 | (y >= objectY) && 82 | (y <= (objectY + objectHeight))) { 83 | return true; 84 | } else { 85 | return false; 86 | } 87 | } 88 | 89 | // Is the bullet visible right now? 90 | bool isVisible() { 91 | return (options & (1 << 0)); 92 | } 93 | 94 | // Is the bullet moving to the right (player) or left (enemy)? 95 | bool isMovingRight() { 96 | return (options & (1 << 1)); 97 | } 98 | 99 | // Is the bullet a laser beam? 100 | bool isLaserBeam() { 101 | return (options & (1 << 2)); 102 | } 103 | 104 | // Hide the bullet. 105 | void hide() { 106 | if (isVisible()) { 107 | options ^= 1 << 0; 108 | } 109 | } 110 | }; 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /examples/ESP8266_ShadowRunner/ESP8266_ShadowRunner.ino: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | * 5 | Ported from ATmega32u4 Arduboy to ESP8266 Arduboy by cheungbx using the ESP8266 Arduboy2 library ported by hartmann1301 and modified ported by by cheungbx to suit the 6 | game board designed by cheungbx using 1 buzzer, 6 push buttons and 1 I2C OLED. 7 | 8 | list of modificaitons to port to ESP8266 9 | 10 | * change "#include arduboy.h" to "#include arduboy2.h" 11 | * chnage all "pgm_read_word" to "pgm_read_dword" 12 | * comment to remove // #include 13 | * comment to remove // ArduboyTones sound(arduboy.audio.enabled); 14 | * change all "sound.tone" to "playTone" 15 | * add "BeepPin1 beep;" 16 | * add "sound() function" 17 | * void sound(byte tone, byte duration) { 18 | * if (arduboy.audio.enabled()) { 19 | * beep.tone(beep.freq(tone), duration/3); 20 | * beep.noTone(); 21 | * } 22 | * } 23 | * 24 | * if EEPROM is used by the game to keep configs/high scores, 25 | * add EEPROM.begin(100) at setup() 26 | * add EEPROM.commit() after the last EEPROM.put(), 27 | * EEPORM.write() and EEPROM.update() of each blocks of code. 28 | */ 29 | /* 30 | SHADOW RUNNER: http://www.team-arg.org/shrun-manual.html 31 | 32 | Arduboy version 1.6 : http://www.team-arg.org/more-about.html 33 | 34 | MADE by TEAM a.r.g. : http://www.team-arg.org/more-about.html 35 | 36 | 2015 - JO3RI - Trodoss 37 | 38 | Special thanks to Dreamer3 for helping with the conversion from Gamby 39 | 40 | Game License: MIT : https://opensource.org/licenses/MIT 41 | 42 | */ 43 | 44 | //determine the game 45 | #define GAME_ID 15 46 | 47 | #include "globals.h" 48 | #include "runner.h" 49 | #include "menu.h" 50 | #include "game.h" 51 | #include "items.h" 52 | #include "playfield.h" 53 | 54 | 55 | typedef void (*FunctionPointer) (); 56 | 57 | const FunctionPointer PROGMEM mainGameLoop[] = { 58 | stateMenuIntro, 59 | stateMenuMain, 60 | stateMenuHelp, 61 | stateMenuPlay, 62 | stateMenuInfo, 63 | stateMenuSoundfx, 64 | stateGameInitLevel, 65 | stateGamePlaying, 66 | stateGamePause, 67 | stateGameOver, 68 | }; 69 | 70 | void setup () { 71 | arduboy.begin(); 72 | beep.begin(); 73 | arduboy.setFrameRate(FRAME_RATE); 74 | arduboy.initRandomSeed(); 75 | arduboy.audio.on(); 76 | 77 | } 78 | 79 | void loop() { 80 | if (!(arduboy.nextFrame())) return; 81 | arduboy.pollButtons(); 82 | arduboy.clear(); 83 | 84 | 85 | // ((FunctionPointer) pgm_read_word (&mainGameLoop[gameState]))(); 86 | 87 | switch (gameState) { 88 | 89 | case 0: 90 | stateMenuIntro(); 91 | break; 92 | 93 | case 1: 94 | stateMenuMain(); 95 | break; 96 | case 2: 97 | stateMenuHelp(); 98 | break; 99 | case 3: 100 | stateMenuPlay(); 101 | break; 102 | case 4: 103 | stateMenuInfo(); 104 | break; 105 | case 5: 106 | stateMenuSoundfx(); 107 | break; 108 | case 6: 109 | stateGameInitLevel(); 110 | break; 111 | case 7: 112 | stateGamePlaying(); 113 | break; 114 | case 8: 115 | stateGamePause(); 116 | break; 117 | case 9: 118 | stateGameOver(); 119 | break; 120 | } 121 | 122 | 123 | arduboy.display(); 124 | } 125 | -------------------------------------------------------------------------------- /examples/ESP8266_evade/letters.h: -------------------------------------------------------------------------------- 1 | #ifndef LETTERS_H 2 | #define LETTERS_H 3 | 4 | /* 5 | * File: letters.h 6 | * Purpose: Bitmap font used in Evade game. 7 | * Author: Modus Create 8 | */ 9 | 10 | PROGMEM const unsigned char A[] = { 11 | // width, height 12 | 7, 6, 13 | 0x20, 0x38, 0x2E, 0x23, 0x2E, 0x18, 0x20 14 | }; 15 | 16 | PROGMEM const unsigned char B[] = { 17 | 6, 6, 18 | 0x3F, 0x21, 0x21, 0x2D, 0x2D, 0x33 19 | }; 20 | 21 | PROGMEM const unsigned char C[] = { 22 | 6, 6, 23 | 0x0E, 0x1F, 0x31, 0x21, 0x31, 0x13 24 | }; 25 | 26 | PROGMEM const unsigned char colon[] = { 27 | 2, 6, 28 | 0x36, 0x36 29 | }; 30 | 31 | PROGMEM const unsigned char D[] = { 32 | 5, 6, 33 | 0x3F, 0x21, 0x21, 0x33, 0x1E 34 | }; 35 | 36 | PROGMEM const unsigned char E[] = { 37 | 4, 6, 38 | 0x3F, 0x21, 0x2D, 0x2D 39 | }; 40 | 41 | PROGMEM const unsigned char F[] = { 42 | 4, 6, 43 | 0x3F, 0x01, 0x0D, 0x0D 44 | }; 45 | 46 | PROGMEM const unsigned char G[] = { 47 | 6, 6, 48 | 0x1E, 0x33, 0x21, 0x29, 0x29, 0x1A 49 | }; 50 | 51 | PROGMEM const unsigned char H[] = { 52 | 5, 6, 53 | 0x3F, 0x0C, 0x0C, 0x00, 0x3F 54 | }; 55 | 56 | PROGMEM const unsigned char I[] = { 57 | 1, 6, 58 | 0x3F 59 | }; 60 | 61 | PROGMEM const unsigned char J[] = { 62 | 5, 6, 63 | 0x18, 0x30, 0x20, 0x30, 0x1F 64 | }; 65 | 66 | PROGMEM const unsigned char K[] = { 67 | 5, 6, 68 | 0x3F, 0x0C, 0x00, 0x0C, 0x33 69 | }; 70 | 71 | PROGMEM const unsigned char L[] = { 72 | 4, 6, 73 | 0x3F, 0x20, 0x20, 0x20 74 | }; 75 | 76 | PROGMEM const unsigned char M[] = { 77 | 8, 6, 78 | 0x38, 0x0E, 0x07, 0x0C, 0x0C, 0x07, 0x0E, 0x38 79 | }; 80 | 81 | PROGMEM const unsigned char N[] = { 82 | 6, 6, 83 | 0x3F, 0x03, 0x06, 0x1C, 0x30, 0x3F 84 | }; 85 | 86 | PROGMEM const unsigned char O[] = { 87 | 6, 6, 88 | 0x1E, 0x33, 0x21, 0x21, 0x33, 0x1E 89 | }; 90 | 91 | PROGMEM const unsigned char P[] = { 92 | 5, 6, 93 | 0x3F, 0x01, 0x09, 0x09, 0x0F 94 | }; 95 | 96 | PROGMEM const unsigned char period[] = { 97 | 2, 6, 98 | 0x30, 0x30 99 | }; 100 | 101 | PROGMEM const unsigned char Q[] = { 102 | 6, 6, 103 | 0x1E, 0x33, 0x21, 0x21, 0x11, 0x2E 104 | }; 105 | 106 | PROGMEM const unsigned char R[] = { 107 | 5, 6, 108 | 0x3F, 0x01, 0x09, 0x1D, 0x37 109 | }; 110 | 111 | PROGMEM const unsigned char S[] = { 112 | 6, 6, 113 | 0x27, 0x25, 0x21, 0x25, 0x3D, 0x19 114 | }; 115 | 116 | PROGMEM const unsigned char T[] = { 117 | 5, 6, 118 | 0x01, 0x01, 0x3F, 0x01, 0x01 119 | }; 120 | 121 | PROGMEM const unsigned char U[] = { 122 | 6, 6, 123 | 0x1F, 0x30, 0x20, 0x20, 0x30, 0x1F 124 | }; 125 | 126 | PROGMEM const unsigned char V[] = { 127 | 7, 6, 128 | 0x03, 0x0C, 0x10, 0x20, 0x10, 0x0C, 0x03 129 | }; 130 | 131 | PROGMEM const unsigned char W[] = { 132 | 8, 6, 133 | 0x3F, 0x30, 0x18, 0x06, 0x06, 0x18, 0x30, 0x3F 134 | }; 135 | 136 | PROGMEM const unsigned char X[] = { 137 | 6, 6, 138 | 0x21, 0x1E, 0x00, 0x0C, 0x1E, 0x21 139 | }; 140 | 141 | PROGMEM const unsigned char Y[] = { 142 | 5, 6, 143 | 0x03, 0x06, 0x3C, 0x06, 0x03 144 | }; 145 | 146 | PROGMEM const unsigned char Z[] = { 147 | 6, 6, 148 | 0x21, 0x31, 0x3D, 0x27, 0x23, 0x21 149 | }; 150 | 151 | PROGMEM const unsigned char exclamation[] = { 152 | 1, 6, 153 | 0x2F 154 | }; 155 | 156 | #endif 157 | -------------------------------------------------------------------------------- /examples/ESP8266_Mystic_Balloon/inputs.h: -------------------------------------------------------------------------------- 1 | #ifndef INPUT_H 2 | #define INPUT_H 3 | 4 | #include 5 | #include "globals.h" 6 | #include "player.h" 7 | 8 | #define TIMER_AMOUNT 48 9 | 10 | void checkInputs() 11 | { 12 | if (kid.balloons <= 0) 13 | return; // Cannot control player if dead 14 | 15 | 16 | cam.offset = vec2(0, 0); 17 | kid.isWalking = false; 18 | if (arduboy.pressed(DOWN_BUTTON)) 19 | { 20 | cam.offset.y = -CAMERA_OFFSET; 21 | } 22 | else if (arduboy.pressed(UP_BUTTON)) 23 | { 24 | cam.offset.y = CAMERA_OFFSET; 25 | } 26 | if (!kid.isSucking) 27 | { 28 | if (arduboy.pressed(LEFT_BUTTON)) 29 | { 30 | mapTimer = TIMER_AMOUNT; 31 | cam.offset.x = CAMERA_OFFSET; 32 | kid.direction = FACING_LEFT; 33 | if (!(kid.isJumping || kid.isBalloon || kid.isLanding)) 34 | { 35 | if (!gridGetSolid((kid.pos.x - 1) >> 4, (kid.pos.y + 8) >> 4)) 36 | kid.actualpos.x -= PLAYER_SPEED_WALKING; 37 | kid.isWalking = true; 38 | kid.speed.x = -1; 39 | } 40 | else 41 | { 42 | //kid.speed.x = max(kid.speed.x - PLAYER_SPEED_AIR, -MAX_XSPEED); 43 | if (kid.speed.x > -MAX_XSPEED) 44 | kid.speed.x -= PLAYER_SPEED_AIR; 45 | } 46 | } 47 | else if (arduboy.pressed(RIGHT_BUTTON)) 48 | { 49 | //mapTimer = TIMER_AMOUNT; 50 | cam.offset.x = -CAMERA_OFFSET; 51 | kid.direction = FACING_RIGHT; 52 | if (!(kid.isJumping || kid.isBalloon || kid.isLanding)) 53 | { 54 | if (!gridGetSolid((kid.pos.x + 12) >> 4, (kid.pos.y + 8) >> 4)) 55 | kid.actualpos.x += PLAYER_SPEED_WALKING; 56 | kid.isWalking = true; 57 | kid.speed.x = 1; 58 | } 59 | else 60 | { 61 | //kid.speed.x = min(kid.speed.x + PLAYER_SPEED_AIR, MAX_XSPEED); 62 | if (kid.speed.x < MAX_XSPEED) 63 | kid.speed.x += PLAYER_SPEED_AIR; 64 | } 65 | } 66 | } 67 | kid.isSucking = false; 68 | if (arduboy.pressed(A_BUTTON)) 69 | { 70 | if (arduboy.pressed(DOWN_BUTTON)) 71 | gameState = STATE_GAME_PAUSE; 72 | else //if (!kid.isBalloon) 73 | { 74 | kid.isBalloon = false; 75 | kid.isSucking = true; 76 | } 77 | } 78 | /*if (arduboy.pressed(A_BUTTON + DOWN_BUTTON)) gameState = STATE_GAME_PAUSE; 79 | if (arduboy.pressed(A_BUTTON) && !kid.isBalloon) 80 | { 81 | kid.isSucking = true; 82 | } 83 | else 84 | kid.isSucking = false;*/ 85 | 86 | // Jump Button 87 | if (arduboy.justPressed(B_BUTTON)) 88 | { 89 | if (kid.speed.y == 0 && kid.isJumping == false && kid.isLanding == false) 90 | { 91 | sound(200, 100); 92 | kid.isWalking = false; 93 | kid.isJumping = true; 94 | kid.jumpLetGo = false; 95 | kid.jumpTimer = PLAYER_JUMP_TIME; 96 | kid.speed.y = PLAYER_JUMP_VELOCITY; 97 | if (arduboy.pressed(RIGHT_BUTTON)) kid.speed.x = MAX_XSPEED; 98 | else if (arduboy.pressed(LEFT_BUTTON)) kid.speed.x = -MAX_XSPEED; 99 | } 100 | else 101 | { 102 | if (kid.balloons > 0) 103 | { 104 | kid.isBalloon = true; 105 | kid.balloonOffset = 16; 106 | kid.isJumping = false; 107 | kid.isLanding = true; 108 | } 109 | } 110 | } 111 | if (!arduboy.pressed(B_BUTTON)) 112 | { 113 | kid.isBalloon = false; 114 | if (kid.isJumping) kid.jumpLetGo = true; 115 | } 116 | } 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /examples/ESP8266_evade/messagecatalog.h: -------------------------------------------------------------------------------- 1 | #ifndef MESSAGECATALOG_H 2 | #define MESSAGECATALOG_H 3 | 4 | /* 5 | * File: messagecatalog.h 6 | * Purpose: Stores credits and other text messages used in Evade game. 7 | * Author: Modus Create 8 | */ 9 | 10 | //YOU SURVIVED BUT 11 | PROGMEM const uint8_t playerWon0[] = { 12 | 16, // Number characters 13 | 24, 14, 20, 255, 18, 20, 17, 21, 8, 21, 4, 3, 255, 1, 20, 19 14 | }; 15 | 16 | //THE MISSION CONTINUES. 17 | PROGMEM const uint8_t playerWon1[] = { 18 | 22, 19 | 19, 7, 4, 255, 12, 8, 18, 18, 8, 14, 13, 255, 2, 14, 13, 19, 8, 13, 20, 4, 18, 27 20 | }; 21 | 22 | //ENEMIES APPROACHING! 23 | PROGMEM const uint8_t playerWon2[] = { 24 | 19, 25 | 4, 13, 4, 12, 8, 4, 18, 255, 0, 15, 15, 17, 14, 0, 2, 7, 8, 13, 6, //28 26 | }; 27 | 28 | 29 | 30 | 31 | //ALIENS INVADED OUR 32 | PROGMEM const uint8_t preIntro0[] = { 33 | 19,// Number characters 34 | 0, 11, 8, 4, 13, 18, 255, 8, 13, 21, 0, 3, 4, 3, 255, 14, 20, 17, 255 35 | }; 36 | 37 | //COLONY AND KILLED 38 | PROGMEM const uint8_t preIntro1[] = { 39 | 18,// Number characters 40 | 2, 14, 11, 14, 13, 24, 255, 0, 13, 3, 255, 10, 8, 11, 11, 4, 3, 255 41 | }; 42 | 43 | //EVERYONE! 44 | PROGMEM const uint8_t preIntro2[] = { 45 | 9,// Number characters 46 | 4, 21, 4, 17, 24, 14, 13, 4, 27 47 | }; 48 | 49 | //YOUR NEW MISSION: 50 | PROGMEM const uint8_t preIntro3[] = { 51 | 17,// Number characters 52 | 24, 14, 20, 17, 255, 13, 4, 22, 255, 12, 8, 18, 18, 8, 14, 13, 26 53 | }; 54 | 55 | //ESCAPE AND... 56 | PROGMEM const uint8_t preIntro4[] = { 57 | 13,// Number characters 58 | 4, 18, 2, 0, 15, 4, 255, 0, 13, 3, 27, 27, 27 59 | }; 60 | 61 | 62 | 63 | //CREDITS: 64 | PROGMEM const uint8_t credits0[] = { 65 | 8, 66 | 2, 17, 4, 3, 8, 19, 18, 26 67 | }; 68 | 69 | //J. GARCIA 70 | PROGMEM const uint8_t credits1[] = { 71 | 9, 72 | 9, 27, 255, 6, 0, 17, 2, 8, 0 73 | }; 74 | 75 | //S. PRICKETT 76 | PROGMEM const uint8_t credits2[] = { 77 | 11, 78 | 18, 27, 255, 15, 17, 8, 2, 10, 4, 19, 19 79 | }; 80 | 81 | //S. BERSHADSKIY 82 | PROGMEM const uint8_t credits3[] = { 83 | 14, 84 | 18, 27, 255, 1, 4, 17, 18, 7, 0, 3, 18, 10, 8, 24 85 | }; 86 | 87 | //A. OWEN 88 | PROGMEM const uint8_t credits4[] = { 89 | 7, 90 | 0, 27, 255, 14, 22, 4, 13 91 | }; 92 | 93 | //A. DENNIS 94 | PROGMEM const uint8_t credits5[] = { 95 | 9, 96 | 0, 27, 255, 3, 4, 13, 13, 8, 18 97 | }; 98 | 99 | //T. EAGAN 100 | PROGMEM const uint8_t credits6[] = { 101 | 8, 102 | 19, 27, 255, 4, 0, 6, 0, 13 103 | }; 104 | 105 | //D. GRIFFITH 106 | PROGMEM const uint8_t credits7[] = { 107 | 11, 108 | 3, 27, 255, 6, 17, 8, 5, 5, 8, 19, 7 109 | }; 110 | 111 | //JD JONES 112 | PROGMEM const uint8_t credits8[] = { 113 | 8, 114 | 9, 3, 255, 9, 14, 13, 4, 18 115 | }; 116 | 117 | //J. VAN DALEN 118 | PROGMEM const uint8_t credits9[] = { 119 | 12, 120 | 9, 27, 255, 21, 0, 13, 255, 3, 0, 11, 4, 13 121 | }; 122 | 123 | //L. STILL 124 | PROGMEM const uint8_t credits10[] = { 125 | 8, 126 | 11, 27, 255, 18, 19, 8, 11, 11 127 | }; 128 | 129 | //M. MCCANTS 130 | PROGMEM const uint8_t credits11[] = { 131 | 10, 132 | 12, 27, 255, 12, 2, 2, 0, 13, 19, 18 133 | }; 134 | 135 | //PLAY 136 | PROGMEM const uint8_t titleScreenText1[] = { 137 | 4, 138 | 15, 11, 0, 24 139 | }; 140 | 141 | //CREDITS 142 | PROGMEM const uint8_t titleScreenText2[] = { 143 | 7, 144 | 2, 17, 4, 3, 8, 19, 18 145 | }; 146 | 147 | //SETTINGS 148 | PROGMEM const uint8_t titleScreenText3[] = { 149 | 8, 150 | 18, 4, 19, 19, 8, 13, 6, 18 151 | }; 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /examples/ESP8266_Buttons/ESP8266_Buttons.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Buttons example 3 | June 11, 2015 4 | Copyright (C) 2015 David Martinez 5 | All rights reserved. 6 | This code is the most basic barebones code for showing how to use buttons in 7 | Arduboy. 8 | 9 | This library is free software; you can redistribute it and/or 10 | modify it under the terms of the GNU Lesser General Public 11 | License as published by the Free Software Foundation; either 12 | version 2.1 of the License, or (at your option) any later version. 13 | */ 14 | 15 | #include 16 | 17 | // Make an instance of arduboy used for many functions 18 | Arduboy2 arduboy; 19 | 20 | // Variables for your game go here. 21 | char title[] = "Press Buttons!"; 22 | byte x; 23 | byte y; 24 | 25 | // Width of each charcter including inter-character space 26 | #define CHAR_WIDTH 6 27 | 28 | // Height of each charater 29 | #define CHAR_HEIGHT 8 30 | 31 | // To get the number of characters, we subtract 1 from the length of 32 | // the array because there will be a NULL terminator at the end. 33 | #define NUM_CHARS (sizeof(title) - 1) 34 | 35 | // This is the highest value that x can be without the end of the text 36 | // going farther than the right side of the screen. We add one because 37 | // there will be a 1 pixel space at the end of the last character. 38 | // WIDTH and HEIGHT are defined in the Arduboy library. 39 | #define X_MAX (WIDTH - (NUM_CHARS * CHAR_WIDTH) + 1) 40 | 41 | // This is the highest value that y can be without the text going below 42 | // the bottom of the screen. 43 | #define Y_MAX (HEIGHT - CHAR_HEIGHT) 44 | 45 | 46 | // This function runs once in your game. 47 | // use it for anything that needs to be set only once in your game. 48 | void setup() { 49 | //initiate arduboy instance 50 | arduboy.begin(); 51 | 52 | // here we set the framerate to 30, we do not need to run at default 60 and 53 | // it saves us battery life. 54 | arduboy.setFrameRate(30); 55 | 56 | // set x and y to the middle of the screen 57 | x = (WIDTH / 2) - (NUM_CHARS * CHAR_WIDTH / 2); 58 | y = (HEIGHT / 2) - (CHAR_HEIGHT / 2); 59 | } 60 | 61 | 62 | // our main game loop, this runs once every cycle/frame. 63 | // this is where our game logic goes. 64 | void loop() { 65 | // pause render until it's time for the next frame 66 | if (!(arduboy.nextFrame())) 67 | return; 68 | 69 | // the next couple of lines will deal with checking if the D-pad buttons 70 | // are pressed and move our text accordingly. 71 | // We check to make sure that x and y stay within a range that keeps the 72 | // text on the screen. 73 | 74 | // if the right button is pressed move 1 pixel to the right every frame 75 | if(arduboy.pressed(RIGHT_BUTTON) && (x < X_MAX)) { 76 | x++; 77 | } 78 | 79 | // if the left button is pressed move 1 pixel to the left every frame 80 | if(arduboy.pressed(LEFT_BUTTON) && (x > 0)) { 81 | x--; 82 | } 83 | 84 | // if the up button or B button is pressed move 1 pixel up every frame 85 | if((arduboy.pressed(UP_BUTTON) || arduboy.pressed(B_BUTTON)) && (y > 0)) { 86 | y--; 87 | } 88 | 89 | // if the down button or A button is pressed move 1 pixel down every frame 90 | if((arduboy.pressed(DOWN_BUTTON) || arduboy.pressed(A_BUTTON)) && (y < Y_MAX)) { 91 | y++; 92 | } 93 | 94 | 95 | // we clear our screen to black 96 | arduboy.clear(); 97 | 98 | // we set our cursor x pixels to the right and y down from the top 99 | arduboy.setCursor(x, y); 100 | 101 | // then we print to screen what is stored in our title variable we declared earlier 102 | arduboy.print(title); 103 | 104 | // then we finaly we tell the arduboy to display what we just wrote to the display. 105 | arduboy.display(); 106 | } 107 | -------------------------------------------------------------------------------- /src/ab_logo.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ab_logo.c 3 | * \brief 4 | * The ARDUBOY logo bitmap. 5 | */ 6 | 7 | #include 8 | 9 | #ifndef ARDUBOY_LOGO_CREATED 10 | #define ARDUBOY_LOGO_CREATED 11 | 12 | // arduboy_logo.png 13 | // drawBitmap() format 14 | // 88x16 15 | const uint8_t arduboy_logo[] PROGMEM = { 16 | 0xF0, 0xF8, 0x9C, 0x8E, 0x87, 0x83, 0x87, 0x8E, 0x9C, 0xF8, 17 | 0xF0, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03, 18 | 0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0x03, 19 | 0x03, 0x03, 0x03, 0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xFF, 20 | 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 21 | 0x00, 0x00, 0xFE, 0xFF, 0x83, 0x83, 0x83, 0x83, 0x83, 0xC7, 22 | 0xEE, 0x7C, 0x38, 0x00, 0x00, 0xF8, 0xFC, 0x0E, 0x07, 0x03, 23 | 0x03, 0x03, 0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0x3F, 0x7F, 24 | 0xE0, 0xC0, 0x80, 0x80, 0xC0, 0xE0, 0x7F, 0x3F, 0xFF, 0xFF, 25 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0x00, 26 | 0x00, 0xFF, 0xFF, 0x0C, 0x0C, 0x0C, 0x0C, 0x1C, 0x3E, 0x77, 27 | 0xE3, 0xC1, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 28 | 0xC0, 0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00, 0x1F, 0x3F, 0x70, 29 | 0xE0, 0xC0, 0xC0, 0xC0, 0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00, 30 | 0x7F, 0xFF, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xE3, 0x77, 0x3E, 31 | 0x1C, 0x00, 0x00, 0x1F, 0x3F, 0x70, 0xE0, 0xC0, 0xC0, 0xC0, 32 | 0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 33 | 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00 34 | }; 35 | 36 | // arduboy_logo.png 37 | // drawCompressed() format 38 | // 88x16 39 | const uint8_t arduboy_logo_compressed[] PROGMEM = { 40 | 0x57, 0x0F, 0x9C, 0x53, 0x72, 0x75, 0x29, 0xE5, 0x9C, 0x92, 41 | 0xCE, 0x95, 0x52, 0xAD, 0x4E, 0x49, 0xE7, 0x08, 0x09, 0xED, 42 | 0x76, 0xBB, 0xDD, 0x2A, 0xAB, 0xAC, 0x55, 0x92, 0x90, 0xD0, 43 | 0x6E, 0xB7, 0xDB, 0xAD, 0xB2, 0xCA, 0x5A, 0x25, 0xF9, 0xF8, 44 | 0xF0, 0xC6, 0x47, 0x48, 0x28, 0x95, 0x54, 0x52, 0x49, 0x25, 45 | 0x9D, 0x3A, 0x95, 0x5A, 0x3A, 0x45, 0x2A, 0xB7, 0x29, 0xA7, 46 | 0xE4, 0x76, 0xBB, 0x55, 0x56, 0x59, 0xAB, 0x24, 0x9F, 0x5D, 47 | 0x5B, 0x65, 0xD7, 0xE9, 0xEC, 0x92, 0x29, 0x3B, 0xA1, 0x4E, 48 | 0xA7, 0xD3, 0xE9, 0x74, 0x9A, 0x8F, 0x8F, 0xEF, 0xED, 0x76, 49 | 0xBB, 0x55, 0x4E, 0xAE, 0x52, 0xAD, 0x9C, 0x9C, 0x4F, 0xE7, 50 | 0xED, 0x76, 0xBB, 0xDD, 0x2E, 0x95, 0x53, 0xD9, 0x25, 0xA5, 51 | 0x54, 0xD6, 0x2A, 0xAB, 0xEC, 0x76, 0xBB, 0x54, 0x4E, 0x65, 52 | 0x97, 0x94, 0x3A, 0x22, 0xA9, 0xA4, 0x92, 0x4A, 0x2A, 0xE9, 53 | 0x94, 0x4D, 0x2D, 0x9D, 0xA2, 0x94, 0xCA, 0x5A, 0x65, 0x95, 54 | 0xDD, 0x6E, 0x97, 0xCA, 0xA9, 0xEC, 0x12, 0x55, 0x69, 0x42, 55 | 0x7A 56 | }; 57 | 58 | // arduboy_logo.png 59 | // Sprites::drawSelfMasked() format 60 | // 88x16 61 | const uint8_t arduboy_logo_sprite[] PROGMEM = { 62 | 88, 16, 63 | 0xF0, 0xF8, 0x9C, 0x8E, 0x87, 0x83, 0x87, 0x8E, 0x9C, 0xF8, 64 | 0xF0, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03, 65 | 0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0x03, 66 | 0x03, 0x03, 0x03, 0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xFF, 67 | 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 68 | 0x00, 0x00, 0xFE, 0xFF, 0x83, 0x83, 0x83, 0x83, 0x83, 0xC7, 69 | 0xEE, 0x7C, 0x38, 0x00, 0x00, 0xF8, 0xFC, 0x0E, 0x07, 0x03, 70 | 0x03, 0x03, 0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0x3F, 0x7F, 71 | 0xE0, 0xC0, 0x80, 0x80, 0xC0, 0xE0, 0x7F, 0x3F, 0xFF, 0xFF, 72 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0x00, 73 | 0x00, 0xFF, 0xFF, 0x0C, 0x0C, 0x0C, 0x0C, 0x1C, 0x3E, 0x77, 74 | 0xE3, 0xC1, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 75 | 0xC0, 0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00, 0x1F, 0x3F, 0x70, 76 | 0xE0, 0xC0, 0xC0, 0xC0, 0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00, 77 | 0x7F, 0xFF, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xE3, 0x77, 0x3E, 78 | 0x1C, 0x00, 0x00, 0x1F, 0x3F, 0x70, 0xE0, 0xC0, 0xC0, 0xC0, 79 | 0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 80 | 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00 81 | }; 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Arduboy2 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | Arduboy2 KEYWORD1 10 | Arduboy2Base KEYWORD1 11 | BeepPin1 KEYWORD1 12 | BeepPin2 KEYWORD1 13 | Point KEYWORD1 14 | Rect KEYWORD1 15 | Sprites KEYWORD1 16 | SpritesB KEYWORD1 17 | 18 | ####################################### 19 | # Methods and Functions (KEYWORD2) 20 | ####################################### 21 | 22 | allPixelsOn KEYWORD2 23 | begin KEYWORD2 24 | blank KEYWORD2 25 | boot KEYWORD2 26 | bootLogo KEYWORD2 27 | bootLogoCompressed KEYWORD2 28 | bootLogoShell KEYWORD2 29 | bootLogoSpritesBOverwrite KEYWORD2 30 | bootLogoSpritesBSelfMasked KEYWORD2 31 | bootLogoSpritesOverwrite KEYWORD2 32 | bootLogoSpritesSelfMasked KEYWORD2 33 | bootLogoText KEYWORD2 34 | buttonsState KEYWORD2 35 | clear KEYWORD2 36 | collide KEYWORD2 37 | cpuLoad KEYWORD2 38 | delayShort KEYWORD2 39 | digitalWriteRGB KEYWORD2 40 | display KEYWORD2 41 | displayOff KEYWORD2 42 | displayOn KEYWORD2 43 | drawBitmap KEYWORD2 44 | drawChar KEYWORD2 45 | drawCircle KEYWORD2 46 | drawCompressed KEYWORD2 47 | drawFastHLine KEYWORD2 48 | drawFastVLine KEYWORD2 49 | drawLine KEYWORD2 50 | drawPixel KEYWORD2 51 | drawRect KEYWORD2 52 | drawRoundRect KEYWORD2 53 | drawSlowXYBitmap KEYWORD2 54 | drawTriangle KEYWORD2 55 | enabled KEYWORD2 56 | everyXFrames KEYWORD2 57 | exitToBootloader KEYWORD2 58 | fillCircle KEYWORD2 59 | fillRect KEYWORD2 60 | fillRoundRect KEYWORD2 61 | fillScreen KEYWORD2 62 | fillTriangle KEYWORD2 63 | flashlight KEYWORD2 64 | flipVertical KEYWORD2 65 | flipHorizontal KEYWORD2 66 | freeRGBled KEYWORD2 67 | generateRandomSeed KEYWORD2 68 | getBuffer KEYWORD2 69 | getCursorX KEYWORD2 70 | getCursorY KEYWORD2 71 | getPixel KEYWORD2 72 | getTextBackground KEYWORD2 73 | getTextColor KEYWORD2 74 | getTextSize KEYWORD2 75 | getTextWrap KEYWORD2 76 | height KEYWORD2 77 | idle KEYWORD2 78 | initRandomSeed KEYWORD2 79 | invert KEYWORD2 80 | justPressed KEYWORD2 81 | justReleased KEYWORD2 82 | nextFrame KEYWORD2 83 | nextFrameDEV KEYWORD2 84 | notPressed KEYWORD2 85 | off KEYWORD2 86 | on KEYWORD2 87 | paint8Pixels KEYWORD2 88 | paintScreen KEYWORD2 89 | pollButtons KEYWORD2 90 | pressed KEYWORD2 91 | readShowBootLogoFlag KEYWORD2 92 | readShowBootLogoLEDsFlag KEYWORD2 93 | readShowUnitNameFlag KEYWORD2 94 | readUnitID KEYWORD2 95 | readUnitName KEYWORD2 96 | safeMode KEYWORD2 97 | saveOnOff KEYWORD2 98 | setCursor KEYWORD2 99 | setFrameDuration KEYWORD2 100 | setFrameRate KEYWORD2 101 | setRGBled KEYWORD2 102 | setTextBackground KEYWORD2 103 | setTextColor KEYWORD2 104 | setTextSize KEYWORD2 105 | setTextWrap KEYWORD2 106 | SPItransfer KEYWORD2 107 | systemButtons KEYWORD2 108 | toggle KEYWORD2 109 | waitNoButtons KEYWORD2 110 | width KEYWORD2 111 | writeShowBootLogoFlag KEYWORD2 112 | writeShowBootLogoLEDsFlag KEYWORD2 113 | writeShowUnitNameFlag KEYWORD2 114 | writeUnitID KEYWORD2 115 | writeUnitName KEYWORD2 116 | 117 | # Arduboy2Beep classes 118 | freq KEYWORD2 119 | noTone KEYWORD2 120 | timer KEYWORD2 121 | tone KEYWORD2 122 | 123 | # Sprites class 124 | drawErase KEYWORD2 125 | drawExternalMask KEYWORD2 126 | drawOverwrite KEYWORD2 127 | drawPlusMask KEYWORD2 128 | drawSelfMasked KEYWORD2 129 | 130 | ####################################### 131 | # Constants (LITERAL1) 132 | ####################################### 133 | 134 | ARDUBOY_LIB_VER LITERAL1 135 | 136 | ARDUBOY_UNIT_NAME_LEN LITERAL1 137 | 138 | EEPROM_STORAGE_SPACE_START LITERAL1 139 | 140 | HEIGHT LITERAL1 141 | WIDTH LITERAL1 142 | 143 | BLACK LITERAL1 144 | WHITE LITERAL1 145 | INVERT LITERAL1 146 | 147 | CLEAR_BUFFER LITERAL1 148 | 149 | A_BUTTON LITERAL1 150 | B_BUTTON LITERAL1 151 | DOWN_BUTTON LITERAL1 152 | LEFT_BUTTON LITERAL1 153 | RIGHT_BUTTON LITERAL1 154 | UP_BUTTON LITERAL1 155 | 156 | PIN_SPEAKER_1 LITERAL1 157 | PIN_SPEAKER_2 LITERAL1 158 | 159 | BLUE_LED LITERAL1 160 | GREEN_LED LITERAL1 161 | RED_LED LITERAL1 162 | 163 | RGB_OFF LITERAL1 164 | RGB_ON LITERAL1 165 | 166 | ARDUBOY_NO_USB LITERAL1 167 | 168 | -------------------------------------------------------------------------------- /examples/ESP8266_BeepDemo/ESP8266_BeepDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This sketch provides an example of using the Arduboy2 library's BeepPin1 class 3 | to play simple tones. 4 | */ 5 | 6 | /* 7 | To the extent possible under law, Scott Allen has waived all copyright and 8 | related or neighboring rights to this BeepDemo program. 9 | */ 10 | 11 | // Comments are only provided for code dealing with tone generation or control. 12 | 13 | #include 14 | // There's no need to #include 15 | // It will be included in Arduboy2.h 16 | 17 | Arduboy2 arduboy; 18 | 19 | BeepPin1 beep; // Create a class instance for speaker pin 1 20 | //BeepPin2 beep; // For speaker pin 2, use this line instead of the line above 21 | 22 | int objectX = 0; 23 | 24 | char displayText[60]; 25 | 26 | void setup() { 27 | arduboy.begin(); 28 | arduboy.setFrameRate(25); 29 | 30 | beep.begin(); // Set up the hardware for playing tones 31 | 32 | commandText("none - Press buttons"); 33 | } 34 | 35 | void loop() { 36 | if (!arduboy.nextFrame()) { 37 | return; 38 | } 39 | 40 | // The timer() function is called once per frame, so duration values will be 41 | // the number of frames that the tone plays for. 42 | // At 25 frames per second each frame will be 40ms. 43 | beep.timer(); // handle tone duration 44 | 45 | arduboy.pollButtons(); 46 | 47 | if (arduboy.justPressed(LEFT_BUTTON)) { 48 | // Play a 523.251Hz tone (piano note C5) for 5 frames (200ms at 25 FPS) 49 | // beep.freq(523.251) is used to convert 523.251Hz to the required count 50 | beep.tone(beep.freq(523.251), 5); 51 | 52 | commandText("beep.tone(\n beep.freq(523.251),\n 5)"); 53 | } 54 | 55 | if (arduboy.justPressed(UP_BUTTON)) { 56 | // Play a 587.330Hz tone (piano note D5) for 15 frames (600ms at 25 FPS) 57 | beep.tone(beep.freq(587.330), 15); 58 | 59 | commandText("beep.tone(\n beep.freq(587.330),\n 15)"); 60 | } 61 | 62 | if (arduboy.justPressed(RIGHT_BUTTON)) { 63 | // Play a 659.255Hz tone (piano note E5) for 50 frames (2s at 25 FPS) 64 | beep.tone(beep.freq(659.255), 50); 65 | 66 | commandText("beep.tone(\n beep.freq(659.255),\n 50)"); 67 | } 68 | 69 | if (arduboy.justPressed(DOWN_BUTTON)) { 70 | // Play a 698.456Hz tone (piano note F5) until stopped 71 | // or replaced by another tone 72 | beep.tone(beep.freq(698.456)); 73 | 74 | commandText("beep.tone(\n beep.freq(698.456))"); 75 | } 76 | 77 | if (arduboy.justPressed(A_BUTTON)) { 78 | // For short tones with a duration less than a frame time, 79 | // or when timer() isn't being used, such as in a menu, 80 | // a continuous tone can be played and then stopped after a delay 81 | // but note that no other work will be done during the delay. 82 | beep.tone(beep.freq(1000)); // Play a 1000Hz tone until stopped 83 | arduboy.delayShort(30); // Delay for 30ms 84 | beep.noTone(); // Stop the tone 85 | 86 | commandText("beep.tone(\n beep.freq(1000))\n(delay 30ms)\nbeep.noTone()"); 87 | } 88 | 89 | if (arduboy.justPressed(B_BUTTON)) { 90 | beep.noTone(); // Stop the tone if one is playing 91 | 92 | commandText("beep.noTone()"); 93 | } 94 | 95 | arduboy.println(F("Last command:")); 96 | arduboy.print(displayText); 97 | 98 | // The Arduboy2 class's audio subclass controls sound muting. 99 | // For this sketch, mute or unmute can be set using the "System Control" 100 | // start up feature. (Hold B while powering up then, while still holding B, 101 | // press UP to enable sound or DOWN for mute.) 102 | if (!arduboy.audio.enabled()) { 103 | arduboy.setCursor(22, 40); 104 | arduboy.print(F("Sound is MUTED")); 105 | } 106 | 107 | arduboy.setCursor(0, 48); 108 | // The "duration" variable can be tested for non-zero to determine if a 109 | // timed tone is currently playing. 110 | if (beep.duration != 0) { 111 | arduboy.print(F("A tone is playing")); 112 | } 113 | else { 114 | arduboy.print(F("Continuous tone or\nno tone playing")); 115 | } 116 | 117 | arduboy.drawRect(objectX, 40, 6, 6); 118 | if (++objectX == WIDTH - 6) { 119 | objectX = 0; 120 | } 121 | 122 | arduboy.display(CLEAR_BUFFER); 123 | } 124 | 125 | void commandText(const char* text) { 126 | strncpy(displayText, text, sizeof displayText); 127 | displayText[sizeof displayText - 1] = '\0'; 128 | } 129 | 130 | -------------------------------------------------------------------------------- /examples/ESP8266_PaddleTest/ESP8266_PaddleTest.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ArduTewst 3 | 2019 02 06 4 | Billy Cheung 5 | This code tests the buttons and the sound output of Arduboy 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | */ 12 | 13 | #define paddle1X A0 14 | 15 | 16 | 17 | #define minPaddle 1 18 | #define maxPaddle 1024 19 | 20 | 21 | 22 | #include 23 | 24 | // Make an instance of arduboy used for many functions 25 | Arduboy2 arduboy; 26 | BeepPin1 beep; // Create a class instance for speaker pin 1 27 | 28 | 29 | // Variables for your game go here. 30 | char title[] = "*"; 31 | byte x; 32 | byte y; 33 | 34 | 35 | 36 | // Width of each charcter including inter-character space 37 | #define CHAR_WIDTH 6 38 | 39 | // Height of each charater 40 | #define CHAR_HEIGHT 8 41 | 42 | // To get the number of characters, we subtract 1 from the length of 43 | // the array because there will be a NULL terminator at the end. 44 | #define NUM_CHARS (sizeof(title) - 1) 45 | 46 | // This is the highest value that x can be without the end of the text 47 | // going farther than the right side of the screen. We add one because 48 | // there will be a 1 pixel space at the end of the last character. 49 | // WIDTH and HEIGHT are defined in the Arduboy library. 50 | #define X_MAX (WIDTH - (NUM_CHARS * CHAR_WIDTH) + 1) 51 | 52 | // This is the highest value that y can be without the text going below 53 | // the bottom of the screen. 54 | #define Y_MAX (HEIGHT - CHAR_HEIGHT) 55 | 56 | 57 | // This function runs once in your game. 58 | // use it for anything that needs to be set only once in your game. 59 | void setup() { 60 | //initiate arduboy instance 61 | arduboy.begin(); 62 | 63 | // here we set the framerate to 30, we do not need to run at default 60 and 64 | // it saves us battery life. 65 | arduboy.setFrameRate(30); 66 | 67 | arduboy.audio.on; 68 | 69 | 70 | } 71 | 72 | 73 | // our main game loop, this runs once every cycle/frame. 74 | // this is where our game logic goes. 75 | void loop() { 76 | 77 | 78 | // pause render until it's time for the next frame 79 | if (!(arduboy.nextFrame())) 80 | return; 81 | 82 | // The timer() function is called once per frame, so duration values will be 83 | // the number of frames that the tone plays for. 84 | // At 25 frames per second each frame will be 40ms. 85 | beep.timer(); // handle tone duration 86 | 87 | // we clear our screen to black 88 | arduboy.clear(); 89 | 90 | // the next couple of lines will deal with checking if the D-pad buttons 91 | // are pressed and print the text accordingly. 92 | arduboy.setCursor(0, 0); 93 | arduboy.print("ArduTest"); 94 | 95 | // Read paddle 1 values from ADC 96 | arduboy.setCursor(0, 10); 97 | arduboy.print("X1="); 98 | arduboy.setCursor(20, 10); 99 | arduboy.print (analogRead(paddle1X)); 100 | x = constrain (map (analogRead(paddle1X), minPaddle, maxPaddle, 0, X_MAX), 0, X_MAX); 101 | y= 20; 102 | 103 | 104 | 105 | // print a "*" at the current position of paddle1 106 | arduboy.setCursor(x, y); 107 | arduboy.print("*"); 108 | 109 | 110 | arduboy.setCursor(20, 30); 111 | if(arduboy.pressed(UP_BUTTON)) {arduboy.print("U"); beep.tone(beep.freq(523.251), 5);} else arduboy.print ("O"); 112 | 113 | arduboy.setCursor(20, 50); 114 | if(arduboy.pressed(DOWN_BUTTON)) { arduboy.print("D"); beep.tone(beep.freq(587.330), 5);} else arduboy.print ("O"); 115 | 116 | arduboy.setCursor(10, 40); 117 | if(arduboy.pressed(LEFT_BUTTON)) { arduboy.print("L"); beep.tone(beep.freq(659.255), 5);} else arduboy.print ("O"); 118 | 119 | arduboy.setCursor(30, 40); 120 | if(arduboy.pressed(RIGHT_BUTTON)) { arduboy.print("R"); beep.tone(beep.freq(698.456), 5);} else arduboy.print ("O"); 121 | 122 | arduboy.setCursor(60, 45); 123 | if(arduboy.pressed(A_BUTTON)) { arduboy.print("A"); beep.tone(beep.freq(784.251), 5);} else arduboy.print ("O"); 124 | 125 | arduboy.setCursor(75, 35); 126 | if(arduboy.pressed(B_BUTTON)) { arduboy.print("B"); beep.tone(beep.freq(880.251), 5);} else arduboy.print ("O"); 127 | 128 | 129 | 130 | // then we finaly we tell the arduboy to display what we just wrote to the display. 131 | arduboy.display(); 132 | } 133 | -------------------------------------------------------------------------------- /examples/ESP8266_Mystic_Balloon/menu.h: -------------------------------------------------------------------------------- 1 | #ifndef MENU_BITMAPS_H 2 | #define MENU_BITMAPS_H 3 | 4 | #include 5 | #include "globals.h" 6 | 7 | #define FONT_TINY 0 8 | #define FONT_SMALL 1 9 | #define FONT_BIG 2 10 | 11 | #define DATA_TIMER 0 12 | #define DATA_SCORE 1 13 | #define DATA_LEVEL 2 14 | 15 | byte blinkingFrames = 0; 16 | byte sparkleFrames = 0; 17 | byte cont = 0; 18 | 19 | extern void drawNumbers(byte numbersX, byte numbersY, byte fontType, byte data); 20 | 21 | void drawTitleScreen() 22 | { 23 | if (arduboy.everyXFrames(8))blinkingFrames = (++blinkingFrames) % 32; 24 | for (byte i = 0; i < 4; i++) sprites.drawSelfMasked(32 * i, 0, titleScreen, i); 25 | sprites.drawSelfMasked(85, 45, badgeMysticBalloon, 0); 26 | sprites.drawSelfMasked(79, 43, stars, sparkleFrames); 27 | sprites.drawSelfMasked(9, 9, leftGuyLeftEye, pgm_read_byte(&blinkingEyesLeftGuy[blinkingFrames])); 28 | sprites.drawSelfMasked(15, 13, leftGuyRightEye, pgm_read_byte(&blinkingEyesLeftGuy[blinkingFrames])); 29 | sprites.drawSelfMasked(109, 34, rightGuyEyes, pgm_read_byte(&blinkingEyesRightGuy[blinkingFrames])); 30 | } 31 | 32 | void stateMenuIntro() 33 | { 34 | globalCounter++; 35 | if (globalCounter < 160) 36 | { 37 | sprites.drawSelfMasked(34, 4, T_arg, 0); 38 | } 39 | else 40 | { 41 | drawTitleScreen(); 42 | if ((globalCounter > 250) || arduboy.justPressed(A_BUTTON | B_BUTTON)) 43 | { 44 | gameState = STATE_MENU_MAIN; 45 | sound(425, 20); 46 | } 47 | } 48 | } 49 | 50 | void stateMenuMain() 51 | { 52 | 53 | drawTitleScreen(); 54 | sprites.drawOverwrite(51, 9, mainMenu, 0); 55 | if (arduboy.justPressed(DOWN_BUTTON) && (menuSelection < 5)) 56 | { 57 | menuSelection++; 58 | sound(300, 20); 59 | } 60 | if (arduboy.justPressed(UP_BUTTON) && (menuSelection > 2)) 61 | { 62 | menuSelection--; 63 | sound(300, 20); 64 | } 65 | if (arduboy.justPressed(A_BUTTON | B_BUTTON)) 66 | { 67 | gameState = menuSelection; 68 | sound(425, 20); 69 | } 70 | sprites.drawPlusMask(46, 9 + 9 * (menuSelection - 2), selector_plus_mask, 0); 71 | } 72 | 73 | void stateMenuHelp() 74 | { 75 | for (byte i = 0; i < 2; i++) sprites.drawSelfMasked(32, 32 * i, qrcode, i); 76 | if (arduboy.justPressed(A_BUTTON | B_BUTTON)) 77 | { 78 | gameState = STATE_MENU_MAIN; 79 | sound(425, 20); 80 | } 81 | } 82 | 83 | 84 | void stateMenuInfo() 85 | { 86 | sprites.drawSelfMasked(43, 2, badgeMysticBalloon, 0); 87 | sprites.drawSelfMasked(37, 0, stars, sparkleFrames); 88 | sprites.drawSelfMasked(40, 48, madeBy, 0); 89 | EEPROM.get(OFFSET_HSCORE, scorePlayer); 90 | if (EEPROM.read(OFFSET_COINSHS) == TOTAL_COINS) 91 | { 92 | sprites.drawSelfMasked(21, 28, badgeSuper, 0); 93 | } 94 | else 95 | { 96 | sprites.drawSelfMasked(28, 28, badgeBorder, 0); 97 | } 98 | sprites.drawSelfMasked(30, 28, badgeHighScore, 0); 99 | drawNumbers(55, 30, FONT_BIG, DATA_SCORE); 100 | if (arduboy.justPressed(A_BUTTON | B_BUTTON)) 101 | { 102 | gameState = STATE_MENU_MAIN; 103 | sound(425, 20); 104 | } 105 | } 106 | 107 | void stateMenuSoundfx() 108 | { 109 | drawTitleScreen(); 110 | sprites.drawOverwrite(51, 9, soundMenu, 0); 111 | if (arduboy.justPressed(DOWN_BUTTON)) 112 | { 113 | arduboy.audio.on(); 114 | sound(300, 20); 115 | } 116 | if (arduboy.justPressed(UP_BUTTON)) arduboy.audio.off(); 117 | sprites.drawPlusMask(54, 18 + 9 * arduboy.audio.enabled(), selector_plus_mask, 0); 118 | if (arduboy.justPressed(A_BUTTON | B_BUTTON)) 119 | { 120 | arduboy.audio.saveOnOff(); 121 | gameState = STATE_MENU_MAIN; 122 | sound(425, 20); 123 | } 124 | } 125 | 126 | void stateMenuPlaySelect() 127 | { 128 | drawTitleScreen(); 129 | sprites.drawOverwrite(53, 18, continueMenu, 0); 130 | if (arduboy.justPressed(DOWN_BUTTON)) 131 | { 132 | cont = 1; 133 | sound(300, 20); 134 | } 135 | if (arduboy.justPressed(UP_BUTTON)) 136 | { 137 | cont = 0; 138 | sound(300, 20); 139 | } 140 | sprites.drawPlusMask(48, 18 + 9 * cont, selector_plus_mask, 0); 141 | if (arduboy.justPressed(B_BUTTON)) 142 | { 143 | gameState = STATE_GAME_PLAYCONTNEW + cont; 144 | cont = 0; 145 | sound(425, 20); 146 | } 147 | if (arduboy.justPressed(A_BUTTON)) 148 | { 149 | gameState = STATE_MENU_MAIN; 150 | sound(425, 20); 151 | } 152 | } 153 | 154 | 155 | #endif 156 | -------------------------------------------------------------------------------- /src/SpritesB.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file SpritesB.h 3 | * \brief 4 | * A class for drawing animated sprites from image and mask bitmaps. 5 | * Optimized for small code size. 6 | */ 7 | 8 | #ifndef SpritesB_h 9 | #define SpritesB_h 10 | 11 | #include "Arduboy2.h" 12 | #include "SpritesCommon.h" 13 | 14 | /** \brief 15 | * A class for drawing animated sprites from image and mask bitmaps. 16 | * Optimized for small code size. 17 | * 18 | * \details 19 | * The functions in this class are identical to the `Sprites` class. The only 20 | * difference is that the functions in this class are optimized for smaller 21 | * code size rather than execution speed. 22 | * 23 | * See the `Sprites` class documentation for details on the use of the 24 | * functions in this class. 25 | * 26 | * Even if the speed is acceptable when using `SpritesB`, you should still try 27 | * using `Sprites`. In some cases `Sprites` will produce less code than 28 | * `SpritesB`, notably when only one of the functions is used. 29 | * 30 | * You can easily switch between using the `Sprites` class or the `SpritesB` 31 | * class by using one or the other to create an object instance: 32 | * 33 | * \code{.cpp} 34 | * Sprites sprites; // Use this to optimize for execution speed 35 | * SpritesB sprites; // Use this to (likely) optimize for code size 36 | * \endcode 37 | * 38 | * \see Sprites 39 | */ 40 | class SpritesB 41 | { 42 | public: 43 | /** \brief 44 | * Draw a sprite using a separate image and mask array. 45 | * 46 | * \param x,y The coordinates of the top left pixel location. 47 | * \param bitmap A pointer to the array containing the image frames. 48 | * \param mask A pointer to the array containing the mask frames. 49 | * \param frame The frame number of the image to draw. 50 | * \param mask_frame The frame number for the mask to use (can be different 51 | * from the image frame number). 52 | * 53 | * \see Sprites::drawExternalMask() 54 | */ 55 | static void drawExternalMask(int16_t x, int16_t y, const uint8_t *bitmap, 56 | const uint8_t *mask, uint8_t frame, uint8_t mask_frame); 57 | 58 | /** \brief 59 | * Draw a sprite using an array containing both image and mask values. 60 | * 61 | * \param x,y The coordinates of the top left pixel location. 62 | * \param bitmap A pointer to the array containing the image/mask frames. 63 | * \param frame The frame number of the image to draw. 64 | * 65 | * \see Sprites::drawPlusMask() 66 | */ 67 | static void drawPlusMask(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame); 68 | 69 | /** \brief 70 | * Draw a sprite by replacing the existing content completely. 71 | * 72 | * \param x,y The coordinates of the top left pixel location. 73 | * \param bitmap A pointer to the array containing the image frames. 74 | * \param frame The frame number of the image to draw. 75 | * 76 | * \see Sprites::drawOverwrite() 77 | */ 78 | static void drawOverwrite(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame); 79 | 80 | /** \brief 81 | * "Erase" a sprite. 82 | * 83 | * \param x,y The coordinates of the top left pixel location. 84 | * \param bitmap A pointer to the array containing the image frames. 85 | * \param frame The frame number of the image to erase. 86 | * 87 | * \see Sprites::drawErase() 88 | */ 89 | static void drawErase(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame); 90 | 91 | /** \brief 92 | * Draw a sprite using only the bits set to 1. 93 | * 94 | * \param x,y The coordinates of the top left pixel location. 95 | * \param bitmap A pointer to the array containing the image frames. 96 | * \param frame The frame number of the image to draw. 97 | * 98 | * \see Sprites::drawSelfMasked() 99 | */ 100 | static void drawSelfMasked(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame); 101 | 102 | // Master function. Needs to be abstracted into separate function for 103 | // every render type. 104 | // (Not officially part of the API) 105 | static void draw(int16_t x, int16_t y, 106 | const uint8_t *bitmap, uint8_t frame, 107 | const uint8_t *mask, uint8_t sprite_frame, 108 | uint8_t drawMode); 109 | 110 | // (Not officially part of the API) 111 | static void drawBitmap(int16_t x, int16_t y, 112 | const uint8_t *bitmap, const uint8_t *mask, 113 | uint8_t w, uint8_t h, uint8_t draw_mode); 114 | }; 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /examples/ESP8266_Sirene/elements.h: -------------------------------------------------------------------------------- 1 | #ifndef ELEMENTS_H 2 | #define ELEMENTS_H 3 | 4 | #define POWER_UP_HEART 0 5 | #define POWER_UP_SHIELD 1 6 | #define POWER_UP_TRIDENT 2 7 | #define POWER_UP_BUBBLE 3 8 | #define POWER_UP_SEASHELL 4 9 | #define POWER_UP_MAGIC 5 10 | #define POWER_UP_STAR 6 11 | 12 | #define SMALL_PILLAR_DEPTH 28 13 | #define BIG_PILLAR_DEPTH 18 14 | #define SUNRAY_OFFSET 32 15 | 16 | 17 | 18 | #include 19 | #include "globals.h" 20 | 21 | 22 | byte powerUpArrayY[] = {11, 47, 23, 41, 35, 29, 17, 53}; 23 | byte bonusCount; 24 | 25 | struct Background 26 | { 27 | public: 28 | int x; 29 | }; 30 | 31 | struct Elements 32 | { 33 | public: 34 | int x; 35 | byte y; 36 | byte type; 37 | boolean isVisible; 38 | boolean isActive; 39 | }; 40 | 41 | struct Bonus 42 | { 43 | public: 44 | byte x; 45 | byte y; 46 | int amount; 47 | boolean isVisible; 48 | boolean isActive; 49 | }; 50 | 51 | Background Column[3]; 52 | Elements powerUP; 53 | Bonus bonus[2]; 54 | 55 | 56 | void setBackground() 57 | { 58 | backgroundIsVisible = true; 59 | Column[0].x = 28; 60 | Column[1].x = 92; 61 | Column[3].x = 128; 62 | } 63 | 64 | 65 | void checkBackground() 66 | { 67 | if (arduboy.everyXFrames(10)) 68 | { 69 | Column[0].x--; 70 | Column[1].x--; 71 | } 72 | if (arduboy.everyXFrames(3)) Column[2].x--; 73 | 74 | if (Column[0].x < -8) Column[0].x = 128; 75 | if (Column[1].x < -8) Column[1].x = 128; 76 | if (Column[2].x < -16) Column[2].x = 128; 77 | } 78 | 79 | void checkPowerUP() 80 | { 81 | if (powerUP.isActive) 82 | { 83 | if (arduboy.everyXFrames(5)) powerUP.isVisible = !powerUP.isVisible; 84 | if (arduboy.everyXFrames(2)) powerUP.x--; 85 | if (powerUP.x < -8) powerUP.isActive = false; 86 | } 87 | } 88 | 89 | 90 | void checkBonus() 91 | { 92 | for (byte i = 0; i < 2; i++) 93 | { 94 | if (bonus[i].isActive) 95 | { 96 | bonus[i].y--; 97 | bonus[i].isVisible = !bonus[i].isVisible; 98 | if (bonus[i].y < 2) 99 | { 100 | bonus[i].isActive = false; 101 | bonus[i].isVisible = false; 102 | } 103 | } 104 | } 105 | } 106 | 107 | 108 | void giveBonus(int amountBonus, byte positionX, byte positionY) 109 | { 110 | bonusCount++; 111 | if (bonusCount > 1) bonusCount = 0; 112 | bonus[bonusCount].x = positionX; 113 | bonus[bonusCount].y = positionY; 114 | bonus[bonusCount].amount = amountBonus; 115 | scorePlayer += amountBonus, 116 | bonus[bonusCount].isActive = true; 117 | bonus[bonusCount].isVisible = true; 118 | } 119 | 120 | 121 | void powerUPSet(byte typeSet) 122 | { 123 | powerUP.type = typeSet; 124 | powerUP.x = 128; 125 | powerUP.y = powerUpArrayY[powerUpSelectorY]; 126 | powerUP.isActive = true; 127 | powerUpSelectorY = (++powerUpSelectorY) % 8; 128 | } 129 | 130 | void drawBackground() 131 | { 132 | if (backgroundIsVisible) 133 | { 134 | for (byte z = 0; z < 2; z++) 135 | { 136 | for (byte i = 0; i < 3; i++) 137 | { 138 | sprites.drawSelfMasked(SUNRAY_OFFSET + (z * 15) + (8 * i), (8 * i), sunRay, i); 139 | } 140 | } 141 | sprites.drawPlusMask(Column[0].x, SMALL_PILLAR_DEPTH, columnSmall_plus_mask, 0); 142 | sprites.drawPlusMask(Column[1].x, SMALL_PILLAR_DEPTH, columnSmall_plus_mask, 0); 143 | sprites.drawPlusMask(Column[2].x, BIG_PILLAR_DEPTH, columnBig_plus_mask, 0); 144 | sprites.drawPlusMask(Column[2].x + 8, BIG_PILLAR_DEPTH, columnSmall_plus_mask, 0); 145 | } 146 | } 147 | 148 | 149 | void drawPowerUP() 150 | { 151 | if (powerUP.isActive && powerUP.isVisible) sprites.drawPlusMask(powerUP.x, powerUP.y, powerUP_plus_mask, powerUP.type); 152 | } 153 | 154 | 155 | 156 | void drawBonus() 157 | { 158 | for (byte i = 0; i < 2; i++) 159 | { 160 | if (bonus[i].isActive && bonus[i].isVisible) 161 | { 162 | char buf[10]; 163 | ltoa(bonus[i].amount, buf, 10); 164 | char charLen = strlen(buf); 165 | 166 | sprites.drawSelfMasked(bonus[i].x, bonus[i].y, numbersSmall, 10); 167 | 168 | for (byte k = 0; k < charLen; k++) 169 | { 170 | char digit = buf[k]; 171 | byte j; 172 | if (digit <= 48) 173 | { 174 | digit = 0; 175 | } 176 | else { 177 | digit -= 48; 178 | if (digit > 9) digit = 0; 179 | } 180 | 181 | for (byte z = 0; z < 10; z++) 182 | { 183 | if (digit == z) j = z; 184 | } 185 | sprites.drawSelfMasked(bonus[i].x + 4 + (5 * k), bonus[i].y, numbersSmall, digit); 186 | } 187 | } 188 | } 189 | } 190 | 191 | 192 | #endif 193 | -------------------------------------------------------------------------------- /examples/ESP8266_Sirene/game.h: -------------------------------------------------------------------------------- 1 | #ifndef GAME_H 2 | #define GAME_H 3 | 4 | #include 5 | #include "globals.h" 6 | #include "inputs.h" 7 | #include "player.h" 8 | #include "enemies.h" 9 | #include "elements.h" 10 | #include "stages.h" 11 | 12 | boolean objectVisible; 13 | 14 | void stateMenuPlay() 15 | { 16 | stage = STAGE_TO_START_WITH - 1; 17 | scorePlayer = 0; 18 | setWeapons(); 19 | setEnemies(); 20 | setMermaid(); 21 | setBosses(); 22 | gameOverAndStageFase = 0; 23 | globalCounter = 0; 24 | leftX = -32; 25 | rightX = 148; 26 | gameState = STATE_GAME_NEXT_STAGE; 27 | }; 28 | 29 | void start() 30 | { 31 | if (gameState == STATE_GAME_OVER) objectVisible = false; 32 | else objectVisible = true; 33 | gameOverAndStageFase++; 34 | } 35 | 36 | void slideToMiddle() 37 | { 38 | byte amount; 39 | if (gameState == STATE_GAME_NEXT_STAGE) amount = 39; 40 | else amount = 31; 41 | if (leftX < amount) 42 | { 43 | leftX += 4; 44 | rightX -= 4; 45 | } 46 | else gameOverAndStageFase++; 47 | } 48 | 49 | void slideOpen() 50 | { 51 | byte amount; 52 | if (gameState == STATE_GAME_NEXT_STAGE) amount = 39; 53 | else amount = 31; 54 | if (leftX > amount) 55 | { 56 | leftX -= 4; 57 | rightX += 4; 58 | } 59 | else gameOverAndStageFase++; 60 | } 61 | 62 | void nextstageFlicker() 63 | { 64 | objectVisible = !objectVisible; 65 | wait(); 66 | } 67 | 68 | 69 | void nextstageEnd() 70 | { 71 | gameState = STATE_GAME_PLAYING; 72 | gameOverAndStageFase = 0; 73 | stage++; 74 | leftX = -32; 75 | rightX = 148; 76 | mermaid.isImune = true; 77 | mermaid.hasShield = false; 78 | objectVisible = false; 79 | setBackground(); 80 | } 81 | 82 | typedef void (*FunctionPointer) (); 83 | const FunctionPointer PROGMEM nextstageFases[] = 84 | { 85 | start, 86 | wait, 87 | slideToMiddle, 88 | slideOpen, 89 | slideToMiddle, 90 | wait, 91 | nextstageFlicker, 92 | nextstageEnd, 93 | }; 94 | 95 | 96 | void stateGameNextStage() 97 | { 98 | checkMermaid(); 99 | drawMermaid(); 100 | currentWave = 0; 101 | previousWave = 255; 102 | bitClear(endBoss.characteristics,4); 103 | if (objectVisible) 104 | { 105 | sprites.drawSelfMasked(leftX, 28, textStage, 0); 106 | sprites.drawSelfMasked(rightX, 28, numbersBig, stage + 1); 107 | } 108 | ((FunctionPointer) pgm_read_dword (&nextstageFases[gameOverAndStageFase]))(); 109 | }; 110 | 111 | 112 | void stateGamePlaying() 113 | { 114 | checkCollisions(); 115 | checkInputs(); 116 | checkWeapons(); 117 | checkMermaid(); 118 | checkEnemyBullet(); 119 | checkEnemies(); 120 | checkEndBoss(); 121 | checkBackground(); 122 | checkPowerUP(); 123 | checkBonus(); 124 | 125 | if (arduboy.everyXFrames(2)) ((FunctionPointer) pgm_read_dword (&stages[stage - 1][currentWave]))(); 126 | 127 | drawBackground(); 128 | drawBosses(); 129 | drawEnemies(); 130 | drawEnemyBullet(); 131 | drawMermaid(); 132 | drawWeapons(); 133 | drawPowerUP(); 134 | drawBonus(); 135 | drawLifeHUD(); 136 | drawScore(SCORE_SMALL_FONT); 137 | }; 138 | 139 | void stateGamePause() 140 | { 141 | sprites.drawSelfMasked(47, 24, textPause, 0); 142 | if (arduboy.justPressed(A_BUTTON)) gameState = STATE_GAME_PLAYING; 143 | }; 144 | 145 | void gameOverShowHighScore() 146 | { 147 | objectVisible = true; 148 | gameOverAndStageFase++; 149 | } 150 | 151 | 152 | void gameOverEnd() 153 | { 154 | if (arduboy.justPressed(A_BUTTON | B_BUTTON)) 155 | { 156 | gameState = STATE_MENU_MAIN; 157 | gameOverAndStageFase = 0; 158 | } 159 | } 160 | 161 | typedef void (*FunctionPointer) (); 162 | const FunctionPointer PROGMEM gameOverFases[] = 163 | { 164 | start, 165 | slideToMiddle, 166 | slideOpen, 167 | slideToMiddle, 168 | wait, 169 | gameOverShowHighScore, 170 | wait, 171 | gameOverEnd, 172 | }; 173 | 174 | 175 | void stateGameOver() 176 | { 177 | ((FunctionPointer) pgm_read_dword (&gameOverFases[gameOverAndStageFase]))(); 178 | sprites.drawSelfMasked(leftX, 16, textGame, 0); 179 | sprites.drawSelfMasked(rightX, 16, textOver, 0); 180 | if (objectVisible) { 181 | sprites.drawSelfMasked(35, 28, textHighscore, 0); 182 | drawScore(SCORE_BIG_FONT); 183 | } 184 | }; 185 | 186 | typedef void (*FunctionPointer) (); 187 | const FunctionPointer PROGMEM gameEndFases[] = 188 | { 189 | start, 190 | wait, 191 | wait, 192 | gameOverEnd, 193 | }; 194 | 195 | void stateGameEnded() 196 | { 197 | ((FunctionPointer) pgm_read_dword (&gameEndFases[gameOverAndStageFase]))(); 198 | if (objectVisible) { 199 | checkMermaid(); 200 | drawMermaid(); 201 | sprites.drawSelfMasked(35, 28, textHighscore, 0); 202 | sprites.drawSelfMasked(41, 16, textTheEnd, 0); 203 | drawScore(SCORE_BIG_FONT); 204 | } 205 | } 206 | 207 | #endif 208 | -------------------------------------------------------------------------------- /EEPROM.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | EEPROM.cpp - esp8266 EEPROM emulation 3 | 4 | Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. 5 | This file is part of the esp8266 core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | #include "Arduino.h" 23 | #include "EEPROM.h" 24 | #include "debug.h" 25 | 26 | extern "C" { 27 | #include "c_types.h" 28 | #include "ets_sys.h" 29 | #include "os_type.h" 30 | #include "osapi.h" 31 | #include "spi_flash.h" 32 | } 33 | 34 | extern "C" uint32_t _EEPROM_start; 35 | 36 | EEPROMClass::EEPROMClass(uint32_t sector) 37 | : _sector(sector) 38 | , _data(0) 39 | , _size(0) 40 | , _dirty(false) 41 | { 42 | } 43 | 44 | EEPROMClass::EEPROMClass(void) 45 | : _sector((((uint32_t)&_EEPROM_start - 0x40200000) / SPI_FLASH_SEC_SIZE)) 46 | , _data(0) 47 | , _size(0) 48 | , _dirty(false) 49 | { 50 | } 51 | 52 | void EEPROMClass::begin(size_t size) { 53 | if (size <= 0) { 54 | DEBUGV("EEPROMClass::begin error, size == 0\n"); 55 | return; 56 | } 57 | if (size > SPI_FLASH_SEC_SIZE) { 58 | DEBUGV("EEPROMClass::begin error, %d > %d\n", size, SPI_FLASH_SEC_SIZE); 59 | size = SPI_FLASH_SEC_SIZE; 60 | } 61 | 62 | size = (size + 3) & (~3); 63 | 64 | //In case begin() is called a 2nd+ time, don't reallocate if size is the same 65 | if(_data && size != _size) { 66 | delete[] _data; 67 | _data = new uint8_t[size]; 68 | } else if(!_data) { 69 | _data = new uint8_t[size]; 70 | } 71 | 72 | _size = size; 73 | 74 | if (!ESP.flashRead(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast(_data), _size)) { 75 | DEBUGV("EEPROMClass::begin flash read failed\n"); 76 | } 77 | 78 | _dirty = false; //make sure dirty is cleared in case begin() is called 2nd+ time 79 | } 80 | 81 | void EEPROMClass::end() { 82 | if (!_size) 83 | return; 84 | 85 | commit(); 86 | if(_data) { 87 | delete[] _data; 88 | } 89 | _data = 0; 90 | _size = 0; 91 | _dirty = false; 92 | } 93 | 94 | 95 | uint8_t EEPROMClass::read(int const address) { 96 | if (address < 0 || (size_t)address >= _size) { 97 | DEBUGV("EEPROMClass::read error, address %d > %d or %d < 0\n", address, _size, address); 98 | return 0; 99 | } 100 | if (!_data) { 101 | DEBUGV("EEPROMClass::read without ::begin\n"); 102 | return 0; 103 | } 104 | 105 | return _data[address]; 106 | } 107 | 108 | void EEPROMClass::write(int const address, uint8_t const value) { 109 | if (address < 0 || (size_t)address >= _size) { 110 | DEBUGV("EEPROMClass::write error, address %d > %d or %d < 0\n", address, _size, address); 111 | return; 112 | } 113 | if(!_data) { 114 | DEBUGV("EEPROMClass::read without ::begin\n"); 115 | return; 116 | } 117 | 118 | // Optimise _dirty. Only flagged if data written is different. 119 | uint8_t* pData = &_data[address]; 120 | if (*pData != value) 121 | { 122 | *pData = value; 123 | _dirty = true; 124 | } 125 | } 126 | 127 | 128 | void EEPROMClass::update(int const address, uint8_t const value) { 129 | if (address < 0 || (size_t)address >= _size) 130 | return; 131 | if(!_data) 132 | return; 133 | 134 | // get data from eeprom 135 | uint8_t storedData = read(address); 136 | 137 | // check if the same 138 | if (storedData == value) 139 | return; 140 | 141 | // call of write() because it is different 142 | write(address, value); 143 | } 144 | 145 | bool EEPROMClass::commit() { 146 | if (!_size) 147 | return false; 148 | if(!_dirty) 149 | return true; 150 | if(!_data) 151 | return false; 152 | 153 | if (ESP.flashEraseSector(_sector)) { 154 | if (ESP.flashWrite(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast(_data), _size)) { 155 | _dirty = false; 156 | return true; 157 | } 158 | } 159 | 160 | DEBUGV("EEPROMClass::commit failed\n"); 161 | return false; 162 | } 163 | 164 | uint8_t * EEPROMClass::getDataPtr() { 165 | _dirty = true; 166 | return &_data[0]; 167 | } 168 | 169 | uint8_t const * EEPROMClass::getConstDataPtr() const { 170 | return &_data[0]; 171 | } 172 | 173 | #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_EEPROM) 174 | EEPROMClass EEPROM; 175 | #endif 176 | -------------------------------------------------------------------------------- /examples/ESP8266_Mystic_Balloon/globals.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOBALS_H 2 | #define GLOBALS_H 3 | 4 | /*-----------------------------* 5 | To turn on hard mode 6 | uncomment the below define. 7 | 8 | Hard mode makes it so you 9 | start each level without 10 | recovering balloons. 11 | ----------------------------*/ 12 | //#define HARD_MODE 13 | 14 | #include 15 | #include 16 | // #include 17 | #include "vec2.h" 18 | #include "bitmaps.h" 19 | 20 | // EEPROM - change this address offset from the arduboy starting address if desired 21 | #define OFFSET_MYBL_START (EEPROM_STORAGE_SPACE_START + 51) 22 | #define OFFSET_LEVEL (OFFSET_MYBL_START + sizeof(byte)) 23 | #define OFFSET_COINS (OFFSET_LEVEL + sizeof(byte)) 24 | #define OFFSET_COINSHS (OFFSET_COINS + sizeof(byte)) 25 | #define OFFSET_SCORE (OFFSET_COINSHS + sizeof(byte)) 26 | #define OFFSET_HSCORE (OFFSET_SCORE + sizeof(unsigned long)) 27 | #define OFFSET_MYBL_END (OFFSET_HSCORE + sizeof(unsigned long)) 28 | 29 | //define menu states (on main menu) 30 | #define STATE_MENU_INTRO 0 31 | #define STATE_MENU_MAIN 1 32 | #define STATE_MENU_HELP 2 33 | #define STATE_MENU_PLAY 3 34 | #define STATE_MENU_INFO 4 35 | #define STATE_MENU_SOUNDFX 5 36 | 37 | //define game states (on main menu) 38 | #define STATE_GAME_NEXT_LEVEL 6 39 | #define STATE_GAME_PLAYING 7 40 | #define STATE_GAME_PAUSE 8 41 | #define STATE_GAME_OVER 9 42 | #define STATE_GAME_PLAYCONTNEW 10 // 11 43 | 44 | #define FACING_RIGHT 0 45 | #define FACING_LEFT 1 46 | 47 | #define LEVEL_TO_START_WITH 1 48 | #define TOTAL_LEVELS 39 49 | #define TOTAL_COINS TOTAL_LEVELS * 6 50 | 51 | #define MAX_PER_TYPE 6 // total instances per enemy type 52 | 53 | #define LEVEL_WIDTH 384 // 24 * 16 54 | #define LEVEL_HEIGHT 384 // 24 * 16 55 | #define LEVEL_CELLSIZE 16 56 | #define LEVEL_WIDTH_CELLS 24 57 | #define LEVEL_HEIGHT_CELLS 24 58 | #define LEVEL_CELL_BYTES (LEVEL_WIDTH_CELLS * LEVEL_HEIGHT_CELLS) >> 3 59 | #define LEVEL_ARRAY_SIZE 576 60 | 61 | #define PLAYER_JUMP_TIME 11 62 | 63 | // This is a replacement for struct Rect in the Arduboy2 library. 64 | // It defines height as an int instead of a uint8_t to allow a higher rectangle. 65 | struct HighRect 66 | { 67 | public: 68 | int x; 69 | int y; 70 | uint16_t width; 71 | int height; 72 | }; 73 | 74 | Arduboy2Base arduboy; 75 | Sprites sprites; 76 | // ArduboyTones sound(arduboy.audio.enabled); 77 | BeepPin1 beep; 78 | 79 | void sound(byte tone, byte duration) { 80 | if (arduboy.audio.enabled()) { 81 | beep.tone(beep.freq(tone), duration /7 ); 82 | } 83 | } 84 | 85 | 86 | byte gameState = STATE_MENU_INTRO; // start the game with the TEAM a.r.g. logo 87 | byte menuSelection = STATE_MENU_PLAY; // PLAY menu item is pre-selected 88 | byte globalCounter = 0; 89 | byte level; 90 | unsigned long scorePlayer; 91 | byte coinsCollected = 0; 92 | byte totalCoins = 0; 93 | byte balloonsLeft; 94 | 95 | boolean nextLevelIsVisible; 96 | boolean scoreIsVisible; 97 | boolean canPressButton; 98 | boolean pressKeyIsVisible; 99 | 100 | byte walkerFrame = 0; 101 | byte fanFrame = 0; 102 | byte coinFrame = 0; 103 | byte coinsActive = 0; 104 | vec2 levelExit = vec2(0, 0); 105 | vec2 startPos; 106 | byte mapTimer = 10; 107 | 108 | void loadSetEEPROM() 109 | { 110 | EEPROM.begin(100); 111 | if ((EEPROM.read(OFFSET_MYBL_START) != GAME_ID) && (EEPROM.read(OFFSET_MYBL_END) != GAME_ID)) 112 | { 113 | EEPROM.put(OFFSET_MYBL_START, (byte)GAME_ID); // game id 114 | EEPROM.put(OFFSET_LEVEL, (byte)LEVEL_TO_START_WITH - 1); // beginning level 115 | EEPROM.put(OFFSET_COINS, (byte)0); // coins current run 116 | EEPROM.put(OFFSET_COINSHS, (byte)0); // coins highscore run 117 | EEPROM.put(OFFSET_SCORE, (unsigned long)0); // clear score 118 | EEPROM.put(OFFSET_HSCORE, (unsigned long)0); // clear high score 119 | EEPROM.put(OFFSET_MYBL_END, (byte)GAME_ID); // game id 120 | EEPROM.commit(); 121 | } 122 | } 123 | 124 | // This is a replacement for the collide() function in the Arduboy2 library. 125 | // It uses struct HighRect instead of the struct Rect in the library. 126 | bool collide(HighRect rect1, HighRect rect2) 127 | { 128 | return !( rect2.x >= rect1.x + rect1.width || 129 | rect2.x + rect2.width <= rect1.x || 130 | rect2.y >= rect1.y + rect1.height || 131 | rect2.y + rect2.height <= rect1.y); 132 | } 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /src/EEPROM.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | EEPROM.cpp - esp8266 EEPROM emulation 3 | 4 | Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. 5 | This file is part of the esp8266 core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | #include "Arduino.h" 23 | #include "EEPROM.h" 24 | #include "debug.h" 25 | 26 | extern "C" { 27 | #include "c_types.h" 28 | #include "ets_sys.h" 29 | #include "os_type.h" 30 | #include "osapi.h" 31 | #include "spi_flash.h" 32 | } 33 | 34 | extern "C" uint32_t _EEPROM_start; 35 | 36 | EEPROMClass::EEPROMClass(uint32_t sector) 37 | : _sector(sector) 38 | , _data(0) 39 | , _size(0) 40 | , _dirty(false) 41 | { 42 | } 43 | 44 | EEPROMClass::EEPROMClass(void) 45 | : _sector((((uint32_t)&_EEPROM_start - 0x40200000) / SPI_FLASH_SEC_SIZE)) 46 | , _data(0) 47 | , _size(0) 48 | , _dirty(false) 49 | { 50 | } 51 | 52 | void EEPROMClass::begin(size_t size) { 53 | if (size <= 0) { 54 | DEBUGV("EEPROMClass::begin error, size == 0\n"); 55 | return; 56 | } 57 | if (size > SPI_FLASH_SEC_SIZE) { 58 | DEBUGV("EEPROMClass::begin error, %d > %d\n", size, SPI_FLASH_SEC_SIZE); 59 | size = SPI_FLASH_SEC_SIZE; 60 | } 61 | 62 | size = (size + 3) & (~3); 63 | 64 | //In case begin() is called a 2nd+ time, don't reallocate if size is the same 65 | if(_data && size != _size) { 66 | delete[] _data; 67 | _data = new uint8_t[size]; 68 | } else if(!_data) { 69 | _data = new uint8_t[size]; 70 | } 71 | 72 | _size = size; 73 | 74 | if (!ESP.flashRead(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast(_data), _size)) { 75 | DEBUGV("EEPROMClass::begin flash read failed\n"); 76 | } 77 | 78 | _dirty = false; //make sure dirty is cleared in case begin() is called 2nd+ time 79 | } 80 | 81 | void EEPROMClass::end() { 82 | if (!_size) 83 | return; 84 | 85 | commit(); 86 | if(_data) { 87 | delete[] _data; 88 | } 89 | _data = 0; 90 | _size = 0; 91 | _dirty = false; 92 | } 93 | 94 | 95 | uint8_t EEPROMClass::read(int const address) { 96 | if (address < 0 || (size_t)address >= _size) { 97 | DEBUGV("EEPROMClass::read error, address %d > %d or %d < 0\n", address, _size, address); 98 | return 0; 99 | } 100 | if (!_data) { 101 | DEBUGV("EEPROMClass::read without ::begin\n"); 102 | return 0; 103 | } 104 | 105 | return _data[address]; 106 | } 107 | 108 | void EEPROMClass::write(int const address, uint8_t const value) { 109 | if (address < 0 || (size_t)address >= _size) { 110 | DEBUGV("EEPROMClass::write error, address %d > %d or %d < 0\n", address, _size, address); 111 | return; 112 | } 113 | if(!_data) { 114 | DEBUGV("EEPROMClass::read without ::begin\n"); 115 | return; 116 | } 117 | 118 | // Optimise _dirty. Only flagged if data written is different. 119 | uint8_t* pData = &_data[address]; 120 | if (*pData != value) 121 | { 122 | *pData = value; 123 | _dirty = true; 124 | } 125 | } 126 | 127 | 128 | void EEPROMClass::update(int const address, uint8_t const value) { 129 | if (address < 0 || (size_t)address >= _size) 130 | return; 131 | if(!_data) 132 | return; 133 | 134 | // get data from eeprom 135 | uint8_t storedData = read(address); 136 | 137 | // check if the same 138 | if (storedData == value) 139 | return; 140 | 141 | // call of write() because it is different 142 | write(address, value); 143 | } 144 | 145 | bool EEPROMClass::commit() { 146 | if (!_size) 147 | return false; 148 | if(!_dirty) 149 | return true; 150 | if(!_data) 151 | return false; 152 | 153 | if (ESP.flashEraseSector(_sector)) { 154 | if (ESP.flashWrite(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast(_data), _size)) { 155 | _dirty = false; 156 | return true; 157 | } 158 | } 159 | 160 | DEBUGV("EEPROMClass::commit failed\n"); 161 | return false; 162 | } 163 | 164 | uint8_t * EEPROMClass::getDataPtr() { 165 | _dirty = true; 166 | return &_data[0]; 167 | } 168 | 169 | uint8_t const * EEPROMClass::getConstDataPtr() const { 170 | return &_data[0]; 171 | } 172 | 173 | #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_EEPROM) 174 | EEPROMClass EEPROM; 175 | #endif 176 | -------------------------------------------------------------------------------- /examples/ESP8266_Mystic_Balloon/game.h: -------------------------------------------------------------------------------- 1 | #ifndef GAME_H 2 | #define GAME_H 3 | 4 | #include 5 | #include "globals.h" 6 | #include "inputs.h" 7 | #include "player.h" 8 | #include "enemies.h" 9 | #include "elements.h" 10 | #include "levels.h" 11 | 12 | #define TOTAL_TONES 10 13 | PROGMEM const byte tones[] = { 14 | //200, 100, 250, 125, 300, 150, 350, 400, 425, 475 15 | 131, 145, 139, 152, 131, 172, 200, 188, 213, 255 16 | }; 17 | 18 | byte toneindex = 0; 19 | 20 | void stateMenuPlayNew() 21 | { 22 | level = LEVEL_TO_START_WITH - 1; 23 | coinsCollected = 0; 24 | totalCoins = 0; 25 | balloonsLeft = 0; 26 | scorePlayer = 0; 27 | globalCounter = 0; 28 | kid.balloons = 3; 29 | gameState = STATE_GAME_NEXT_LEVEL; 30 | scoreIsVisible = false; 31 | nextLevelIsVisible = true; 32 | pressKeyIsVisible = false; 33 | } 34 | 35 | void stateMenuPlayContinue() 36 | { 37 | level = EEPROM.read(OFFSET_LEVEL); 38 | totalCoins = EEPROM.read(OFFSET_COINS); 39 | coinsCollected = 0; 40 | balloonsLeft = 0; 41 | //scorePlayer = 0; 42 | EEPROM.get(OFFSET_SCORE, scorePlayer); 43 | globalCounter = 0; 44 | kid.balloons = 3; 45 | gameState = STATE_GAME_NEXT_LEVEL; 46 | scoreIsVisible = false; 47 | nextLevelIsVisible = true; 48 | pressKeyIsVisible = false; 49 | } 50 | 51 | 52 | void stateGameNextLevel() 53 | { 54 | //if (level < TOTAL_LEVELS) 55 | //{ 56 | if (arduboy.everyXFrames(20)) 57 | { 58 | canPressButton = false; 59 | if (coinsCollected > 0) 60 | { 61 | coinsCollected--; 62 | scorePlayer += 20; 63 | sound(pgm_read_byte(tones + toneindex++), 150); 64 | } 65 | else if (balloonsLeft > 0) 66 | { 67 | balloonsLeft--; 68 | scorePlayer += 30; 69 | sound(pgm_read_byte(tones + toneindex++), 150); 70 | } 71 | else 72 | { 73 | canPressButton = true; 74 | scoreIsVisible = false; 75 | pressKeyIsVisible = !pressKeyIsVisible; 76 | if (toneindex < TOTAL_TONES) 77 | { 78 | sound(pgm_read_byte(tones + toneindex++), 200); 79 | toneindex = TOTAL_TONES; 80 | } 81 | if (level >= TOTAL_LEVELS) 82 | gameState = STATE_GAME_OVER; 83 | } 84 | } 85 | /*} 86 | else 87 | { 88 | gameState = STATE_GAME_OVER; 89 | return; 90 | }*/ 91 | 92 | // Update EEPROM 93 | EEPROM.put(OFFSET_LEVEL, level); 94 | EEPROM.put(OFFSET_COINS, totalCoins); 95 | EEPROM.put(OFFSET_SCORE, scorePlayer); 96 | 97 | 98 | //if (nextLevelIsVisible) 99 | //{ 100 | if (level < TOTAL_LEVELS) 101 | { 102 | sprites.drawSelfMasked(35, 4, badgeNextLevel, 0); 103 | drawNumbers(78, 13, FONT_BIG, DATA_LEVEL); 104 | } 105 | else 106 | { 107 | EEPROM.put(OFFSET_LEVEL, (byte)LEVEL_TO_START_WITH - 1); 108 | // Score remains after completing game? (no) 109 | EEPROM.put(OFFSET_SCORE, (unsigned long)0); 110 | } 111 | drawNumbers(43, 49, FONT_BIG, DATA_SCORE); 112 | //} 113 | 114 | EEPROM.commit(); 115 | 116 | if (scoreIsVisible) 117 | { 118 | byte totalBadges = coinsCollected + balloonsLeft; 119 | 120 | for (byte i = 0; i < totalBadges; ++i) 121 | { 122 | if (i < coinsCollected) sprites.drawOverwrite(65 - (7 * totalBadges) + (i * 14), 27, badgeElements, 0); 123 | else sprites.drawOverwrite(65 - (7 * totalBadges) + (i * 14), 27, badgeElements, 1); 124 | } 125 | } 126 | 127 | if (canPressButton) 128 | { 129 | 130 | if (pressKeyIsVisible) sprites.drawOverwrite(38, 29, badgePressKey, 0); 131 | if (arduboy.justPressed(A_BUTTON | B_BUTTON)) 132 | { 133 | toneindex = 0; 134 | sound(425, 20); 135 | setKid(); 136 | //cam.pos = vec2(0, 0); 137 | cam.pos = vec2(0, LEVEL_HEIGHT - 64); 138 | cam.offset = vec2(0, 0); 139 | enemiesInit(); 140 | levelLoad(levels[level]); 141 | gameState = STATE_GAME_PLAYING; 142 | } 143 | } 144 | }; 145 | 146 | 147 | void stateGamePlaying() 148 | { 149 | checkInputs(); 150 | checkKid(); 151 | updateCamera(); 152 | 153 | drawGrid(); 154 | enemiesUpdate(); 155 | 156 | drawKid(); 157 | drawHUD(); 158 | 159 | checkCollisions(); 160 | } 161 | 162 | 163 | void stateGamePause() 164 | { 165 | sprites.drawSelfMasked(47, 17, badgePause, 0); 166 | if (arduboy.justPressed(A_BUTTON | B_BUTTON)) 167 | { 168 | gameState = STATE_GAME_PLAYING; 169 | } 170 | } 171 | 172 | 173 | void stateGameOver() 174 | { 175 | byte x = 35 + 12; 176 | if (level < TOTAL_LEVELS) 177 | { 178 | drawNumbers(78, 26, FONT_BIG, DATA_LEVEL); 179 | x -= 12; 180 | } 181 | sprites.drawSelfMasked(x, 17, badgeGameOver, 0); 182 | drawNumbers(43, 49, FONT_BIG, DATA_SCORE); 183 | 184 | unsigned long highscore = 0; 185 | EEPROM.get(OFFSET_HSCORE, highscore); 186 | if (scorePlayer > highscore) { 187 | EEPROM.put(OFFSET_COINSHS, totalCoins); 188 | EEPROM.put(OFFSET_HSCORE, scorePlayer); 189 | EEPROM.commit(); 190 | } 191 | 192 | if (arduboy.justPressed(A_BUTTON | B_BUTTON)) 193 | { 194 | gameState = STATE_MENU_MAIN; 195 | } 196 | } 197 | 198 | #endif 199 | -------------------------------------------------------------------------------- /src/Arduboy2Audio.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Arduboy2Audio.h 3 | * \brief 4 | * The Arduboy2Audio class for speaker and sound control. 5 | */ 6 | 7 | #ifndef ARDUBOY2_AUDIO_H 8 | #define ARDUBOY2_AUDIO_H 9 | 10 | #include 11 | #include 12 | 13 | /** \brief 14 | * Provide speaker and sound control. 15 | * 16 | * \details 17 | * This class provides functions to initialize the speaker and control the 18 | * enabling and disabling (muting) of sound. It doesn't provide any functions 19 | * to actually produce sound. 20 | * 21 | * The state of sound muting is stored in system EEPROM and so is retained 22 | * over power cycles. 23 | * 24 | * An Arduboy2Audio class object named `audio` will be created by the 25 | * Arduboy2Base class, so there is no need for a sketch itself to create an 26 | * Arduboy2Audio object. Arduboy2Audio functions can be called using the 27 | * Arduboy2 or Arduboy2Base `audio` object. 28 | * 29 | * Example: 30 | * 31 | * \code{.cpp} 32 | * #include 33 | * 34 | * Arduboy2 arduboy; 35 | * 36 | * // Arduboy2Audio functions can be called as follows: 37 | * arduboy.audio.on(); 38 | * arduboy.audio.off(); 39 | * \endcode 40 | * 41 | * \note 42 | * \parblock 43 | * In order for this class to be fully functional, the external library or 44 | * functions used by a sketch to actually to produce sounds should be compliant 45 | * with this class. This means they should only produce sound if it is enabled, 46 | * or mute the sound if it's disabled. The `enabled()` function can be used 47 | * to determine if sound is enabled or muted. Generally a compliant library 48 | * would accept the `enabled()` function as an initialization parameter and 49 | * then call it as necessary to determine the current state. 50 | * 51 | * For example, the ArduboyTones and ArduboyPlaytune libraries require an 52 | * `enabled()` type function to be passed as a parameter in the constructor, 53 | * like so: 54 | * 55 | * \code{.cpp} 56 | * #include 57 | * #include 58 | * 59 | * Arduboy2 arduboy; 60 | * ArduboyTones sound(arduboy.audio.enabled); 61 | * \endcode 62 | * \endparblock 63 | * 64 | * \note 65 | * \parblock 66 | * A friend class named _Arduboy2Ex_ is declared by this class. The intention 67 | * is to allow a sketch to create an _Arduboy2Ex_ class which would have access 68 | * to the private and protected members of the Arduboy2Audio class. It is hoped 69 | * that this may eliminate the need to create an entire local copy of the 70 | * library, in order to extend the functionality, in most circumstances. 71 | * \endparblock 72 | */ 73 | class Arduboy2Audio 74 | { 75 | friend class Arduboy2Ex; 76 | 77 | public: 78 | /** \brief 79 | * Initialize the speaker based on the current mute setting. 80 | * 81 | * \details 82 | * The speaker is initialized based on the current mute setting saved in 83 | * system EEPROM. This function is called by `Arduboy2Base::begin()` so it 84 | * isn't normally required to call it within a sketch. However, if 85 | * `Arduboy2Core::boot()` is used instead of `Arduboy2Base::begin()` and the 86 | * sketch includes sound, then this function should be called after `boot()`. 87 | */ 88 | void static begin(); 89 | 90 | /** \brief 91 | * Turn sound on. 92 | * 93 | * \details 94 | * The system is configured to generate sound. This function sets the sound 95 | * mode only until the unit is powered off. To save the current mode use 96 | * `saveOnOff()`. 97 | * 98 | * \see off() toggle() saveOnOff() 99 | */ 100 | void static on(); 101 | 102 | /** \brief 103 | * Turn sound off (mute). 104 | * 105 | * \details 106 | * The system is configured to not produce sound (mute). This function sets 107 | * the sound mode only until the unit is powered off. To save the current 108 | * mode use `saveOnOff()`. 109 | * 110 | * \see on() toggle() saveOnOff() 111 | */ 112 | void static off(); 113 | 114 | /** \brief 115 | * Toggle the sound on/off state. 116 | * 117 | * \details 118 | * If the system is configured for sound on, it will be changed to sound off 119 | * (mute). If sound is off, it will be changed to on. This function sets 120 | * the sound mode only until the unit is powered off. To save the current 121 | * mode use `saveOnOff()`. 122 | * 123 | * \see on() off() saveOnOff() 124 | */ 125 | void static toggle(); 126 | 127 | /** \brief 128 | * Save the current sound state in EEPROM. 129 | * 130 | * \details 131 | * The current sound state, set by `on()` or `off()`, is saved to the 132 | * reserved system area in EEPROM. This allows the state to carry over between 133 | * power cycles and after uploading a different sketch. 134 | * 135 | * \note 136 | * EEPROM is limited in the number of times it can be written to. Sketches 137 | * should not continuously change and then save the state rapidly. 138 | * 139 | * \see on() off() toggle() 140 | */ 141 | void static saveOnOff(); 142 | 143 | /** \brief 144 | * Get the current sound state. 145 | * 146 | * \return `true` if sound is currently enabled (not muted). 147 | * 148 | * \details 149 | * This function should be used by code that actually generates sound. 150 | * If `true` is returned, sound can be produced. If `false` is returned, 151 | * sound should be muted. 152 | * 153 | * \see on() off() toggle() 154 | */ 155 | bool static enabled(); 156 | 157 | protected: 158 | bool static audio_enabled; 159 | }; 160 | 161 | #endif 162 | -------------------------------------------------------------------------------- /src/SpritesB.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file SpritesB.cpp 3 | * \brief 4 | * A class for drawing animated sprites from image and mask bitmaps. 5 | * Optimized for small code size. 6 | */ 7 | 8 | #include "SpritesB.h" 9 | 10 | void SpritesB::drawExternalMask(int16_t x, int16_t y, const uint8_t *bitmap, 11 | const uint8_t *mask, uint8_t frame, uint8_t mask_frame) 12 | { 13 | draw(x, y, bitmap, frame, mask, mask_frame, SPRITE_MASKED); 14 | } 15 | 16 | void SpritesB::drawOverwrite(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame) 17 | { 18 | draw(x, y, bitmap, frame, NULL, 0, SPRITE_OVERWRITE); 19 | } 20 | 21 | void SpritesB::drawErase(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame) 22 | { 23 | draw(x, y, bitmap, frame, NULL, 0, SPRITE_IS_MASK_ERASE); 24 | } 25 | 26 | void SpritesB::drawSelfMasked(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame) 27 | { 28 | draw(x, y, bitmap, frame, NULL, 0, SPRITE_IS_MASK); 29 | } 30 | 31 | void SpritesB::drawPlusMask(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame) 32 | { 33 | draw(x, y, bitmap, frame, NULL, 0, SPRITE_PLUS_MASK); 34 | } 35 | 36 | 37 | //common functions 38 | void SpritesB::draw(int16_t x, int16_t y, 39 | const uint8_t *bitmap, uint8_t frame, 40 | const uint8_t *mask, uint8_t sprite_frame, 41 | uint8_t drawMode) 42 | { 43 | unsigned int frame_offset; 44 | 45 | if (bitmap == NULL) 46 | return; 47 | 48 | uint8_t width = pgm_read_byte(bitmap); 49 | uint8_t height = pgm_read_byte(++bitmap); 50 | bitmap++; 51 | if (frame > 0 || sprite_frame > 0) { 52 | frame_offset = (width * ( height / 8 + ( height % 8 == 0 ? 0 : 1))); 53 | // sprite plus mask uses twice as much space for each frame 54 | if (drawMode == SPRITE_PLUS_MASK) { 55 | frame_offset *= 2; 56 | } else if (mask != NULL) { 57 | mask += sprite_frame * frame_offset; 58 | } 59 | bitmap += frame * frame_offset; 60 | } 61 | 62 | // if we're detecting the draw mode then base it on whether a mask 63 | // was passed as a separate object 64 | if (drawMode == SPRITE_AUTO_MODE) { 65 | drawMode = mask == NULL ? SPRITE_UNMASKED : SPRITE_MASKED; 66 | } 67 | 68 | drawBitmap(x, y, bitmap, mask, width, height, drawMode); 69 | } 70 | 71 | void SpritesB::drawBitmap(int16_t x, int16_t y, 72 | const uint8_t *bitmap, const uint8_t *mask, 73 | uint8_t w, uint8_t h, uint8_t draw_mode) 74 | { 75 | // no need to draw at all of we're offscreen 76 | if (x + w <= 0 || x > WIDTH - 1 || y + h <= 0 || y > HEIGHT - 1) 77 | return; 78 | 79 | if (bitmap == NULL) 80 | return; 81 | 82 | // xOffset technically doesn't need to be 16 bit but the math operations 83 | // are measurably faster if it is 84 | uint16_t xOffset, ofs; 85 | int8_t yOffset = y & 7; 86 | int8_t sRow = y / 8; 87 | uint8_t loop_h, start_h, rendered_width; 88 | 89 | if (y < 0 && yOffset > 0) { 90 | sRow--; 91 | } 92 | 93 | // if the left side of the render is offscreen skip those loops 94 | if (x < 0) { 95 | xOffset = abs(x); 96 | } else { 97 | xOffset = 0; 98 | } 99 | 100 | // if the right side of the render is offscreen skip those loops 101 | if (x + w > WIDTH - 1) { 102 | rendered_width = ((WIDTH - x) - xOffset); 103 | } else { 104 | rendered_width = (w - xOffset); 105 | } 106 | 107 | // if the top side of the render is offscreen skip those loops 108 | if (sRow < -1) { 109 | start_h = abs(sRow) - 1; 110 | } else { 111 | start_h = 0; 112 | } 113 | 114 | loop_h = h / 8 + (h % 8 > 0 ? 1 : 0); // divide, then round up 115 | 116 | // if (sRow + loop_h - 1 > (HEIGHT/8)-1) 117 | if (sRow + loop_h > (HEIGHT / 8)) { 118 | loop_h = (HEIGHT / 8) - sRow; 119 | } 120 | 121 | // prepare variables for loops later so we can compare with 0 122 | // instead of comparing two variables 123 | loop_h -= start_h; 124 | 125 | sRow += start_h; 126 | ofs = (sRow * WIDTH) + x + xOffset; 127 | 128 | uint8_t mul_amt = 1 << yOffset; 129 | uint16_t mask_data; 130 | uint16_t bitmap_data; 131 | 132 | const uint8_t ofs_step = draw_mode == SPRITE_PLUS_MASK ? 2 : 1; 133 | const uint8_t ofs_stride = (w - rendered_width)*ofs_step; 134 | const uint16_t initial_bofs = ((start_h * w) + xOffset)*ofs_step; 135 | 136 | const uint8_t *bofs = bitmap + initial_bofs; 137 | const uint8_t *mask_ofs = !mask ? bitmap : mask; 138 | mask_ofs += initial_bofs + ofs_step - 1; 139 | 140 | for (uint8_t a = 0; a < loop_h; a++) { 141 | for (uint8_t iCol = 0; iCol < rendered_width; iCol++) { 142 | uint8_t data; 143 | 144 | bitmap_data = pgm_read_byte(bofs) * mul_amt; 145 | mask_data = ~bitmap_data; 146 | 147 | if (draw_mode == SPRITE_UNMASKED) { 148 | mask_data = ~(0xFF * mul_amt); 149 | } else if (draw_mode == SPRITE_IS_MASK_ERASE) { 150 | bitmap_data = 0; 151 | } else { 152 | mask_data = ~(pgm_read_byte(mask_ofs) * mul_amt); 153 | } 154 | 155 | if (sRow >= 0) { 156 | data = Arduboy2Base::sBuffer[ofs]; 157 | data &= (uint8_t)(mask_data); 158 | data |= (uint8_t)(bitmap_data); 159 | Arduboy2Base::sBuffer[ofs] = data; 160 | } 161 | if (yOffset != 0 && sRow < 7) { 162 | data = Arduboy2Base::sBuffer[ofs + WIDTH]; 163 | data &= (*((unsigned char *) (&mask_data) + 1)); 164 | data |= (*((unsigned char *) (&bitmap_data) + 1)); 165 | Arduboy2Base::sBuffer[ofs + WIDTH] = data; 166 | } 167 | ofs++; 168 | mask_ofs += ofs_step; 169 | bofs += ofs_step; 170 | } 171 | sRow++; 172 | bofs += ofs_stride; 173 | mask_ofs += ofs_stride; 174 | ofs += WIDTH - rendered_width; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /examples/ESP8266_ShadowRunner/playfield.h: -------------------------------------------------------------------------------- 1 | #ifndef PLAYFIELD_H 2 | #define PLAYFIELD_H 3 | 4 | #include 5 | #include "globals.h" 6 | #include "runner.h" 7 | #include "items.h" 8 | 9 | int background1step = 0; 10 | int background2step = 128; 11 | byte background1id = 0; 12 | byte background2id = 1; 13 | int fence1step = 0; 14 | int fence2step = 128; 15 | byte fence1id = 0; 16 | byte fence2id = 1; 17 | int forgroundstep = 128; 18 | byte forgroundid = 0; 19 | 20 | 21 | void drawScore(int scoreX, int scoreY) 22 | { 23 | sprites.drawSelfMasked(scoreX, scoreY, score, 0); 24 | char buf[8]; 25 | ltoa(scorePlayer, buf, 10); // Numerical base used to represent the value as a string, between 2 and 36, where 10 means decimal base 26 | char charLen = strlen(buf); 27 | char pad = 8 - charLen; 28 | 29 | //draw 0 padding 30 | for (byte i = 0; i < pad; i++) 31 | { 32 | sprites.drawSelfMasked(scoreX + 28 + (5 * i), scoreY + 1, numbers, 0); 33 | } 34 | 35 | for (byte i = 0; i < charLen; i++) 36 | { 37 | char digit = buf[i]; 38 | byte j; 39 | if (digit <= 48) 40 | { 41 | digit = 0; 42 | } 43 | else { 44 | digit -= 48; 45 | if (digit > 9) digit = 0; 46 | } 47 | 48 | for (byte z = 0; z < 10; z++) 49 | { 50 | if (digit == z) j = z; 51 | } 52 | sprites.drawSelfMasked(scoreX + 28 + (pad * 5) + (5 * i), scoreY + 1, numbers, digit); 53 | } 54 | } 55 | 56 | void drawBackGround() 57 | { 58 | if (arduboy.everyXFrames(3)) 59 | { 60 | background1step -= 1; 61 | background2step -= 1; 62 | } 63 | if (background1step < -127) 64 | { 65 | background1step = 128; 66 | background1id = random(0, 2); 67 | } 68 | if (background2step < -127) 69 | { 70 | background2step = 128; 71 | background2id = random(1, 5); 72 | } 73 | sprites.drawSelfMasked(background1step, 0, backGrounds, 2 * background1id); 74 | sprites.drawSelfMasked(background1step + 64, 0, backGrounds, (2 * background1id) + 1); 75 | sprites.drawSelfMasked(background2step, 0, backGrounds, 2 * background2id); 76 | sprites.drawSelfMasked(background2step + 64, 0, backGrounds, 2 * (background2id) + 1); 77 | } 78 | 79 | void drawFence() 80 | { 81 | if (arduboy.everyXFrames(1)) 82 | { 83 | fence1step -= 1; 84 | fence2step -= 1; 85 | } 86 | sprites.drawPlusMask(fence1step, 36, fences_plus_mask, 2 * fence1id); 87 | sprites.drawPlusMask(fence1step + 64, 36, fences_plus_mask, (2 * fence1id) + 1); 88 | sprites.drawPlusMask(fence2step, 36, fences_plus_mask, 2 * fence2id); 89 | sprites.drawPlusMask(fence2step + 64, 36, fences_plus_mask, (2 * fence2id) + 1); 90 | if (fence1step < -127) 91 | { 92 | fence1step = 128; 93 | fence1id = random(0, 3); 94 | } 95 | if (fence2step < -127) 96 | { 97 | fence2step = 128; 98 | fence2id = random(2, 5); 99 | } 100 | } 101 | 102 | void drawForGround() 103 | { 104 | if (forgroundstep == 128) forgroundid = random(0, 3); 105 | sprites.drawErase(forgroundstep, -4, forgroundTrees, forgroundid); 106 | if (arduboy.everyXFrames(2)) 107 | { 108 | forgroundstep -= 4; 109 | } 110 | if (forgroundstep < -255) forgroundstep = 128; 111 | } 112 | 113 | void drawScoreAndLive() 114 | { 115 | if (arduboy.everyXFrames(16 - 2 * level)) 116 | { 117 | lifePlayer--; 118 | } 119 | if (lifePlayer < 64) 120 | { 121 | showitems = showitems | B00100000; 122 | } 123 | sprites.drawSelfMasked(2, 52, life, 0); 124 | for (byte i = 0; i < lifePlayer + 1; i++) sprites.drawSelfMasked(i, 61, lifeBar, 0); 125 | drawScore(59, 52); 126 | } 127 | 128 | void checkScoreAndLevel() 129 | { 130 | if (nextLevelAt < scorePlayer) 131 | { 132 | level += 1; 133 | nextLevelAt += 1000; 134 | if (level > 7) level = 7; 135 | } 136 | scorePlayer++; 137 | } 138 | 139 | void checkInputs() 140 | { 141 | if (arduboy.justPressed(B_BUTTON)) 142 | { 143 | if (!jumping) 144 | { 145 | jumping = true; 146 | runnerFrame = RUNNER_JUMPING; 147 | } 148 | } 149 | else if (arduboy.justPressed(A_BUTTON | LEFT_BUTTON)) 150 | { 151 | if (!ducking && !jumping) 152 | { 153 | ducking = true; 154 | runnerFrame = RUNNER_DUCKING; 155 | } 156 | } 157 | else if (arduboy.justPressed(UP_BUTTON | DOWN_BUTTON | RIGHT_BUTTON)) gameState = STATE_GAME_PAUSE; 158 | } 159 | 160 | void checkCollisions() 161 | { 162 | Rect runnerRect = {.x = runnerX + 8, .y = runnerY + 2, .width = 10, .height = 20}; 163 | 164 | Rect stoneOneRect = {.x = itemX[ITEM_STONE_ONE] + 2, .y = STONES_Y + 4, .width = 11, .height = 12}; 165 | Rect stoneTwoRect = {.x = itemX[ITEM_STONE_TWO] + 2, .y = STONES_Y + 4, .width = 11, .height = 12}; 166 | Rect birdOneRect = {.x = itemX[ITEM_BIRD_ONE] + 2, .y = BIRDS_Y + 4, .width = 12, .height = 20}; 167 | Rect birdTwoRect = {.x = itemX[ITEM_BIRD_TWO] + 2, .y = BIRDS_Y + 4, .width = 12, .height = 20}; 168 | Rect extraLifeRect = {.x = itemX[ITEM_EXTRA_LIFE] + 2, .y = HEART_Y + 2, .width = 12, .height = 12}; 169 | 170 | if ((showitems & B00000001) && arduboy.collide(runnerRect, stoneOneRect)) 171 | { 172 | lifePlayer -= 4; 173 | sound(175, 1); 174 | } 175 | 176 | if ((showitems & B00000010) && arduboy.collide(runnerRect, stoneTwoRect)) 177 | { 178 | lifePlayer -= 4; 179 | sound(175, 1); 180 | } 181 | 182 | if ((showitems & B00000100) && arduboy.collide(runnerRect, birdOneRect)) 183 | { 184 | lifePlayer -= 2; 185 | sound(523, 1); 186 | } 187 | 188 | if ((showitems & B00001000) && arduboy.collide(runnerRect, birdTwoRect)) 189 | { 190 | lifePlayer -= 2; 191 | sound(523, 1); 192 | } 193 | 194 | if ((showitems & B00100000) && arduboy.collide(runnerRect, extraLifeRect)) 195 | { 196 | showitems ^= B00100000; 197 | itemX[ITEM_EXTRA_LIFE] = 128; 198 | lifePlayer = 128; 199 | scorePlayer += 500; 200 | sound(750, 1); 201 | } 202 | } 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | \page licenses Software License Agreements 3 | \verbatim 4 | 5 | Software License Agreements 6 | 7 | ------------------------------------------------------------------------------- 8 | Licensed under the BSD 3-clause license: 9 | 10 | Arduboy2 library: 11 | Copyright (c) 2016-2018, Scott Allen 12 | All rights reserved. 13 | 14 | The Arduboy2 library was forked from the Arduboy library: 15 | https://github.com/Arduboy/Arduboy 16 | Copyright (c) 2016, Kevin "Arduboy" Bates 17 | Copyright (c) 2016, Chris Martinez 18 | Copyright (c) 2016, Josh Goebel 19 | Copyright (c) 2016, Scott Allen 20 | All rights reserved. 21 | which is in turn partially based on the Adafruit_SSD1306 library 22 | https://github.com/adafruit/Adafruit_SSD1306 23 | Copyright (c) 2012, Adafruit Industries 24 | All rights reserved. 25 | 26 | SetSystemEEPROM example sketch: 27 | Copyright (c) 2018, Scott Allen 28 | All rights reserved. 29 | 30 | Redistribution and use in source and binary forms, with or without 31 | modification, are permitted provided that the following conditions are met: 32 | 1. Redistributions of source code must retain the above copyright 33 | notice, this list of conditions and the following disclaimer. 34 | 2. Redistributions in binary form must reproduce the above copyright 35 | notice, this list of conditions and the following disclaimer in the 36 | documentation and/or other materials provided with the distribution. 37 | 3. Neither the name of the copyright holders nor the 38 | names of its contributors may be used to endorse or promote products 39 | derived from this software without specific prior written permission. 40 | 41 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 42 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 43 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 44 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 45 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 46 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 48 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 50 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 | 52 | ------------------------------------------------------------------------------- 53 | Licensed under the BSD 2-clause license: 54 | 55 | Portions of the Arduboy library, and thus portions of the Arduboy2 library, 56 | based on the Adafruit-GFX library: 57 | https://github.com/adafruit/Adafruit-GFX-Library 58 | Copyright (c) 2012 Adafruit Industries 59 | All rights reserved. 60 | 61 | Redistribution and use in source and binary forms, with or without 62 | modification, are permitted provided that the following conditions are met: 63 | 64 | - Redistributions of source code must retain the above copyright notice, 65 | this list of conditions and the following disclaimer. 66 | - Redistributions in binary form must reproduce the above copyright notice, 67 | this list of conditions and the following disclaimer in the documentation 68 | and/or other materials provided with the distribution. 69 | 70 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 71 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 72 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 73 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 74 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 75 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 76 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 77 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 78 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 79 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 80 | POSSIBILITY OF SUCH DAMAGE. 81 | 82 | ------------------------------------------------------------------------------- 83 | Licensed under the MIT license: 84 | 85 | Code from ArduboyExtra: 86 | https://github.com/yyyc514/ArduboyExtra 87 | Copyright (c) 2015 Josh Goebel 88 | 89 | Code for drawing compressed bitmaps: 90 | https://github.com/TEAMarg/drawCompressed 91 | Copyright (c) 2016 TEAM a.r.g. 92 | 93 | Permission is hereby granted, free of charge, to any person obtaining a copy 94 | of this software and associated documentation files (the "Software"), to deal 95 | in the Software without restriction, including without limitation the rights 96 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 97 | copies of the Software, and to permit persons to whom the Software is 98 | furnished to do so, subject to the following conditions: 99 | 100 | The above copyright notice and this permission notice shall be included in all 101 | copies or substantial portions of the Software. 102 | 103 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 104 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 105 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 106 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 107 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 108 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 109 | SOFTWARE. 110 | 111 | ------------------------------------------------------------------------------- 112 | Licensed under the GNU LGPL license: 113 | https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html 114 | 115 | ArduBreakout example sketch: 116 | Original work: 117 | Copyright (c) 2011 Sebastian Goscik 118 | All rights reserved. 119 | Modified work: 120 | Copyright (c) 2016 Scott Allen 121 | All rights reserved. 122 | 123 | Buttons and HelloWorld example sketches: 124 | Copyright (c) 2015 David Martinez 125 | All rights reserved. 126 | 127 | This work is free software; you can redistribute it and/or 128 | modify it under the terms of the GNU Lesser General Public 129 | License as published by the Free Software Foundation; either 130 | version 2.1 of the License, or (at your option) any later version. 131 | 132 | This library is distributed in the hope that it will be useful, 133 | but WITHOUT ANY WARRANTY; without even the implied warranty of 134 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 135 | Lesser General Public License for more details. 136 | 137 | ------------------------------------------------------------------------------- 138 | Placed in the public domain: 139 | 140 | BeepDemo example sketch: 141 | By Scott Allen 142 | 143 | RGBled example sketch: 144 | By Scott Allen 145 | 146 | =============================================================================== 147 | \endverbatim 148 | */ 149 | -------------------------------------------------------------------------------- /examples/ESP8266_evade/enemy.h: -------------------------------------------------------------------------------- 1 | #ifndef ENEMY_H 2 | #define ENEMY_H 3 | 4 | /* 5 | * File: enemy.h 6 | * Purpose: Deals with regular and boss enemies for Evade game. 7 | * Author: Modus Create 8 | */ 9 | 10 | #include "globals.h" 11 | #include "bitmaps.h" 12 | #include "bullet.h" 13 | 14 | struct Enemy { 15 | byte x, 16 | y, 17 | width, 18 | height, 19 | type, 20 | difficulty, 21 | dying, 22 | // isMovingLeft (0), isMovingDown (1), tookDamage (2) 23 | options; 24 | int health, 25 | animFrame; 26 | const uint8_t *bitmap; 27 | unsigned long damageFrame; 28 | Bullet bullets[MAX_BOSS_BULLETS]; 29 | 30 | // Initialize the enemy, uses currentIteration to increase difficulty 31 | // and make enemies stronger. 32 | void set(byte _x, byte _y, byte _type, byte currentIteration) { 33 | x = _x; 34 | y = _y; 35 | type = _type; 36 | dying = 0; 37 | 38 | // Hide all bullets 39 | for (byte i = 0; i < MAX_BOSS_BULLETS; i++) { 40 | bullets[i].hide(); 41 | } 42 | 43 | // Randomize direction 44 | if (random(2)) { 45 | options ^= 1 << 0; 46 | } 47 | if (random(2)) { 48 | options ^= 1 << 1; 49 | } 50 | 51 | width = 16; 52 | height = 16; 53 | difficulty = 4; 54 | 55 | if (type < 5) { 56 | difficulty = (currentIteration == 0 ? 1: 2); 57 | bitmap = enemy1; 58 | health = 25; 59 | } else if (type < 9) { 60 | difficulty = 2; 61 | bitmap = enemy2; 62 | health = 150 + (currentIteration * B_BULLET_DAMAGE); 63 | } else if (type == 9) { 64 | bitmap = enemy3; 65 | health = 500 + (currentIteration * A_BULLET_DAMAGE); 66 | } else if (type == 128) { 67 | bitmap = boss1; 68 | health = 1000 + (currentIteration * 500); 69 | width = 32; 70 | } else if (type == 129) { 71 | bitmap = boss2; 72 | health = 2000 + (currentIteration * 1000); 73 | width = 32; 74 | } else if (type == 130) { 75 | bitmap = boss3; 76 | health = 3000 + (currentIteration * 3000); 77 | width = 59; 78 | height = 53; 79 | } 80 | 81 | draw(); 82 | } 83 | 84 | // Update enemy determine if it is dying, or a new enemy needs to take 85 | // its place unless we are in a phase where new enemies are not allowed 86 | // to spawn. 87 | void update(bool stopSpawningEnemies, byte currentIteration) { 88 | if ((inGameFrame > (damageFrame + 4)) 89 | && (isTakingDamage()) 90 | && (inGameFrame % 4)) { 91 | options &= ~(1 << 2); 92 | } 93 | 94 | if (isAlive()) { 95 | move(); 96 | if (!isTakingDamage()) { 97 | draw(); 98 | } 99 | } else if (dying > 0) { 100 | updateDeathSequence(); 101 | } else if ((type <= 9) && (! stopSpawningEnemies) && (random(600) == 0)) { 102 | spawn(currentIteration); 103 | } 104 | 105 | if ((type <= 9) 106 | || ((type == 128) && (x == MIN_ENEMY_SHIP_X)) 107 | || ((type == 129) && (x <= 110)) 108 | || ((type == 130) && (x == 69))) { 109 | 110 | for (byte i = 0; i < MAX_BOSS_BULLETS; i++) { 111 | if (!bullets[i].isVisible()) { 112 | fire(i, currentIteration); 113 | } else { 114 | bullets[i].update(); 115 | } 116 | } 117 | } 118 | } 119 | 120 | // Spawn new enemy, uses currentIteration to determine enemy health 121 | // and bullet speed. 122 | void spawn(byte currentIteration) { 123 | byte enemyX = random(MIN_ENEMY_SHIP_X, MAX_ENEMY_SHIP_X), 124 | enemyY = random(MIN_PLAYER_Y, MAX_PLAYER_Y); 125 | set(enemyX, enemyY, random(10), currentIteration); 126 | } 127 | 128 | // Update enemy position on screen. 129 | void move() { 130 | if ((random(10 / difficulty) == 0) || (type > 9)) { 131 | changeDirection(); 132 | 133 | bool typeIs128 = (type == 128), 134 | typeIs129 = (type == 129); 135 | 136 | if (typeIs128 && x > MIN_ENEMY_SHIP_X) { 137 | if (inGameFrame % 4 == 0) { 138 | x--; 139 | } 140 | } else if (typeIs129 && x > 110) { 141 | if (inGameFrame % 3 == 0) { 142 | x--; 143 | } 144 | } else if ((type == 130) && x > 69) { 145 | if (inGameFrame % 5 == 0) { 146 | x--; 147 | } 148 | } else if ((type <= 9) 149 | || ((typeIs128 || typeIs129) && (random(3) == 0))) { 150 | 151 | byte newX = x + (isMovingLeft() ? -1 : 1); 152 | byte newY = y + (isMovingDown() ? -1 : 1); 153 | 154 | if (((type <= 9) && (newX >= MIN_ENEMY_SHIP_X) && (newX <= MAX_ENEMY_SHIP_X)) 155 | || ((type == 129) && (newX >= 97) && (newX <= 109))) { 156 | x = newX; 157 | } 158 | 159 | bool newShipYisGreater = newY >= MIN_PLAYER_Y; 160 | if (((type <= 9) && newShipYisGreater && (newY <= MAX_PLAYER_Y)) 161 | || (((type == 128) || (type == 129)) && newShipYisGreater && (newY <= (MAX_PLAYER_Y + 16 - height)))) { 162 | y = newY; 163 | } 164 | } 165 | } 166 | } 167 | 168 | // Render the enemy on the screen, uses different bitmaps depending 169 | // on enemy type. 170 | void draw() { 171 | if (type != 129) { 172 | drawBitmap(x, y, bitmap, 0); 173 | } else { 174 | if (inGameFrame % 13 == 0) { 175 | animFrame++; 176 | } 177 | drawBitmap(x, y, bitmap, animFrame); 178 | if (animFrame > 2) { 179 | animFrame = 0; 180 | } 181 | } 182 | } 183 | 184 | 185 | 186 | // If the enemy is dying, update the dying effect for the current frame, 187 | // reset when effect completed. 188 | void updateDeathSequence() { 189 | if (dying < 30) { 190 | dying++; 191 | 192 | explode(x + width / 2,y + height / 2,dying); 193 | } else { 194 | // Fully dead, reset it so it can respawn 195 | dying = 0; 196 | } 197 | } 198 | 199 | // Switch enemy movement direction somewhat randomly. 200 | void changeDirection() { 201 | if (((type <= 9) && (random(30) == 0)) 202 | || ((type > 9) && (random(50) == 0))) { 203 | options ^= 1 << 0; 204 | } 205 | 206 | if (((type <= 9) && (random(10) == 0)) 207 | || ((type == 128) && (random(50) == 0)) 208 | || ((type == 129) && (random(20) == 0))) { 209 | options ^= 1 << 1; 210 | } 211 | } 212 | 213 | // Determine whether to fire enemy bullet, configures bullet 214 | // based on type of enemy firing it. 215 | void fire(byte bulletIndex, byte currentIteration) { 216 | if (isAlive() && inGameFrame > 120) { 217 | byte newY = (y + (height / 2) - 1); 218 | 219 | if (type <= 9) { 220 | if ((bulletIndex == 0) 221 | && (!bullets[bulletIndex].isVisible()) 222 | && (random(1000 / difficulty) == 0)) { 223 | bullets[bulletIndex].set(x, newY, false, 1, getBulletSpeed(0.8, currentIteration), false); 224 | } 225 | } else if (type == 128) { 226 | bullets[bulletIndex].set(x, newY, false, 1, getBulletSpeed(0.7, currentIteration), false); 227 | } else if ((type == 129) && (inGameFrame % 50 == 0) && (random(2) == 0)) { 228 | if (random(4) == 0) { 229 | bullets[bulletIndex].set((x - 10), newY, false, 1, getBulletSpeed(1.0, currentIteration), true); 230 | } else { 231 | bullets[bulletIndex].set(x, newY, false, 1, getBulletSpeed(0.9, currentIteration), false); 232 | } 233 | } else if (type == 130) { 234 | bullets[bulletIndex].set(x, random(MIN_PLAYER_Y, (MAX_PLAYER_Y + 8)), false, 1, getBulletSpeed(0.8, currentIteration), false); 235 | } 236 | } 237 | } 238 | 239 | // Calculate the speed for a new bullet, gets harder as currentIteration 240 | // increases. 241 | float getBulletSpeed(float initialSpeed, byte currentIteration) { 242 | if (currentIteration > 0 && (initialSpeed + (0.1f * currentIteration) > 1.5)) { 243 | return 1.5f; 244 | } 245 | 246 | return (initialSpeed + (0.1f * (currentIteration - 1))); 247 | } 248 | 249 | // Work out if taking damage. 250 | void takeDamage() { 251 | options |= 1 << 2; 252 | damageFrame = inGameFrame; 253 | } 254 | 255 | // Is the enemy alive (has health and is not in the dying sequence). 256 | bool isAlive() { 257 | return ((health > 0) && (dying == 0)); 258 | } 259 | 260 | // Is the enemy moving to the left? 261 | bool isMovingLeft() { 262 | return (options & (1 << 0)); 263 | } 264 | 265 | // Is the enemy moving to the bottom of the screen? 266 | bool isMovingDown() { 267 | return (options & (1 << 1)); 268 | } 269 | 270 | // Is the enemy able to take damage (not dying etc)? 271 | bool isTakingDamage() { 272 | return (options & (1 << 2)); 273 | } 274 | }; 275 | 276 | #endif 277 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2019 Aug 20 cheungbx 2 | 3 | Many people have discussed and shared videos running Arduboy games on ESP8266. However, I have not seen any source codes shared by anyone for games running on a ESP8266 with working Aruboy2 library that support push buttons. Hence I try to make one myself and share it. 4 | Here is my youtube video that demonstrate the games that are working so far. 5 | 6 | https://youtu.be/CinJb7gifH8 7 | 8 | [![ESP8266%20Arduboy%20Video](https://github.com/cheungbx/esp8266_arduboy2/blob/master/ESP8266%20Arduboy%20Video.jpg)](https://youtu.be/CinJb7gifH8) 9 | 10 | 11 | ESP8266 has pros and cons as a portable game console compared to the original Arduboy using ATmega32U4 (Pro Micro). 12 | 13 | con 14 | === 15 | - heavy power consumption, will only run for 1-2 hours max on a tiny LIPO battery. 16 | - limited GPIO pins hence cannot support other features in the original Arduboy, e.g. RGB LED, two audio output pins. 17 | - due to the above, restricted to using I2C for OLED display which may slow down some complex games 18 | - sound support is minimal, only through the beeping function. 19 | - support on background music and other sound related library that require timer interrupts is a challenge. I have not see a working library that support this yet. 20 | 21 | Pro 22 | === 23 | + faster CPU 80Mh/160Mhz may compensate for some of the slowless mentioned above except for the limitation of I2C speed. 24 | + A big memory. Comes with 4MB, and can be upgraded to 16MB using the same memory chip that @Mr.Blinky used for the flash cart. This allow for more complex games, and also storing of games on the memory (there is a file system for ESP called SPIFFS that is a simplified version of SD CARD file system with only one flat directory, no subdirectory) 25 | + WIFI capable, opens up possibility for online games, posting of top scores from individual players to the web dashboard for competition, download and refresh of games directly from a web site, like that of an Android playstore. 26 | + Simpler wiring if you use the Node MCU D1 mini to make the board. 27 | + Cheaper overall cost. 28 | 29 | Arduboy2 library for ESP8266 with push button supports I2C OLED and single pin sound 30 | ===================================================================================== 31 | 32 | Thanks to hartmann1301 who created the Arduboy2 library based on the Arduboy2 library for the Slim boy version of Arduboy that runs on the Adruino Nano and I2C OLED dipslay. This ARduboy2 library for ESP8266 allow Arduboy games to be run on ESP8266 with a slower I2C SSD1306 OLED and an external button function for PS2 joysticks. refer to https://github.com/hartmann1301/Arduboy2 33 | 34 | However, I found that library not supporting push buttons for ESP8266 directly. The game need to be programmed with extra external functions to read the push buttons. This add extra efforts to port Arduboy games over to an ESP8266 Arduboy. 35 | 36 | I modified that a bit to define the mapping of GPIO push buttons for ESP8266, and codes to read these buttons. 37 | As ESP8266 has limited pins, so I have to use both the GPIO 0 and RX for A and B buttons. 38 | Hence make sure you do not accidentally push these two buttons when you are flashing the firmware. 39 | Otherwise, the flash may fail and you may need to redo the flash again. 40 | 41 | Here is the link to my github 42 | * https://github.com/cheungbx/esp8266_arduboy2 43 | 44 | As the ESP8266 already have 4MB memory, it should be able to hold many games on the go and self-flash it using a boot loader like what @Mr.Blinky did for the original Arduboy flash cartridge. 45 | I know ESP8266 can be partitioned into two parts and self-flash over the air (OTA) to the second partition that is not actively running a program. Then switch over to boot and run from the second partition. 46 | But my programming skill is not at that level yet. So, do not know how to do that. 47 | 48 | Appreciate help from anyone who's doing something similar. 49 | 50 | Here are the list of the original Arduboy games that have been successfully ported to ESP8266 Arduboy/ The source code files modified for ESP8266_Arduboy can be found in the examples folder of this library with original licensing comments are kept in the modified source codes. Credits to the original creators of these Arduboy games. 51 | 52 | TESTED on ESP8266 Arduboy 53 | ========================= 54 | * evade - no background music 55 | * ArduBOYING 56 | * ArduBreakout 57 | * breakout-v 58 | * Sirene 59 | * Mystic Balloon 60 | * PicoVaders (space invader) 61 | * Shadow Runner 62 | 63 | Here are the pins used and wiring diagram. I am using a Node MCI D1 Mini on a bread board and then created a perf board version. Next, I I will try to build a tiny one using a mini-joystick (as small as button) and the bare ESP12E module. Programming will be done through a ESP_USB programmer. 64 | 65 | 66 | ![ESP8266%20Arduboy](https://github.com/cheungbx/esp8266_arduboy2/blob/master/ESP8266%20Arduboy.jpg) 67 | 68 | PARTS 69 | ======== 70 | *NODE MCU Mini D1 (ESP8266) 71 | 72 | * if you want to build a custom design board that is super small, you can use the ESP8266 12E module directly, and get a USB_to_ESP programmer board to program it. 73 | * The ESP8266 12E is a bare board and you need to tie certain pins to ground and other pins to VCC to make it run firmware, or put it in the a programming mode. Make the following permanent connections to put the ESP8266 12E at the normal firmware running mode. Then leave the rest to the USB_to_ESP programmer to flip the EN, Reset and GPIO 0 pins to the right level to put it at a firmware programming mode. 74 | 75 | * Connect the following pins to their own 1K resistors then to VCC (3.3V) : 76 | * D3 (GPIO 0) 77 | * Reset 78 | * EN (chip enable) 79 | * Connect the following pins to their own 1K resistors then to GND : 80 | * D8 (GPIO15) 81 | ![ESP12E$20Mini%20Arduboy](https://github.com/cheungbx/esp8266_arduboy2/blob/master/ESP12E%20Arduboy%20.jpg) 82 | 83 | 84 | *I2C SSD1306 OLED 128x64 85 | 86 | *six push buttons 87 | 88 | *extra push button for rest (for perf board version only) 89 | 90 | *power on/off switch (or perf board version only) 91 | 92 | *3.7V LIPO Battery 93 | 94 | *Perf Board or breadboard 95 | 96 | *Wires 97 | 98 | *Pins for buttons 99 | 100 | *GPIO13 D7—— Rightbutton----- .GND 101 | 102 | *GPIO12 D6—— Left button----- .GND 103 | 104 | *GPIO14 D5—— UP button----- .GND 105 | 106 | *GPIO2 D4—— Down button----- .GND 107 | 108 | *GPIO0 D3—— A button----- .GND // ** WARNING ** DO NOT press this button when flashing firmware. 109 | 110 | *GPIO16 D0—— B button----- .GND // ** Tie the ther end of this button through a 10K resistor to VCC, 111 | * as it cannot be pulled high by software. 112 | 113 | *A0 Paddle --- connect to middle pin of 10K VR, connect left pin to VCC, right pin to Ground 114 | 115 | *GPIO15 D8——Piezo Speaker/headphone--GND 116 | 117 | *ESP8266 i2c SSD1306 Oled 118 | 119 | *============================= 120 | 121 | *3.3V ------------VCC 122 | 123 | *GND -------------GND 124 | 125 | *GPIO5 D1 --------SCL 126 | 127 | *GPIO4 D2—--------SDA 128 | 129 | * Extra Libraries required to work with the ESP8266_Arduboy2 library: 130 | 131 | * https://github.com/ThingPulse/esp8266-oled-ssd1306 version 4.0.0 132 | 133 | * Brzo I2C library to drive SSD 1306 display at the max. I2C. speed. 134 | 135 | * https://github.com/pasko-zh/brzo_i2c 136 | 137 | Simple Steps to convert Arduboy games to run on ESP8266 Arduboy. 138 | ======================================================================= 139 | * change "#include arduboy.h" to "#include arduboy2.h" 140 | * add "BeepPin1 beep;" 141 | * add "sound() function" 142 | * use the ArduboyTones library for ESP8266 from ESPBOY (https://github.com/ESPboy-edu/ESPboy_Arduboy2_lib/tree/master/libs). 143 | * some games use a function pointer arrary instead of a switch function to pass control to different part of the codes as the game state changes. In ATMEGA32U4 the memory address are 2 bytes (single word) long, in ESP8266, the memory addresses are 4 bytyes ( doube word) long, So you need to 144 | change all "pgm_read_word" to "pgm_read_dword" 145 | * if EEPROM is used by the game to keep configs/high scores, 146 | * refer to the notes in my github EEPROMnotes.txt on how to add the eeprom.update function to your eeprom library in the ESP8266 library for your adruino ide. 147 | 148 | * add EEPROM.begin(1000) at setup() // 1000 is just a rough max no. need to check the size 149 | * add EEPROM.commit() after the last EEPROM.put(), EEPORM.write() and EEPROM.update() of each blocks of code. 150 | 151 | Caveats 152 | =============== 153 | 154 | * remove any reference to the ATMlib for complex sound output 155 | * games that directly control the SPI bus to write to OLED display need much more work to port instead of the simple steps above. 156 | -------------------------------------------------------------------------------- /examples/ESP8266_Mystic_Balloon/enemies.h: -------------------------------------------------------------------------------- 1 | #ifndef ENEMIES_H 2 | #define ENEMIES_H 3 | 4 | #include 5 | #include "globals.h" 6 | //#include "vec2.h" 7 | 8 | #define MAX_FAN_PARTICLES 4 9 | #define FAN_POWER 5 10 | #define FAN_UP 0 11 | #define FAN_RIGHT 1 12 | #define FAN_LEFT 2 13 | 14 | #define SPIKES_LEFT 0 15 | #define SPIKES_DOWN 1 16 | #define SPIKES_RIGHT 2 17 | #define SPIKES_UP 3 18 | 19 | 20 | struct Coin 21 | { 22 | vec2 pos; 23 | bool active; 24 | }; 25 | 26 | Coin coins[MAX_PER_TYPE]; 27 | 28 | struct Key 29 | { 30 | vec2 pos; 31 | bool active; 32 | bool haveKey; 33 | }; 34 | 35 | Key key = {.pos = vec2(0, 0), .active = false, .haveKey = false}; 36 | 37 | struct Walker 38 | { 39 | vec2 pos; 40 | int8_t direction; 41 | int8_t HP; 42 | bool hurt; 43 | bool active; 44 | }; 45 | 46 | Walker walkers[MAX_PER_TYPE]; 47 | 48 | struct Spike 49 | { 50 | HighRect pos; 51 | byte characteristics;//B00000000; //this byte holds all the enemies characteristics 52 | // |||||||| 53 | // |||||||└-> 0 \ these 2 bits are used to determine the spike type 54 | // ||||||└--> 1 / 55 | // |||||└---> 2 the spike is active (0 = false / 1 = true) 56 | }; 57 | 58 | Spike spikes[MAX_PER_TYPE]; 59 | 60 | struct Fan 61 | { 62 | vec2 pos; 63 | vec2 particles[5]; 64 | int height; 65 | bool active; 66 | uint8_t dir; 67 | }; 68 | 69 | Fan fans[MAX_PER_TYPE]; 70 | 71 | void enemiesInit() 72 | { 73 | coinsActive = 0; 74 | //for (byte i = 0; i < MAX_PER_TYPE; ++i) 75 | for (byte i = MAX_PER_TYPE-1; i < MAX_PER_TYPE; --i) 76 | { 77 | // Fans 78 | fans[i].pos = vec2(0, 0); 79 | for (byte a = 0; a < MAX_FAN_PARTICLES; ++a) 80 | fans[i].particles[a] = vec2(random(16), random(16)); 81 | fans[i].height = 0; 82 | fans[i].active = false; 83 | fans[i].dir = FAN_UP; 84 | 85 | // Spikes 86 | spikes[i].pos.x = 0; 87 | spikes[i].pos.y = 0; 88 | spikes[i].pos.width = 16; 89 | spikes[i].pos.height = 16; 90 | 91 | spikes[i].characteristics = 1; 92 | 93 | // Walkers 94 | walkers[i].pos.x = 0; 95 | walkers[i].pos.y = 0; 96 | walkers[i].active = false; 97 | walkers[i].HP = 30; 98 | walkers[i].direction = 1; 99 | walkers[i].hurt = false; 100 | 101 | // Coins 102 | coins[i].pos.x = 0; 103 | coins[i].pos.y = 0; 104 | coins[i].active = false; 105 | } 106 | } 107 | 108 | void coinsCreate(vec2 pos) 109 | { 110 | //for (byte i = 0; i < MAX_PER_TYPE; ++i) 111 | for (byte i = MAX_PER_TYPE-1; i < MAX_PER_TYPE; --i) 112 | { 113 | if (!coins[i].active) 114 | { 115 | ++coinsActive; 116 | coins[i].pos = pos << 4; 117 | coins[i].pos.x += 2; 118 | coins[i].active = true; 119 | return; 120 | } 121 | } 122 | } 123 | 124 | void keyCreate(vec2 pos) 125 | { 126 | key.pos = pos << 4; 127 | key.active = true; 128 | key.haveKey = false; 129 | } 130 | 131 | void walkersCreate(vec2 pos) 132 | { 133 | for (byte i = 0; i < MAX_PER_TYPE; ++i) 134 | //for (byte i = MAX_PER_TYPE-1; i < MAX_PER_TYPE; --i) 135 | { 136 | if (!walkers[i].active) 137 | { 138 | walkers[i].pos = pos << 4; 139 | walkers[i].pos.y += 8; 140 | walkers[i].active = true; 141 | return; 142 | } 143 | } 144 | } 145 | 146 | void spikesCreate(vec2 pos, byte l) 147 | { 148 | for (byte i = 0; i < MAX_PER_TYPE; ++i) 149 | { 150 | if (!bitRead(spikes[i].characteristics, 2)) 151 | { 152 | int len = 16 * (l + 1); 153 | spikes[i].pos.x = pos.x << 4; 154 | spikes[i].pos.y = pos.y << 4; 155 | // Solid above 156 | if (gridGetSolid(pos.x, pos.y - 1)) 157 | { 158 | spikes[i].characteristics = B00000111; 159 | spikes[i].pos.width = len; 160 | spikes[i].pos.height = 8; 161 | } 162 | // Solid below 163 | else if (gridGetSolid(pos.x, pos.y + 1)) 164 | { 165 | spikes[i].characteristics = B00000101; 166 | spikes[i].pos.width = len; 167 | spikes[i].pos.height = 8; 168 | spikes[i].pos.y += 8; 169 | } 170 | // Solid left 171 | else if (gridGetSolid(pos.x - 1, pos.y)) 172 | { 173 | spikes[i].characteristics = B00000100; 174 | spikes[i].pos.width = 8; 175 | spikes[i].pos.height = len; 176 | } 177 | // Solid right 178 | else if (gridGetSolid(pos.x + 1, pos.y)) 179 | { 180 | spikes[i].characteristics = B00000110; 181 | spikes[i].pos.width = 8; 182 | spikes[i].pos.height = len; 183 | spikes[i].pos.x += 8; 184 | } 185 | return; 186 | } 187 | } 188 | } 189 | 190 | void fansCreate(vec2 pos, byte height, uint8_t dir = FAN_UP) 191 | { 192 | //for (byte i = 0; i < MAX_PER_TYPE; ++i) 193 | for (byte i = MAX_PER_TYPE-1; i < MAX_PER_TYPE; --i) 194 | { 195 | if (!fans[i].active) 196 | { 197 | fans[i].pos = pos << 4; 198 | fans[i].height = height << 4; 199 | fans[i].active = true; 200 | fans[i].dir = dir; 201 | return; 202 | } 203 | } 204 | } 205 | 206 | void enemiesUpdate() 207 | { 208 | if (arduboy.everyXFrames(8)) 209 | { 210 | walkerFrame = (++walkerFrame) % 2; 211 | coinFrame = (++coinFrame) % 4; 212 | } 213 | 214 | if (key.active) 215 | { 216 | int commonx = key.pos.x - cam.pos.x; 217 | int commony = key.pos.y - cam.pos.y; 218 | sprites.drawOverwrite(commonx, commony, elements, 4); 219 | } 220 | 221 | // Draw spikes first 222 | //for (byte i = 0; i < MAX_PER_TYPE; ++i) 223 | for (byte i = MAX_PER_TYPE-1; i < MAX_PER_TYPE; --i) 224 | { 225 | if (bitRead(spikes[i].characteristics, 2)) // spike active 226 | { 227 | int commonx = spikes[i].pos.x - cam.pos.x; 228 | int commony = spikes[i].pos.y - cam.pos.y; 229 | sprites.drawOverwrite(commonx, commony, sprSpikes, spikes[i].characteristics & B00000011); 230 | if (!bitRead(spikes[i].characteristics, 0)) { 231 | for (int l = 8; l < spikes[i].pos.height; l += 8) 232 | sprites.drawOverwrite(commonx, commony + l, sprSpikes, spikes[i].characteristics & B00000011); 233 | } 234 | else { 235 | for (int l = 8; l < spikes[i].pos.width; l += 8) 236 | sprites.drawOverwrite(commonx + l, commony, sprSpikes, spikes[i].characteristics & B00000011); 237 | } 238 | } 239 | } 240 | 241 | if (arduboy.everyXFrames(4)) fanFrame = (++fanFrame) % 3; 242 | for (byte i = 0; i < MAX_PER_TYPE; ++i) 243 | { 244 | // Fans 245 | if (fans[i].active) 246 | { 247 | // Update 248 | if (arduboy.everyXFrames(2)) 249 | for (byte a = 0; a < MAX_FAN_PARTICLES; ++a) 250 | { 251 | // Update Particles 252 | fans[i].particles[a].y = 253 | (fans[i].particles[a].y < (fans[i].height)) ? 254 | fans[i].particles[a].y + 6 : random((fans[i].height) >> 2); 255 | 256 | // Draw particles 257 | switch (fans[i].dir) 258 | { 259 | case FAN_UP: 260 | sprites.drawErase(fans[i].pos.x + fans[i].particles[a].x - cam.pos.x, fans[i].pos.y - fans[i].particles[a].y - cam.pos.y, particle , 0); 261 | break; 262 | case FAN_RIGHT: 263 | sprites.drawErase(fans[i].pos.x + 16 + fans[i].particles[a].y - cam.pos.x, fans[i].pos.y + 16 - fans[i].particles[a].x - cam.pos.y, particle , 0); 264 | break; 265 | default: 266 | sprites.drawErase(fans[i].pos.x - fans[i].particles[a].y - cam.pos.x, fans[i].pos.y + 16 - fans[i].particles[a].x - cam.pos.y, particle , 0); 267 | } 268 | } 269 | 270 | // Draw fan 271 | int _x = fans[i].pos.x - cam.pos.x; 272 | int _y = fans[i].pos.y - cam.pos.y; 273 | uint8_t foff = 3 * fans[i].dir; 274 | //if (fans[i].dir > FAN_UP) foff += 3; 275 | //else if (fans[i].dir > FAN_RIGHT) foff += 6; 276 | sprites.drawOverwrite(_x, _y, fan, fanFrame + foff); 277 | } 278 | 279 | // Walkers 280 | if (walkers[i].active) 281 | { 282 | if (arduboy.everyXFrames(2) && walkers[i].HP > 0 && !walkers[i].hurt) 283 | { 284 | if (!gridGetSolid((walkers[i].pos.x + 4 + (walkers[i].direction * 5)) >> 4, walkers[i].pos.y >> 4) 285 | && gridGetSolid((walkers[i].pos.x + 4 + (walkers[i].direction * 5)) >> 4, (walkers[i].pos.y >> 4) + 1)) 286 | { 287 | walkers[i].pos.x += walkers[i].direction; 288 | } 289 | else 290 | { 291 | walkers[i].direction = -walkers[i].direction; 292 | } 293 | } 294 | 295 | sprites.drawOverwrite(walkers[i].pos.x - cam.pos.x, walkers[i].pos.y - cam.pos.y, walkerSprite, walkerFrame + (walkers[i].HP <= 0) * 2); 296 | } 297 | 298 | // Coins 299 | if (coins[i].active) 300 | { 301 | sprites.drawOverwrite(coins[i].pos.x - cam.pos.x, coins[i].pos.y - cam.pos.y, elements, coinFrame); 302 | } 303 | } 304 | } 305 | 306 | 307 | #endif 308 | -------------------------------------------------------------------------------- /examples/ESP8266_Sirene/player.h: -------------------------------------------------------------------------------- 1 | #ifndef PLAYER_H 2 | #define PLAYER_H 3 | 4 | #include 5 | #include "globals.h" 6 | 7 | #define WEAPON_TYPE_TRIDENT 0 8 | #define WEAPON_TYPE_BUBBLES 1 9 | #define WEAPON_TYPE_SEASHELL 2 10 | #define WEAPON_TYPE_MAGIC 3 11 | 12 | #define SEASHELL_GO_STRAIGHT 0 13 | #define SEASHELL_GO_UP 1 14 | #define SEASHELL_GO_DOWN -1 15 | 16 | #define WEAPON_COOLDOWN_TRIDENT 24 17 | #define WEAPON_COOLDOWN_BUBBLES 8 18 | #define WEAPON_COOLDOWN_SEASHELL 24 19 | #define WEAPON_COOLDOWN_MAGIC 24 20 | 21 | #define DAMAGE_TRIDENT 2 22 | #define DAMAGE_BUBBLES 1 23 | #define DAMAGE_SEASHELL 1 24 | #define DAMAGE_MAGIC 1 //charges up to 4 25 | 26 | #define BULLET_SPEED_TRIDENT 2 27 | #define BULLET_SPEED_BUBBLES 3 28 | #define BULLET_SPEED_SEASHELL 2 29 | #define BULLET_SPEED_MAGIC 3 30 | 31 | #define MAX_ONSCREEN_BULLETS 9 32 | #define MAX_ONSCREEN_SPARKLES 8 33 | #define MAX_ONSCREEN_SHIELDS 2 34 | 35 | #define MERMAID_IMUNE_TIME 30 36 | #define MERMAID_SUPER_TIME 250 37 | 38 | #define MERMAID_COLLISION_OFFSET 2 39 | #define MERMAID_COLLISION_SIZE 12 40 | 41 | #define TRIDENT_COLLISION_OFFSET 6 42 | #define BUBBLES_COLLISION_OFFSET 14 43 | #define SEASHELL_COLLISION_OFFSET 0 44 | #define MAGIC_COLLISION_OFFSET 8 45 | 46 | #define AMOUNT_OF_HEARTS 4 47 | #define MAX_HP_MERMAID AMOUNT_OF_HEARTS + 1 48 | 49 | 50 | int seaShellSpeedY[] = {SEASHELL_GO_STRAIGHT, SEASHELL_GO_UP, SEASHELL_GO_DOWN}; 51 | byte coolDown[] = { WEAPON_COOLDOWN_TRIDENT, WEAPON_COOLDOWN_BUBBLES, WEAPON_COOLDOWN_SEASHELL, WEAPON_COOLDOWN_MAGIC}; 52 | byte coolDownMax[] = { WEAPON_COOLDOWN_TRIDENT, WEAPON_COOLDOWN_BUBBLES, WEAPON_COOLDOWN_SEASHELL, WEAPON_COOLDOWN_MAGIC}; 53 | byte bulletSpeed[] = {BULLET_SPEED_TRIDENT, BULLET_SPEED_BUBBLES, BULLET_SPEED_SEASHELL, BULLET_SPEED_MAGIC}; 54 | byte bulletDamage[] = {DAMAGE_TRIDENT, DAMAGE_BUBBLES, DAMAGE_SEASHELL, DAMAGE_MAGIC}; 55 | byte bulletCollisionOffset[] = {TRIDENT_COLLISION_OFFSET, BUBBLES_COLLISION_OFFSET, SEASHELL_COLLISION_OFFSET, MAGIC_COLLISION_OFFSET}; 56 | const unsigned char PROGMEM shieldX[] = {11, 7, 3, 1, 0, 1, 4, 7, 12, 16, 20, 22, 23, 22, 19, 16}; 57 | const unsigned char PROGMEM shieldY[] = {0, 1, 4, 7, 12, 16, 20, 22, 23, 22, 19, 16, 11, 7, 3, 1}; 58 | 59 | 60 | 61 | //////// define player and weapons ///////// 62 | //////////////////////////////////////////// 63 | 64 | struct Players 65 | { 66 | public: 67 | byte x; 68 | byte y; 69 | byte weaponType; 70 | boolean isVisible; 71 | boolean isImune; 72 | boolean hasShield; 73 | boolean magicCharging; 74 | byte imuneTimer; 75 | byte HP; 76 | byte frame; 77 | byte chargeBarFrame; 78 | byte currentBullet; 79 | byte currentSeaShell; 80 | }; 81 | 82 | Players mermaid; 83 | 84 | struct Bullets 85 | { 86 | public: 87 | byte x; 88 | int y; 89 | byte damage; 90 | boolean isVisible = false; 91 | byte type; 92 | byte frame; 93 | int speedY; 94 | }; 95 | 96 | struct Sparkles 97 | { 98 | public: 99 | int x; 100 | int y; 101 | int speedX; 102 | int speedY; 103 | byte frame; 104 | }; 105 | 106 | 107 | Bullets bullet[MAX_ONSCREEN_BULLETS]; 108 | Sparkles sparkle[MAX_ONSCREEN_SPARKLES]; 109 | 110 | 111 | //////// Player functions ////////////////// 112 | //////////////////////////////////////////// 113 | 114 | void setMermaid() 115 | { 116 | mermaid.x = 16; 117 | mermaid.y = 24; 118 | mermaid.weaponType = WEAPON_TYPE_TRIDENT; 119 | mermaid.isVisible = true; 120 | mermaid.HP = 4; 121 | mermaid.imuneTimer = 0; 122 | } 123 | 124 | 125 | void checkMermaid() 126 | { 127 | // MERMAID is IMUNE 128 | if (mermaid.isImune) 129 | { 130 | if (arduboy.everyXFrames(3)) 131 | { 132 | mermaid.imuneTimer++; 133 | mermaid.isVisible = !mermaid.isVisible; 134 | } 135 | if (mermaid.imuneTimer > MERMAID_IMUNE_TIME) 136 | { 137 | mermaid.imuneTimer = 0; 138 | mermaid.isImune = false; 139 | mermaid.isVisible = true; 140 | } 141 | } 142 | 143 | // MERMAID has SHIELD 144 | if (mermaid.hasShield) 145 | { 146 | if (arduboy.everyXFrames(3)) 147 | { 148 | mermaid.imuneTimer++; 149 | } 150 | if (mermaid.imuneTimer > MERMAID_SUPER_TIME) 151 | { 152 | mermaid.imuneTimer = 0; 153 | mermaid.hasShield = false; 154 | mermaid.isVisible = true; 155 | } 156 | } 157 | 158 | // MERMAID dies 159 | if (mermaid.HP < 2) 160 | { 161 | if (PLAYER_CAN_DIE) 162 | { 163 | rightX = 132; 164 | gameState = STATE_GAME_OVER; 165 | } 166 | else mermaid.HP = MAX_HP_MERMAID; 167 | } 168 | 169 | // MERMAID animation 170 | if (arduboy.everyXFrames(10)) mermaid.frame = (++mermaid.frame) % 6; 171 | 172 | // MERMAID SPARKLE animation 173 | if (arduboy.everyXFrames(5)) 174 | { 175 | for (byte i = 0; i < MAX_ONSCREEN_SPARKLES; i++) 176 | { 177 | sparkle[i].frame = (++sparkle[i].frame) % 16; 178 | } 179 | } 180 | } 181 | 182 | 183 | void drawMermaid() 184 | { 185 | // SHOW SHIELD 186 | if (mermaid.hasShield) 187 | { 188 | for (byte i = 0; i < MAX_ONSCREEN_SHIELDS; i++) 189 | { 190 | sprites.drawSelfMasked(mermaid.x - 7 + pgm_read_byte(&shieldX[sparkle[i].frame]), mermaid.y - 7 + pgm_read_byte(&shieldY[sparkle[i].frame]), protectionShield, sparkle[i].frame % 4); 191 | } 192 | } 193 | 194 | // SHOW MERMAID 195 | if (mermaid.isVisible) sprites.drawPlusMask(mermaid.x, mermaid.y, mermaid_plus_mask, mermaid.frame); 196 | 197 | // SHOW CHARGING 198 | if (mermaid.magicCharging) 199 | { 200 | for (byte i = 0; i < MAX_ONSCREEN_SPARKLES; i++) 201 | { 202 | sprites.drawSelfMasked(mermaid.x + sparkle[i].x + (sparkle[i].speedX * (sparkle[i].frame % 8)), mermaid.y + sparkle[i].y + (sparkle[i].speedY * (sparkle[i].frame % 8)), chargeSparkles, sparkle[i].frame % 8); 203 | } 204 | sprites.drawPlusMask(mermaid.x, mermaid.y, chargeBar_plus_mask, mermaid.chargeBarFrame); 205 | } 206 | } 207 | 208 | 209 | //////// Weapon functions ////////////////// 210 | //////////////////////////////////////////// 211 | 212 | void setWeapons() 213 | { 214 | mermaid.magicCharging = false; 215 | mermaid.chargeBarFrame = 0; 216 | mermaid.currentBullet = 0; 217 | mermaid.currentSeaShell = 0; 218 | for (byte i = 0; i < MAX_ONSCREEN_BULLETS; i++) 219 | { 220 | bullet[i].isVisible = false; 221 | bullet[i].frame = 0; 222 | } 223 | sparkle[0] = { .x = 18, .y = -6, .speedX = -2, .speedY = 3, .frame = 0}; 224 | sparkle[1] = { .x = -6, .y = 6, .speedX = 2, .speedY = 0, .frame = 7}; 225 | sparkle[2] = { .x = 18, .y = 18, .speedX = -2, .speedY = -3, .frame = 6}; 226 | sparkle[3] = { .x = 8, .y = -7, .speedX = 0, .speedY = 2, .frame = 5}; 227 | sparkle[4] = { .x = -5, .y = 18, .speedX = 2, .speedY = -3, .frame = 4}; 228 | sparkle[5] = { .x = 19, .y = 6, .speedX = -2, .speedY = 0, .frame = 3}; 229 | sparkle[6] = { .x = -5, .y = -6, .speedX = 2, .speedY = 3, .frame = 2}; 230 | sparkle[7] = { .x = 7, .y = 19, .speedX = 0, .speedY = -2, .frame = 1}; 231 | } 232 | 233 | 234 | void checkWeapons() 235 | { 236 | if (coolDown[mermaid.weaponType] < coolDownMax[mermaid.weaponType]) 237 | { 238 | coolDown[mermaid.weaponType]--; 239 | if (coolDown[mermaid.weaponType] < 1) coolDown[mermaid.weaponType] = coolDownMax[mermaid.weaponType]; 240 | } 241 | for (byte i = 0; i < MAX_ONSCREEN_BULLETS; i++) 242 | { 243 | if (bullet[i].type == WEAPON_TYPE_BUBBLES && arduboy.everyXFrames(3)) bullet[i].frame = !bullet[i].frame; 244 | if (bullet[i].type == WEAPON_TYPE_MAGIC && arduboy.everyXFrames(2)) bullet[i].frame++; 245 | if (bullet[i].type == WEAPON_TYPE_MAGIC && bullet[i].frame > 3) bullet[i].frame = 0; 246 | 247 | bullet[i].x += bulletSpeed[bullet[i].type]; 248 | if (bullet[i].type == WEAPON_TYPE_SEASHELL) bullet[i].y += bullet[i].speedY; 249 | if (bullet[i].x > 128 || bullet[i].y < -7 || bullet[i].y > 64) 250 | { 251 | bullet[i].isVisible = false; 252 | } 253 | } 254 | } 255 | 256 | 257 | 258 | void shootWeapon() 259 | { 260 | sound(880, 20); 261 | if (!bullet[mermaid.currentBullet].isVisible) 262 | { 263 | if (bullet[mermaid.currentBullet].type != WEAPON_TYPE_SEASHELL)bullet[mermaid.currentBullet].frame = 0; 264 | bullet[mermaid.currentBullet].type = mermaid.weaponType; 265 | bullet[mermaid.currentBullet].isVisible = true; 266 | bullet[mermaid.currentBullet].x = mermaid.x + 8; 267 | bullet[mermaid.currentBullet].y = mermaid.y + 6; 268 | bullet[mermaid.currentBullet].damage = bulletDamage[bullet[mermaid.currentBullet].type]; 269 | if (bullet[mermaid.currentBullet].type == WEAPON_TYPE_MAGIC) bullet[mermaid.currentBullet].damage += mermaid.chargeBarFrame; 270 | if (bullet[mermaid.currentBullet].type == WEAPON_TYPE_SEASHELL) 271 | { 272 | bullet[mermaid.currentBullet].speedY = seaShellSpeedY[mermaid.currentSeaShell]; 273 | bullet[mermaid.currentBullet].frame = mermaid.currentSeaShell; 274 | mermaid.currentSeaShell++; 275 | if (mermaid.currentSeaShell > 2) mermaid.currentSeaShell = 0; 276 | } 277 | mermaid.chargeBarFrame = 0; 278 | } 279 | mermaid.currentBullet++; 280 | if (mermaid.currentBullet > MAX_ONSCREEN_BULLETS - 1) mermaid.currentBullet = 0; 281 | } 282 | 283 | 284 | void drawWeapons() 285 | { 286 | for (byte i = 0; i < MAX_ONSCREEN_BULLETS; i++) 287 | { 288 | if (bullet[i].isVisible) sprites.drawSelfMasked(bullet[i].x, bullet[i].y, weapons[bullet[i].type], bullet[i].frame); 289 | } 290 | } 291 | 292 | void drawLifeHUD() 293 | { 294 | for (byte i = 0; i < AMOUNT_OF_HEARTS; i++) sprites.drawSelfMasked(8 * i, 0, hearts, 0); 295 | for (byte i = 0; i < mermaid.HP - 1; i++)sprites.drawSelfMasked(8 * i, 0, hearts, 1); 296 | } 297 | 298 | 299 | #endif 300 | -------------------------------------------------------------------------------- /examples/ESP8266_Mystic_Balloon/player.h: -------------------------------------------------------------------------------- 1 | #ifndef PLAYER_H 2 | #define PLAYER_H 3 | 4 | #include 5 | #include "globals.h" 6 | //#include "levels.h" 7 | #include "vec2.h" 8 | 9 | #define FIXED_POINT 5 10 | #define PLAYER_SPEED_WALKING 1 << FIXED_POINT 11 | #define PLAYER_SPEED_AIR 2 12 | #define PLAYER_PARTICLES 3 13 | #define PLAYER_JUMP_VELOCITY (1 << FIXED_POINT) + 8 14 | #define GRAVITY 3 15 | #define FRICTION 1 // for horizontal speed 16 | #define MAX_XSPEED PLAYER_SPEED_WALKING 17 | #define MAX_XSPEED_FAN 54 18 | #define MAX_YSPEED 3 * (1 << FIXED_POINT) 19 | #define CAMERA_OFFSET 16 20 | 21 | extern bool gridGetSolid(int8_t x, int8_t y); 22 | extern void kidHurt(); 23 | extern void windNoise(); 24 | 25 | struct Camera 26 | { 27 | // x and y are 9.6 signed fixed vec2 values 28 | vec2 pos; 29 | vec2 offset; 30 | }; 31 | 32 | struct Players 33 | { 34 | public: 35 | // x and y are 9.6 signed fixed vec2 values 36 | vec2 pos; 37 | vec2 actualpos; 38 | vec2 speed; 39 | boolean isActive; 40 | boolean isImune; 41 | boolean direction; 42 | boolean isWalking; 43 | boolean isJumping; 44 | boolean isLanding; 45 | boolean isBalloon; 46 | boolean jumpLetGo; 47 | boolean isSucking; 48 | byte imuneTimer; 49 | byte jumpTimer; 50 | byte frame; 51 | byte balloons; 52 | byte balloonOffset; 53 | vec2 particles[PLAYER_PARTICLES]; 54 | }; 55 | 56 | Players kid; 57 | Camera cam; 58 | 59 | void setKid() 60 | { 61 | kid.pos.x = 0; 62 | kid.pos.y = 0; 63 | kid.actualpos.x = 128; 64 | kid.actualpos.y = 0; 65 | kid.speed.x = 0; 66 | kid.speed.y = 0; 67 | kid.isActive = true; 68 | kid.isImune = true; 69 | kid.imuneTimer = 0; 70 | kid.jumpTimer = 0; 71 | kid.direction = FACING_RIGHT; 72 | kid.isWalking = false; 73 | kid.isJumping = false; 74 | kid.isLanding = false; 75 | kid.isBalloon = false; 76 | kid.jumpLetGo = true; 77 | kid.isSucking = false; 78 | #ifndef HARD_MODE 79 | kid.balloons = 3; 80 | #endif 81 | kid.balloonOffset = 0; 82 | for (byte i = 0; i < PLAYER_PARTICLES; ++i) 83 | kid.particles[i] = vec2(random(16), random(16)); 84 | } 85 | 86 | void checkKid() 87 | { 88 | if (kid.isImune) 89 | { 90 | if (arduboy.everyXFrames(2)) kid.isActive = !kid.isActive; 91 | kid.imuneTimer++; 92 | if (kid.imuneTimer > 60) 93 | { 94 | kid.imuneTimer = 0; 95 | kid.isImune = false; 96 | kid.isActive = true; 97 | } 98 | } 99 | 100 | if (kid.isWalking || kid.isSucking) 101 | { 102 | if (arduboy.everyXFrames(8)) 103 | { 104 | kid.frame = (++kid.frame) % 4; 105 | if (kid.frame % 2 == 0) 106 | sound(150, 20); 107 | } 108 | } 109 | else 110 | kid.frame = 0; 111 | 112 | // Kid is moving up 113 | if (!kid.isBalloon && kid.speed.y > 0) 114 | { 115 | kid.isJumping = true; 116 | kid.isLanding = false; 117 | if (!kid.jumpLetGo && kid.jumpTimer > 0) 118 | { 119 | kid.speed.y += GRAVITY + 2; 120 | kid.jumpTimer--; 121 | } 122 | } 123 | else if (kid.speed.y < 0) 124 | { 125 | // Kid is moving down 126 | kid.isJumping = false; 127 | kid.isLanding = true; 128 | } 129 | 130 | // Update position--- 131 | // -Solid checking 132 | int tx = (kid.pos.x + 6) >> 4; 133 | int ty = (kid.pos.y + 8) >> 4; 134 | boolean solidbelow = gridGetSolid(tx, (kid.pos.y + 16) >> 4); 135 | //boolean solidabove = gridGetSolid(tx, (kid.pos.y - 1) >> 4); 136 | //boolean solidleft = gridGetSolid((kid.pos.x - 1) >> 4, ty); 137 | //boolean solidright = gridGetSolid((kid.pos.x + 13) >> 4, ty); 138 | int tx2 = (((kid.actualpos.x + kid.speed.x) >> FIXED_POINT) - 1 + (kid.speed.x > 0) * 14) >> 4; 139 | boolean solidH = gridGetSolid(tx2, (kid.pos.y + 2) >> 4) 140 | || gridGetSolid(tx2, (kid.pos.y + 13) >> 4); 141 | int ty2 = (((kid.actualpos.y - kid.speed.y) >> FIXED_POINT) + (kid.speed.y < 0) * 17) >> 4; 142 | boolean solidV = gridGetSolid((kid.pos.x + 2) >> 4, ty2) 143 | || gridGetSolid((kid.pos.x + 10) >> 4, ty2); 144 | 145 | // Gravity 146 | if (kid.balloons == 0 || kid.speed.y > 0 || !solidbelow) 147 | { 148 | //kid.speed.y += GRAVITY; 149 | kid.speed.y = (kid.speed.y > -MAX_YSPEED) ? kid.speed.y - GRAVITY : -MAX_YSPEED; 150 | if (kid.isBalloon) 151 | { 152 | //cam.offset.y += 3; 153 | if (kid.balloonOffset > 0) 154 | kid.balloonOffset -= 2; 155 | else 156 | { 157 | //kid.speed.y = max(-((8 / kid.balloons) >> 1), kid.speed.y); 158 | kid.speed.y = max(kid.balloons - 5, kid.speed.y); 159 | } 160 | } 161 | } 162 | 163 | // Kid on ground 164 | if (kid.balloons > 0 && kid.speed.y <= 0 && (solidV || solidbelow)) 165 | { 166 | if (kid.isLanding) sound(80, 30); 167 | kid.speed.y = 0; 168 | kid.speed.x = 0; 169 | kid.isLanding = false; 170 | kid.isJumping = false; 171 | kid.isBalloon = false; 172 | int8_t ysnap = (((kid.actualpos.y >> FIXED_POINT) + 12) >> 4); 173 | //if (!gridGetSolid(ysnap, kid.pos.x >> 4)) 174 | kid.actualpos.y = ysnap << (FIXED_POINT + 4); 175 | 176 | // Fall off edge 177 | //if (abs(((kid.pos.x + 6) % 16) - 8) >= 4) 178 | //if (!arduboy.pressed(RIGHT_BUTTON) && !arduboy.pressed(LEFT_BUTTON)) 179 | if (!arduboy.pressed(RIGHT_BUTTON | LEFT_BUTTON)) 180 | { 181 | int yy = (kid.pos.y + 16) >> 4; 182 | bool sl = gridGetSolid((kid.pos.x + 4) >> 4, yy); 183 | bool sr = gridGetSolid((kid.pos.x + 8) >> 4, yy); 184 | if (!sl & gridGetSolid((kid.pos.x + 11) >> 4, yy)) 185 | kid.actualpos.x -= FIXED_POINT << 2; 186 | else if (!sr && gridGetSolid((kid.pos.x) >> 4, yy)) 187 | kid.actualpos.x += FIXED_POINT << 2; 188 | } 189 | } 190 | else 191 | { 192 | // Friction in air 193 | if (abs(kid.speed.x) > FRICTION) 194 | { 195 | if (arduboy.everyXFrames(4)) 196 | { 197 | if (kid.speed.x > 0) kid.speed.x -= FRICTION; 198 | else if (kid.speed.x < 0) kid.speed.x += FRICTION; 199 | } 200 | } 201 | else 202 | { 203 | kid.speed.x = 0; 204 | } 205 | } 206 | 207 | // Move out of walls 208 | if (!gridGetSolid(tx, ty)) 209 | { 210 | if (gridGetSolid((kid.pos.x) >> 4, ty)) 211 | kid.actualpos.x += 8; 212 | else if (gridGetSolid((kid.pos.x + 11) >> 4, ty)) 213 | kid.actualpos.x -= 8; 214 | } 215 | 216 | if (kid.balloons == 0 || (!solidV && kid.speed.y != 0)) 217 | { 218 | kid.actualpos.y -= kid.speed.y; 219 | } 220 | else 221 | { 222 | if (solidV && kid.speed.y > 0) 223 | { 224 | kid.actualpos.y = ((kid.pos.y + 8) >> 4) << (FIXED_POINT + 4); 225 | kid.speed.y = 0; 226 | sound(80, 30); 227 | } 228 | } 229 | 230 | // -X Position 231 | //if ((kid.speed.x < 0 && !solidH) || (kid.speed.x > 0 && !solidH)) 232 | if (kid.speed.x != 0) 233 | { 234 | if (!solidH) 235 | { 236 | kid.actualpos.x += kid.speed.x; 237 | } 238 | else 239 | { 240 | kid.speed.x = 0; 241 | kid.actualpos.x = ((((kid.pos.x + 6) >> 4) << 4) + ((!kid.direction) * 4)) << (FIXED_POINT); 242 | } 243 | } 244 | 245 | kid.pos = (kid.actualpos >> FIXED_POINT); 246 | 247 | if (kid.isSucking) windNoise();//sound(300 + random(10), 20); 248 | } 249 | 250 | /* updateCamera() 251 | * Positions camera to show kid 252 | */ 253 | void updateCamera() 254 | { 255 | if (kid.balloons == 0) 256 | return; 257 | // Camera offset 258 | if (cam.offset.x > 0) cam.offset.x--; 259 | else if (cam.offset.x < 0) cam.offset.x++; 260 | if (cam.offset.y > 0) cam.offset.y--; 261 | else if (cam.offset.y < 0) cam.offset.y++; 262 | 263 | vec2 cp; 264 | //kp = kid.pos; 265 | cp = (cam.pos + cam.offset); 266 | 267 | vec2 V; 268 | //vec2 V = (kid.pos - cam.pos + cam.offset) >> 3; // more bytes 269 | V.x = kid.pos.x - cp.x - 58; 270 | V.y = kid.pos.y - cp.y - 24; 271 | V = V >> 2; 272 | 273 | cam.pos += V; 274 | cam.pos.y = min(320, cam.pos.y); 275 | } 276 | 277 | void drawKid() 278 | { 279 | if (kid.isActive) 280 | { 281 | vec2 kidcam; 282 | kidcam.x = kid.pos.x - cam.pos.x; 283 | kidcam.y = kid.pos.y - cam.pos.y; 284 | // Fall off earth 285 | if (kidcam.y > 64 + (CAMERA_OFFSET * 3)) 286 | { 287 | kid.actualpos = startPos; 288 | kidHurt(); 289 | if (kid.balloons == 0) 290 | { 291 | // dead 292 | gameState = STATE_GAME_OVER; 293 | } 294 | //--kid.balloons; 295 | } 296 | 297 | if (kid.isBalloon) 298 | { 299 | int commonx = kidcam.x - (6 * kid.direction); 300 | int commony = kidcam.y + kid.balloonOffset; 301 | if (kid.balloons > 1) 302 | { 303 | sprites.drawPlusMask(commonx + 1, commony - 11, balloon_plus_mask, 0); 304 | if (kid.balloons > 2) sprites.drawPlusMask(commonx + 7, commony - 12, balloon_plus_mask, 0); 305 | } 306 | sprites.drawPlusMask(commonx + 4, commony - 9, balloon_plus_mask, 0); 307 | } 308 | if (!kid.isSucking) 309 | { 310 | sprites.drawSelfMasked(kidcam.x, kidcam.y, kidSprite, 12 + kid.direction); 311 | sprites.drawErase(kidcam.x, kidcam.y, kidSprite, kid.frame + 6 * kid.direction + ((kid.isJumping << 2) + 5 * (kid.isLanding || kid.isBalloon)) * !kid.isSucking); 312 | } 313 | 314 | else 315 | { 316 | sprites.drawPlusMask(kidcam.x - 2, kidcam.y, kidSpriteSuck_plus_mask, walkerFrame + 2*kid.direction); //kidSpriteSuck 317 | for (byte i = 0; i < PLAYER_PARTICLES; ++i) 318 | { 319 | // Update 320 | if (kid.particles[i].y > 2) --kid.particles[i].y; 321 | else if (kid.particles[i].y < -2) ++kid.particles[i].y; 322 | kid.particles[i].x -= 2; 323 | if (kid.particles[i].x < 0) 324 | { 325 | kid.particles[i].x = 16; 326 | kid.particles[i].y = -4 + random(13); 327 | } 328 | 329 | // Draw 330 | if (kid.direction) 331 | sprites.drawErase(kidcam.x - kid.particles[i].x, kidcam.y + 10 + kid.particles[i].y, particle , 0); 332 | else 333 | sprites.drawErase(kidcam.x + 15 + kid.particles[i].x, kidcam.y + 10 + kid.particles[i].y, particle , 0); 334 | } 335 | } 336 | } 337 | } 338 | 339 | 340 | #endif 341 | -------------------------------------------------------------------------------- /src/glcdfont.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file glcdfont.c 3 | * \brief 4 | * The font definitions used to display text characters. 5 | */ 6 | 7 | #ifndef ESP8266 8 | #include 9 | #include 10 | #endif 11 | 12 | #ifndef FONT5X7_H 13 | #define FONT5X7_H 14 | 15 | // standard ascii 5x7 font 16 | 17 | #ifndef ESP8266 18 | static const unsigned char font[] PROGMEM = 19 | #else 20 | static const unsigned char font[] = 21 | #endif 22 | { 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 24 | 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 25 | 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 26 | 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 27 | 0x18, 0x3C, 0x7E, 0x3C, 0x18, 28 | 0x1C, 0x57, 0x7D, 0x57, 0x1C, 29 | 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 30 | 0x00, 0x18, 0x3C, 0x18, 0x00, 31 | 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 32 | 0x00, 0x18, 0x24, 0x18, 0x00, 33 | 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 34 | 0x30, 0x48, 0x3A, 0x06, 0x0E, 35 | 0x26, 0x29, 0x79, 0x29, 0x26, 36 | 0x40, 0x7F, 0x05, 0x05, 0x07, 37 | 0x40, 0x7F, 0x05, 0x25, 0x3F, 38 | 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 39 | 0x7F, 0x3E, 0x1C, 0x1C, 0x08, 40 | 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 41 | 0x14, 0x22, 0x7F, 0x22, 0x14, 42 | 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 43 | 0x06, 0x09, 0x7F, 0x01, 0x7F, 44 | 0x00, 0x66, 0x89, 0x95, 0x6A, 45 | 0x60, 0x60, 0x60, 0x60, 0x60, 46 | 0x94, 0xA2, 0xFF, 0xA2, 0x94, 47 | 0x08, 0x04, 0x7E, 0x04, 0x08, 48 | 0x10, 0x20, 0x7E, 0x20, 0x10, 49 | 0x08, 0x08, 0x2A, 0x1C, 0x08, 50 | 0x08, 0x1C, 0x2A, 0x08, 0x08, 51 | 0x1E, 0x10, 0x10, 0x10, 0x10, 52 | 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 53 | 0x30, 0x38, 0x3E, 0x38, 0x30, 54 | 0x06, 0x0E, 0x3E, 0x0E, 0x06, 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 56 | 0x00, 0x00, 0x5F, 0x00, 0x00, 57 | 0x00, 0x07, 0x00, 0x07, 0x00, 58 | 0x14, 0x7F, 0x14, 0x7F, 0x14, 59 | 0x24, 0x2A, 0x7F, 0x2A, 0x12, 60 | 0x23, 0x13, 0x08, 0x64, 0x62, 61 | 0x36, 0x49, 0x56, 0x20, 0x50, 62 | 0x00, 0x08, 0x07, 0x03, 0x00, 63 | 0x00, 0x1C, 0x22, 0x41, 0x00, 64 | 0x00, 0x41, 0x22, 0x1C, 0x00, 65 | 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 66 | 0x08, 0x08, 0x3E, 0x08, 0x08, 67 | 0x00, 0x80, 0x70, 0x30, 0x00, 68 | 0x08, 0x08, 0x08, 0x08, 0x08, 69 | 0x00, 0x00, 0x60, 0x60, 0x00, 70 | 0x20, 0x10, 0x08, 0x04, 0x02, 71 | 0x3E, 0x51, 0x49, 0x45, 0x3E, 72 | 0x00, 0x42, 0x7F, 0x40, 0x00, 73 | 0x72, 0x49, 0x49, 0x49, 0x46, 74 | 0x21, 0x41, 0x49, 0x4D, 0x33, 75 | 0x18, 0x14, 0x12, 0x7F, 0x10, 76 | 0x27, 0x45, 0x45, 0x45, 0x39, 77 | 0x3C, 0x4A, 0x49, 0x49, 0x31, 78 | 0x41, 0x21, 0x11, 0x09, 0x07, 79 | 0x36, 0x49, 0x49, 0x49, 0x36, 80 | 0x46, 0x49, 0x49, 0x29, 0x1E, 81 | 0x00, 0x00, 0x14, 0x00, 0x00, 82 | 0x00, 0x40, 0x34, 0x00, 0x00, 83 | 0x00, 0x08, 0x14, 0x22, 0x41, 84 | 0x14, 0x14, 0x14, 0x14, 0x14, 85 | 0x00, 0x41, 0x22, 0x14, 0x08, 86 | 0x02, 0x01, 0x59, 0x09, 0x06, 87 | 0x3E, 0x41, 0x5D, 0x59, 0x4E, 88 | 0x7C, 0x12, 0x11, 0x12, 0x7C, 89 | 0x7F, 0x49, 0x49, 0x49, 0x36, 90 | 0x3E, 0x41, 0x41, 0x41, 0x22, 91 | 0x7F, 0x41, 0x41, 0x41, 0x3E, 92 | 0x7F, 0x49, 0x49, 0x49, 0x41, 93 | 0x7F, 0x09, 0x09, 0x09, 0x01, 94 | 0x3E, 0x41, 0x41, 0x51, 0x73, 95 | 0x7F, 0x08, 0x08, 0x08, 0x7F, 96 | 0x00, 0x41, 0x7F, 0x41, 0x00, 97 | 0x20, 0x40, 0x41, 0x3F, 0x01, 98 | 0x7F, 0x08, 0x14, 0x22, 0x41, 99 | 0x7F, 0x40, 0x40, 0x40, 0x40, 100 | 0x7F, 0x02, 0x1C, 0x02, 0x7F, 101 | 0x7F, 0x04, 0x08, 0x10, 0x7F, 102 | 0x3E, 0x41, 0x41, 0x41, 0x3E, 103 | 0x7F, 0x09, 0x09, 0x09, 0x06, 104 | 0x3E, 0x41, 0x51, 0x21, 0x5E, 105 | 0x7F, 0x09, 0x19, 0x29, 0x46, 106 | 0x26, 0x49, 0x49, 0x49, 0x32, 107 | 0x03, 0x01, 0x7F, 0x01, 0x03, 108 | 0x3F, 0x40, 0x40, 0x40, 0x3F, 109 | 0x1F, 0x20, 0x40, 0x20, 0x1F, 110 | 0x3F, 0x40, 0x38, 0x40, 0x3F, 111 | 0x63, 0x14, 0x08, 0x14, 0x63, 112 | 0x03, 0x04, 0x78, 0x04, 0x03, 113 | 0x61, 0x59, 0x49, 0x4D, 0x43, 114 | 0x00, 0x7F, 0x41, 0x41, 0x41, 115 | 0x02, 0x04, 0x08, 0x10, 0x20, 116 | 0x00, 0x41, 0x41, 0x41, 0x7F, 117 | 0x04, 0x02, 0x01, 0x02, 0x04, 118 | 0x40, 0x40, 0x40, 0x40, 0x40, 119 | 0x00, 0x03, 0x07, 0x08, 0x00, 120 | 0x20, 0x54, 0x54, 0x78, 0x40, 121 | 0x7F, 0x28, 0x44, 0x44, 0x38, 122 | 0x38, 0x44, 0x44, 0x44, 0x28, 123 | 0x38, 0x44, 0x44, 0x28, 0x7F, 124 | 0x38, 0x54, 0x54, 0x54, 0x18, 125 | 0x00, 0x08, 0x7E, 0x09, 0x02, 126 | 0x18, 0xA4, 0xA4, 0x9C, 0x78, 127 | 0x7F, 0x08, 0x04, 0x04, 0x78, 128 | 0x00, 0x44, 0x7D, 0x40, 0x00, 129 | 0x20, 0x40, 0x40, 0x3D, 0x00, 130 | 0x7F, 0x10, 0x28, 0x44, 0x00, 131 | 0x00, 0x41, 0x7F, 0x40, 0x00, 132 | 0x7C, 0x04, 0x78, 0x04, 0x78, 133 | 0x7C, 0x08, 0x04, 0x04, 0x78, 134 | 0x38, 0x44, 0x44, 0x44, 0x38, 135 | 0xFC, 0x18, 0x24, 0x24, 0x18, 136 | 0x18, 0x24, 0x24, 0x18, 0xFC, 137 | 0x7C, 0x08, 0x04, 0x04, 0x08, 138 | 0x48, 0x54, 0x54, 0x54, 0x24, 139 | 0x04, 0x04, 0x3F, 0x44, 0x24, 140 | 0x3C, 0x40, 0x40, 0x20, 0x7C, 141 | 0x1C, 0x20, 0x40, 0x20, 0x1C, 142 | 0x3C, 0x40, 0x30, 0x40, 0x3C, 143 | 0x44, 0x28, 0x10, 0x28, 0x44, 144 | 0x4C, 0x90, 0x90, 0x90, 0x7C, 145 | 0x44, 0x64, 0x54, 0x4C, 0x44, 146 | 0x00, 0x08, 0x36, 0x41, 0x00, 147 | 0x00, 0x00, 0x77, 0x00, 0x00, 148 | 0x00, 0x41, 0x36, 0x08, 0x00, 149 | 0x02, 0x01, 0x02, 0x04, 0x02, 150 | 0x3C, 0x26, 0x23, 0x26, 0x3C, 151 | 0x1E, 0xA1, 0xA1, 0x61, 0x12, 152 | 0x3A, 0x40, 0x40, 0x20, 0x7A, 153 | 0x38, 0x54, 0x54, 0x55, 0x59, 154 | 0x21, 0x55, 0x55, 0x79, 0x41, 155 | 0x21, 0x54, 0x54, 0x78, 0x41, 156 | 0x21, 0x55, 0x54, 0x78, 0x40, 157 | 0x20, 0x54, 0x55, 0x79, 0x40, 158 | 0x0C, 0x1E, 0x52, 0x72, 0x12, 159 | 0x39, 0x55, 0x55, 0x55, 0x59, 160 | 0x39, 0x54, 0x54, 0x54, 0x59, 161 | 0x39, 0x55, 0x54, 0x54, 0x58, 162 | 0x00, 0x00, 0x45, 0x7C, 0x41, 163 | 0x00, 0x02, 0x45, 0x7D, 0x42, 164 | 0x00, 0x01, 0x45, 0x7C, 0x40, 165 | 0xF0, 0x29, 0x24, 0x29, 0xF0, 166 | 0xF0, 0x28, 0x25, 0x28, 0xF0, 167 | 0x7C, 0x54, 0x55, 0x45, 0x00, 168 | 0x20, 0x54, 0x54, 0x7C, 0x54, 169 | 0x7C, 0x0A, 0x09, 0x7F, 0x49, 170 | 0x32, 0x49, 0x49, 0x49, 0x32, 171 | 0x32, 0x48, 0x48, 0x48, 0x32, 172 | 0x32, 0x4A, 0x48, 0x48, 0x30, 173 | 0x3A, 0x41, 0x41, 0x21, 0x7A, 174 | 0x3A, 0x42, 0x40, 0x20, 0x78, 175 | 0x00, 0x9D, 0xA0, 0xA0, 0x7D, 176 | 0x39, 0x44, 0x44, 0x44, 0x39, 177 | 0x3D, 0x40, 0x40, 0x40, 0x3D, 178 | 0x3C, 0x24, 0xFF, 0x24, 0x24, 179 | 0x48, 0x7E, 0x49, 0x43, 0x66, 180 | 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, 181 | 0xFF, 0x09, 0x29, 0xF6, 0x20, 182 | 0xC0, 0x88, 0x7E, 0x09, 0x03, 183 | 0x20, 0x54, 0x54, 0x79, 0x41, 184 | 0x00, 0x00, 0x44, 0x7D, 0x41, 185 | 0x30, 0x48, 0x48, 0x4A, 0x32, 186 | 0x38, 0x40, 0x40, 0x22, 0x7A, 187 | 0x00, 0x7A, 0x0A, 0x0A, 0x72, 188 | 0x7D, 0x0D, 0x19, 0x31, 0x7D, 189 | 0x26, 0x29, 0x29, 0x2F, 0x28, 190 | 0x26, 0x29, 0x29, 0x29, 0x26, 191 | 0x30, 0x48, 0x4D, 0x40, 0x20, 192 | 0x38, 0x08, 0x08, 0x08, 0x08, 193 | 0x08, 0x08, 0x08, 0x08, 0x38, 194 | 0x2F, 0x10, 0xC8, 0xAC, 0xBA, 195 | 0x2F, 0x10, 0x28, 0x34, 0xFA, 196 | 0x00, 0x00, 0x7B, 0x00, 0x00, 197 | 0x08, 0x14, 0x2A, 0x14, 0x22, 198 | 0x22, 0x14, 0x2A, 0x14, 0x08, 199 | 0x95, 0x00, 0x22, 0x00, 0x95, 200 | 0xAA, 0x00, 0x55, 0x00, 0xAA, 201 | 0xAA, 0x55, 0xAA, 0x55, 0xAA, 202 | 0x00, 0x00, 0x00, 0xFF, 0x00, 203 | 0x10, 0x10, 0x10, 0xFF, 0x00, 204 | 0x14, 0x14, 0x14, 0xFF, 0x00, 205 | 0x10, 0x10, 0xFF, 0x00, 0xFF, 206 | 0x10, 0x10, 0xF0, 0x10, 0xF0, 207 | 0x14, 0x14, 0x14, 0xFC, 0x00, 208 | 0x14, 0x14, 0xF7, 0x00, 0xFF, 209 | 0x00, 0x00, 0xFF, 0x00, 0xFF, 210 | 0x14, 0x14, 0xF4, 0x04, 0xFC, 211 | 0x14, 0x14, 0x17, 0x10, 0x1F, 212 | 0x10, 0x10, 0x1F, 0x10, 0x1F, 213 | 0x14, 0x14, 0x14, 0x1F, 0x00, 214 | 0x10, 0x10, 0x10, 0xF0, 0x00, 215 | 0x00, 0x00, 0x00, 0x1F, 0x10, 216 | 0x10, 0x10, 0x10, 0x1F, 0x10, 217 | 0x10, 0x10, 0x10, 0xF0, 0x10, 218 | 0x00, 0x00, 0x00, 0xFF, 0x10, 219 | 0x10, 0x10, 0x10, 0x10, 0x10, 220 | 0x10, 0x10, 0x10, 0xFF, 0x10, 221 | 0x00, 0x00, 0x00, 0xFF, 0x14, 222 | 0x00, 0x00, 0xFF, 0x00, 0xFF, 223 | 0x00, 0x00, 0x1F, 0x10, 0x17, 224 | 0x00, 0x00, 0xFC, 0x04, 0xF4, 225 | 0x14, 0x14, 0x17, 0x10, 0x17, 226 | 0x14, 0x14, 0xF4, 0x04, 0xF4, 227 | 0x00, 0x00, 0xFF, 0x00, 0xF7, 228 | 0x14, 0x14, 0x14, 0x14, 0x14, 229 | 0x14, 0x14, 0xF7, 0x00, 0xF7, 230 | 0x14, 0x14, 0x14, 0x17, 0x14, 231 | 0x10, 0x10, 0x1F, 0x10, 0x1F, 232 | 0x14, 0x14, 0x14, 0xF4, 0x14, 233 | 0x10, 0x10, 0xF0, 0x10, 0xF0, 234 | 0x00, 0x00, 0x1F, 0x10, 0x1F, 235 | 0x00, 0x00, 0x00, 0x1F, 0x14, 236 | 0x00, 0x00, 0x00, 0xFC, 0x14, 237 | 0x00, 0x00, 0xF0, 0x10, 0xF0, 238 | 0x10, 0x10, 0xFF, 0x10, 0xFF, 239 | 0x14, 0x14, 0x14, 0xFF, 0x14, 240 | 0x10, 0x10, 0x10, 0x1F, 0x00, 241 | 0x00, 0x00, 0x00, 0xF0, 0x10, 242 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 243 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 244 | 0xFF, 0xFF, 0xFF, 0x00, 0x00, 245 | 0x00, 0x00, 0x00, 0xFF, 0xFF, 246 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 247 | 0x38, 0x44, 0x44, 0x38, 0x44, 248 | 0x7C, 0x2A, 0x2A, 0x3E, 0x14, 249 | 0x7E, 0x02, 0x02, 0x06, 0x06, 250 | 0x02, 0x7E, 0x02, 0x7E, 0x02, 251 | 0x63, 0x55, 0x49, 0x41, 0x63, 252 | 0x38, 0x44, 0x44, 0x3C, 0x04, 253 | 0x40, 0x7E, 0x20, 0x1E, 0x20, 254 | 0x06, 0x02, 0x7E, 0x02, 0x02, 255 | 0x99, 0xA5, 0xE7, 0xA5, 0x99, 256 | 0x1C, 0x2A, 0x49, 0x2A, 0x1C, 257 | 0x4C, 0x72, 0x01, 0x72, 0x4C, 258 | 0x30, 0x4A, 0x4D, 0x4D, 0x30, 259 | 0x30, 0x48, 0x78, 0x48, 0x30, 260 | 0xBC, 0x62, 0x5A, 0x46, 0x3D, 261 | 0x3E, 0x49, 0x49, 0x49, 0x00, 262 | 0x7E, 0x01, 0x01, 0x01, 0x7E, 263 | 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 264 | 0x44, 0x44, 0x5F, 0x44, 0x44, 265 | 0x40, 0x51, 0x4A, 0x44, 0x40, 266 | 0x40, 0x44, 0x4A, 0x51, 0x40, 267 | 0x00, 0x00, 0xFF, 0x01, 0x03, 268 | 0xE0, 0x80, 0xFF, 0x00, 0x00, 269 | 0x08, 0x08, 0x6B, 0x6B, 0x08, 270 | 0x36, 0x12, 0x36, 0x24, 0x36, 271 | 0x06, 0x0F, 0x09, 0x0F, 0x06, 272 | 0x00, 0x00, 0x18, 0x18, 0x00, 273 | 0x00, 0x00, 0x10, 0x10, 0x00, 274 | 0x30, 0x40, 0xFF, 0x01, 0x01, 275 | 0x00, 0x1F, 0x01, 0x01, 0x1E, 276 | 0x00, 0x19, 0x1D, 0x17, 0x12, 277 | 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 278 | 0x00, 0x00, 0x00, 0x00, 0x00, 279 | }; 280 | 281 | #endif 282 | -------------------------------------------------------------------------------- /examples/ESP8266_PlayTune/ESP8266_PlayTune.ino: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | Play a musical composition in the background while 3 | the main sketch code runs in the foreground. 4 | 5 | The ArduboyPlaytune library must be installed to use this sketch 6 | https://github.com/Arduboy/ArduboyPlayTune 7 | 8 | The D-Pad buttons will move the text and play a tone. 9 | 10 | The A button mutes the sound. 11 | The screen is inverted when sound is muted. 12 | 13 | The B button will turn sound back on if it's muted. 14 | 15 | The score that is played contains two parts. 16 | With the DevKit only one part is played. 17 | ***************************************************************/ 18 | 19 | #include 20 | #include 21 | 22 | // 2 Part Inventions No. 3 - J.S. Bach 23 | const byte score[] PROGMEM = { 24 | 2,154, 0x90,62, 0,166, 0x90,64, 0,166, 0x90,66, 0,166, 0x90,64, 0,166, 25 | 0x90,67, 0,166, 0x90,66, 0,166, 0x90,64, 0,166, 0x90,62, 0,166, 0x90,69, 26 | 0,166, 0x90,67, 0,166, 0x90,66, 0,166, 0x90,64, 0,166, 0x91,50, 0x90,66, 27 | 0,166, 0x91,52, 0x90,62, 0,166, 0x91,54, 0x90,69, 0,166, 0x91,52, 0,166, 28 | 0x90,71, 0x91,55, 0,166, 0x91,54, 0,166, 0x90,73, 0x91,52, 0,55, 0x90,71, 29 | 0,55, 0x90,73, 0,55, 0x91,50, 0x90,74, 0,166, 0x91,57, 0x90,73, 0,83, 30 | 0x90,74, 0,83, 0x91,55, 0x90,73, 0,166, 0x91,54, 0x90,71, 0,83, 0x90,69, 31 | 0,83, 0x91,52, 0,125, 0x80, 0,41, 0x90,73, 0x91,54, 0,166, 0x90,74, 0x91,50, 32 | 0,166, 0x90,76, 0x91,57, 0,166, 0x90,73, 0,166, 0x91,45, 0x90,78, 0,166, 33 | 0x90,74, 0,166, 0x91,57, 0x90,73, 0,166, 0x90,71, 0,138, 0x81, 0,27, 0x91,57, 34 | 0x90,76, 0,166, 0x90,73, 0,166, 0x91,45, 0x90,74, 0,166, 0x90,71, 0,166, 35 | 0x91,57, 0x90,69, 0,166, 0x90,68, 0,138, 0x81, 0,27, 0x91,57, 0x90,76, 0,166, 36 | 0x90,73, 0,166, 0x91,45, 0x90,78, 0,166, 0x90,74, 0,166, 0x91,57, 0x90,73, 37 | 0,166, 0x90,71, 0,138, 0x81, 0,27, 0x91,57, 0x90,76, 0,166, 0x90,73, 0,166, 38 | 0x91,45, 0x90,74, 0,166, 0x90,71, 0,166, 0x91,57, 0x90,69, 0,166, 0x90,68, 39 | 0,138, 0x81, 0,27, 0x91,57, 0x90,73, 0,166, 0x90,71, 0,166, 0x91,59, 0x90,74, 40 | 0,166, 0x90,73, 0,166, 0x91,61, 0x90,71, 0,166, 0x90,69, 0,166, 0x91,62, 41 | 0x90,78, 0,166, 0x91,61, 0,166, 0x90,68, 0x91,64, 0,166, 0x91,62, 0,166, 42 | 0x90,69, 0x91,61, 0,166, 0x91,59, 0,166, 0x91,61, 0,27, 0x80, 0,27, 0x90,71, 43 | 0,55, 0x90,69, 0,55, 0x91,62, 0x90,68, 0,55, 0x90,69, 0,55, 0x90,71, 44 | 0,27, 0x80, 0,27, 0x90,71, 0x91,64, 1,77, 0x91,52, 0,166, 0x90,69, 0,166, 45 | 0x91,57, 0x90,69, 0,166, 0x91,52, 0,166, 0x91,54, 0,166, 0x91,56, 0,166, 46 | 0x91,57, 0x80, 0,166, 0x91,59, 0,166, 0x91,61, 0,166, 0x91,59, 0,166, 0x90,76, 47 | 0x91,62, 0,166, 0x91,61, 0,166, 0x90,81, 0x91,59, 0,166, 0x91,57, 0,166, 48 | 0x91,64, 0,166, 0x90,71, 0,166, 0x91,52, 0x90,73, 0,166, 0x90,75, 0,166, 49 | 0x90,76, 0x81, 0,166, 0x90,78, 0,166, 0x90,79, 0,166, 0x90,78, 0,166, 0x91,59, 50 | 0x90,81, 0,166, 0x90,79, 0,166, 0x91,64, 0x90,78, 0,166, 0x90,76, 0,166, 51 | 0x90,83, 0,166, 0x91,54, 0,166, 0x90,71, 0x91,56, 0,166, 0x91,58, 0,166, 52 | 0x91,59, 0x80, 0,166, 0x91,61, 0,166, 0x91,62, 0,166, 0x91,61, 0,166, 0x90,66, 53 | 0x91,64, 0,166, 0x91,62, 0,166, 0x90,71, 0x91,61, 0,166, 0x91,59, 0,166, 54 | 0x91,66, 0,166, 0x90,70, 0,166, 0x91,54, 0x90,71, 0,166, 0x90,73, 0,166, 55 | 0x91,64, 0x90,74, 0,166, 0x90,76, 0,166, 0x91,62, 0x90,78, 0,166, 0x90,76, 56 | 0,166, 0x91,71, 0x90,79, 0,166, 0x91,70, 0x90,78, 0,166, 0x91,71, 0x90,76, 57 | 0,166, 0x90,74, 0,166, 0x91,61, 0x90,76, 0,166, 0x90,74, 0,166, 0x91,70, 58 | 0x90,78, 0,166, 0x91,68, 0x90,76, 0,166, 0x91,70, 0x90,74, 0,166, 0x90,73, 59 | 0,166, 0x91,71, 0x90,74, 0,166, 0x91,69, 0x90,73, 0,166, 0x91,67, 0x90,76, 60 | 0,166, 0x91,66, 0x90,74, 0,166, 0x91,64, 0x90,73, 0,166, 0x91,62, 0x90,71, 61 | 0,166, 0x91,64, 0x90,73, 0,166, 0x91,62, 0,166, 0x90,70, 0x91,66, 0,83, 62 | 0x90,68, 0,83, 0x91,64, 0x90,70, 0,166, 0x91,62, 0x90,71, 0,166, 0x91,61, 63 | 0,166, 0x91,62, 0,166, 0x90,73, 0x91,64, 0,138, 0x80, 0,27, 0x90,73, 0x91,66, 64 | 0,83, 0x90,74, 0,83, 0x90,73, 0,166, 0x91,54, 0,166, 0x90,71, 0,166, 65 | 0x91,59, 0,166, 0x90,66, 0,166, 0x91,54, 0x90,68, 0,166, 0x90,70, 0,166, 66 | 0x91,50, 0x90,71, 0,166, 0x90,73, 0,166, 0x91,47, 0x90,74, 0,166, 0x90,73, 67 | 0,166, 0x90,76, 0,166, 0x90,74, 0,166, 0x90,73, 0x81, 0,166, 0x90,71, 0,166, 68 | 0x90,79, 0,166, 0x91,47, 0,166, 0x91,49, 0,166, 0x91,51, 0,166, 0x91,52, 69 | 0,166, 0x91,54, 0,166, 0x91,55, 0,166, 0x91,54, 0,166, 0x91,57, 0,166, 70 | 0x91,55, 0,166, 0x91,54, 0,166, 0x91,52, 0,166, 0x91,57, 0,138, 0x80, 0,27, 71 | 0x90,64, 0,166, 0x90,66, 0,166, 0x90,68, 0,166, 0x90,69, 0,166, 0x90,71, 72 | 0,166, 0x90,73, 0,166, 0x90,71, 0,166, 0x90,74, 0,166, 0x90,73, 0,166, 73 | 0x90,71, 0,166, 0x90,69, 0,166, 0x90,78, 0,138, 0x81, 0,27, 0x91,45, 0,166, 74 | 0x91,47, 0,166, 0x91,49, 0,166, 0x91,50, 0,166, 0x91,52, 0,166, 0x91,54, 75 | 0,166, 0x91,52, 0,166, 0x91,55, 0,166, 0x91,54, 0,166, 0x91,52, 0,166, 76 | 0x91,50, 0,166, 0x91,56, 0,138, 0x80, 0,27, 0x90,71, 0,166, 0x90,76, 0,166, 77 | 0x91,52, 0x90,74, 0,166, 0x91,54, 0x90,73, 0,166, 0x91,56, 0x90,71, 0,166, 78 | 0x91,57, 0x90,73, 0,166, 0x91,56, 0x90,71, 0,166, 0x91,54, 0x90,74, 0,166, 79 | 0x91,52, 0x90,73, 0,166, 0x91,50, 0x90,71, 0,166, 0x91,54, 0x90,69, 0,166, 80 | 0x91,52, 0x90,68, 0,83, 0x90,69, 0,83, 0x91,50, 0x90,68, 0,166, 0x91,49, 81 | 0x90,64, 0,166, 0x91,47, 0,166, 0x90,69, 0x91,49, 0,166, 0x90,71, 0x91,45, 82 | 0,166, 0x90,73, 0x91,57, 0,166, 0x90,71, 0,166, 0x91,54, 0x90,74, 0,166, 83 | 0x90,73, 0,166, 0x91,49, 0x90,71, 0,166, 0x90,69, 0,166, 0x91,50, 0x90,78, 84 | 0,166, 0x91,49, 0,166, 0x91,52, 0,166, 0x90,68, 0x91,50, 0,166, 0x90,69, 85 | 0x91,49, 0,166, 0x90,68, 0x91,47, 0,166, 0x90,69, 0x91,49, 0,166, 0x90,74, 86 | 0x91,50, 0,166, 0x90,71, 0x91,52, 1,77, 0x91,40, 0,166, 0x90,69, 0,138, 87 | 0x80, 0,27, 0x90,69, 0x91,45, 0,166, 0x91,49, 0,166, 0x91,50, 0,166, 0x90,73, 88 | 0x91,52, 0,166, 0x90,74, 0x91,54, 0,166, 0x90,76, 0x91,55, 0,166, 0x90,66, 89 | 0x91,57, 0,166, 0x91,55, 0,166, 0x90,67, 0x91,59, 0,166, 0x91,57, 0,166, 90 | 0x90,71, 0x91,55, 0,83, 0x90,69, 0,83, 0x91,54, 0x90,67, 0,83, 0x90,69, 91 | 0,83, 0x91,55, 0x90,71, 0,166, 0x91,54, 0,166, 0x90,74, 0x91,57, 0,83, 92 | 0x90,73, 0,83, 0x91,55, 0x90,71, 0,83, 0x90,73, 0,83, 0x91,54, 0x90,74, 93 | 0,166, 0x91,52, 0,166, 0x91,54, 0,166, 0x90,73, 0x91,52, 0,166, 0x90,76, 94 | 0x91,55, 0,166, 0x90,74, 0x91,54, 0,166, 0x90,73, 0x91,52, 0,166, 0x90,74, 95 | 0x91,50, 0,166, 0x90,76, 0x91,57, 0,166, 0x90,74, 0,166, 0x91,45, 0x90,73, 96 | 0,166, 0x90,71, 0,166, 0x90,69, 0x81, 0,166, 0x90,67, 0,166, 0x90,66, 0,166, 97 | 0x90,64, 0,166, 0x90,67, 0,166, 0x90,66, 0,166, 0x90,64, 0,166, 0x90,62, 98 | 0,166, 0x90,69, 0,166, 0x90,67, 0,166, 0x90,66, 0,166, 0x90,64, 0,166, 99 | 0x91,50, 0x90,66, 0,166, 0x91,52, 0x90,62, 0,166, 0x91,54, 0x90,69, 0,166, 100 | 0x91,52, 0,166, 0x90,71, 0x91,55, 0,166, 0x91,54, 0,166, 0x90,73, 0x91,52, 101 | 0,55, 0x90,71, 0,55, 0x90,73, 0,55, 0x91,50, 0x90,74, 0,166, 0x91,57, 102 | 0x90,73, 0,83, 0x90,74, 0,83, 0x91,55, 0x90,73, 0,166, 0x91,54, 0x90,71, 103 | 0,83, 0x90,69, 0,83, 0x91,52, 0,125, 0x80, 0,41, 0x90,74, 0x91,54, 0,166, 104 | 0x91,50, 0,138, 0x80, 0,27, 0x90,74, 0x91,57, 0,166, 0x91,54, 0,166, 0x90,62, 105 | 0x91,59, 0,166, 0x91,55, 0,166, 0x90,74, 0x91,54, 0,166, 0x91,52, 0,138, 106 | 0x80, 0,27, 0x90,74, 0x91,57, 0,166, 0x91,54, 0,166, 0x90,62, 0x91,55, 0,166, 107 | 0x91,52, 0,166, 0x90,74, 0x91,50, 0,166, 0x91,49, 0,138, 0x80, 0,27, 0x90,74, 108 | 0x91,57, 0,166, 0x91,54, 0,166, 0x90,62, 0x91,59, 0,166, 0x91,55, 0,166, 109 | 0x90,74, 0x91,54, 0,166, 0x91,52, 0,138, 0x80, 0,27, 0x90,74, 0x91,57, 0,166, 110 | 0x91,54, 0,166, 0x90,62, 0x91,55, 0,166, 0x91,52, 0,166, 0x90,74, 0x91,50, 111 | 0,166, 0x90,76, 0x91,49, 0,166, 0x90,78, 0x91,50, 0,166, 0x90,76, 0,166, 112 | 0x91,52, 0x90,79, 0,166, 0x90,78, 0,166, 0x91,54, 0x90,76, 0,166, 0x90,74, 113 | 0,166, 0x91,55, 0x90,83, 0,166, 0x91,54, 0,166, 0x90,73, 0x91,57, 0,166, 114 | 0x91,55, 0,166, 0x90,74, 0x91,54, 0,166, 0x91,52, 0,166, 0x91,54, 0,27, 115 | 0x80, 0,27, 0x90,76, 0,55, 0x90,74, 0,55, 0x91,55, 0x90,73, 0,55, 0x90,74, 116 | 0,55, 0x90,76, 0,41, 0x80, 0,13, 0x90,76, 0x91,57, 1,77, 0x91,45, 0,166, 117 | 0x90,74, 0,138, 0x80, 0,27, 0x90,74, 0x91,47, 0,166, 0x91,45, 0,166, 0x90,62, 118 | 0x91,48, 0,166, 0x91,47, 0,166, 0x90,67, 0x91,45, 0,166, 0x91,43, 0,166, 119 | 0x91,50, 0,166, 0x90,57, 0,166, 0x90,59, 0,166, 0x90,61, 0,166, 0x90,62, 120 | 0,166, 0x90,64, 0,166, 0x90,66, 0,138, 0x81, 0,27, 0x91,49, 0x90,64, 0,166, 121 | 0x91,47, 0x90,67, 0,166, 0x91,45, 0x90,66, 0,166, 0x91,43, 0x90,64, 0,166, 122 | 0x91,42, 0x90,62, 0,166, 0x91,43, 0x90,71, 0,166, 0x91,42, 0,166, 0x91,45, 123 | 0,166, 0x90,61, 0x91,43, 0,166, 0x90,62, 0x91,42, 0,166, 0x90,61, 0x91,40, 124 | 0,166, 0x90,62, 0x91,42, 0,166, 0x90,67, 0x91,43, 0,166, 0x90,64, 0x91,45, 125 | 1,244, 0x90,62, 0,138, 0x80, 0,27, 0x90,62, 0x91,38, 7,208, 0x80, 0x81, 126 | 0xf0 127 | }; 128 | 129 | Arduboy2 arduboy; 130 | ArduboyPlaytune tunes(arduboy.audio.enabled); 131 | 132 | void setup() 133 | { 134 | arduboy.begin(); 135 | 136 | arduboy.setFrameRate(25); 137 | arduboy.setTextSize(3); 138 | 139 | // audio setup 140 | tunes.initChannel(PIN_SPEAKER_1); 141 | #ifndef AB_DEVKIT 142 | // if not a DevKit 143 | tunes.initChannel(PIN_SPEAKER_2); 144 | #else 145 | // if it's a DevKit 146 | tunes.initChannel(PIN_SPEAKER_1); // use the same pin for both channels 147 | tunes.toneMutesScore(true); // mute the score when a tone is sounding 148 | #endif 149 | 150 | arduboy.invert(!arduboy.audio.enabled()); // invert display if sound muted 151 | } 152 | 153 | 154 | int x = 20, y = 10; // initial text position 155 | 156 | void loop() 157 | { 158 | // pause render until it's time for the next frame 159 | if (!(arduboy.nextFrame())) 160 | return; 161 | 162 | if (arduboy.pressed(UP_BUTTON)) { 163 | y-=1; 164 | tunes.tone(1175,300); 165 | } else if (arduboy.pressed(DOWN_BUTTON)) { 166 | y+=1; 167 | tunes.tone(1397,300); 168 | } else if (arduboy.pressed(LEFT_BUTTON)) { 169 | x-=1; 170 | tunes.tone(1047,300); 171 | } else if (arduboy.pressed(RIGHT_BUTTON)) { 172 | x+=1; 173 | tunes.tone(1319,300); 174 | } 175 | 176 | if (arduboy.pressed(A_BUTTON)) { 177 | arduboy.invert(true); 178 | arduboy.audio.off(); 179 | } else if (arduboy.pressed(B_BUTTON)) { 180 | arduboy.invert(false); 181 | arduboy.audio.on(); 182 | } 183 | 184 | arduboy.clear(); 185 | arduboy.setCursor(x,y); 186 | arduboy.print("Music"); 187 | arduboy.setCursor(x+8,y+24); 188 | arduboy.print("Demo"); 189 | arduboy.display(); 190 | 191 | // play the tune if we aren't already 192 | if (!tunes.playing()) 193 | tunes.playScore(score); 194 | } 195 | --------------------------------------------------------------------------------