First Commit
This commit is contained in:
27
libraries/ssd1306/examples/games/arkanoid/arkanoid.h
Normal file
27
libraries/ssd1306/examples/games/arkanoid/arkanoid.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File generated by LCD Assistant
|
||||
// http://en.radzio.dxp.pl/bitmap_converter/
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const unsigned char arkanoid_2 [] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0x60, 0x30, 0x18, 0xFC, 0x00, 0xFC, 0x04, 0xE4,
|
||||
0x28, 0xA4, 0x4C, 0x18, 0xB0, 0xE0, 0x40, 0x00, 0xFC, 0x04, 0xFC, 0x00, 0x00, 0x80, 0xC0, 0x60,
|
||||
0xB0, 0xE0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0x60, 0x30, 0x18, 0xFC, 0x00, 0xFC,
|
||||
0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x04, 0xFC, 0x00, 0x80, 0xE0, 0x30,
|
||||
0xD0, 0x78, 0x28, 0x38, 0x1C, 0x14, 0x14, 0x1C, 0x38, 0x28, 0x78, 0xD0, 0x30, 0xE0, 0x80, 0x00,
|
||||
0xFC, 0x04, 0xFC, 0x00, 0xFC, 0x04, 0xFC, 0x04, 0x0E, 0x9B, 0xF6, 0x0C, 0x98, 0xF0, 0x60, 0x00,
|
||||
|
||||
0x00, 0x30, 0x78, 0xFC, 0xFE, 0xFF, 0xCD, 0x84, 0x02, 0xFC, 0xFE, 0xFF, 0x00, 0xFF, 0x7C, 0x3F,
|
||||
0x1D, 0x1C, 0x3E, 0x7B, 0xF1, 0xE0, 0x40, 0x00, 0xFF, 0x7C, 0x3F, 0x1E, 0x1F, 0x3F, 0x7E, 0xFB,
|
||||
0xF1, 0xE0, 0x40, 0x30, 0x78, 0xFC, 0xFE, 0xFF, 0xCD, 0x84, 0x02, 0xFC, 0xFE, 0xFF, 0x00, 0xFF,
|
||||
0xFC, 0xFE, 0x02, 0x06, 0x0D, 0x1F, 0x3E, 0x7C, 0xF8, 0xFF, 0xFC, 0x7F, 0x00, 0x0F, 0x3C, 0x7F,
|
||||
0x78, 0xF0, 0xE0, 0xE0, 0xC0, 0xC0, 0xC0, 0xC0, 0xE0, 0xE0, 0xF0, 0x78, 0x7F, 0x3C, 0x0F, 0x00,
|
||||
0xFF, 0xFC, 0x7F, 0x00, 0xFF, 0xFC, 0x7F, 0x3E, 0x1F, 0x0D, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01,
|
||||
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
800
libraries/ssd1306/examples/games/arkanoid/arkanoid.ino
Normal file
800
libraries/ssd1306/examples/games/arkanoid/arkanoid.ino
Normal file
@@ -0,0 +1,800 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016-2019, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* This game is based on original game, developed by Ilya Titov in 2014.
|
||||
* It can be still flashed to http://webboggles.com/attiny85-breakout-keychain-game/ HW.
|
||||
*/
|
||||
/*
|
||||
* Attiny85 PINS
|
||||
* ____
|
||||
* RESET -|_| |- 3V
|
||||
* SCL (3) -| |- (2) LEFT
|
||||
* SDA (4) -| |- (1) BUZZER
|
||||
* GND -|____|- (0) RIGHT
|
||||
*
|
||||
*
|
||||
* ATMEL ATMEGA8 & 168 & 328 / ARDUINO NANO
|
||||
*
|
||||
* ____
|
||||
* 10kOm PC6 1|_| |28 PC5
|
||||
* PD0 2| |27 PC4
|
||||
* PD1 3| |26 PC3
|
||||
* RIGHT(D 2) PD2 4| |25 PC2
|
||||
* BUZZ (D 3) PD3 5| |24 PC1
|
||||
* LEFT (D 4) PD4 6| |23 PC0 Z-KEYPAD (A 0) if USE_Z_KEYPAD is defined (refer to buttons.h)
|
||||
* VCC 7| |22 GND
|
||||
* GND 8| |21 AREF
|
||||
* BUZZ (D 6) PB6 9| |20 AVCC
|
||||
* PB7 10| |19 PB5
|
||||
* PD5 11| |18 PB4
|
||||
* PD6 12| |17 PB3
|
||||
* PD7 13| |16 PB2
|
||||
* PB0 14|____|15 PB1
|
||||
*
|
||||
* IMPORTANT!!! D6 is used instead of D3 with SSD1331 display mode
|
||||
*/
|
||||
|
||||
#include "ssd1306.h"
|
||||
#include "intf/ssd1306_interface.h"
|
||||
#include "intf/i2c/ssd1306_i2c.h"
|
||||
#include "lcd/lcd_common.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
//#define ARKANOID_SSD1331
|
||||
#if defined(ESP32) || defined(ESP8266) || (defined(__linux__)) || defined(__MINGW32__)
|
||||
#define DEEP_SLEEP_NOT_SUPPORTED
|
||||
#endif
|
||||
|
||||
#include "levels.h"
|
||||
#include "blocks.h"
|
||||
#include "sprites.h"
|
||||
#include "arkanoid.h"
|
||||
#include "buttons.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SPRITE sprite;
|
||||
uint8_t type;
|
||||
uint8_t extra;
|
||||
} GameObject;
|
||||
|
||||
|
||||
uint16_t *EEPROM_ADDR = (uint16_t*)0;
|
||||
|
||||
#if defined(__AVR_ATtiny45__) | defined(__AVR_ATtiny85__)
|
||||
# define BUZZER 1
|
||||
#else // For Arduino Nano/Atmega328 we use different pins
|
||||
# ifdef ARKANOID_SSD1331
|
||||
# define BUZZER 6
|
||||
# else
|
||||
# define BUZZER 3
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
const int LEFT_EDGE = 0;
|
||||
#ifdef ARKANOID_SSD1331
|
||||
const int RIGHT_EDGE = (96 - 14);
|
||||
const int SCREEN_WIDTH = (96 - 16);
|
||||
const uint8_t OUTPUT_OFFSET = 16;
|
||||
#else
|
||||
const int RIGHT_EDGE = (128 - 14);
|
||||
const int SCREEN_WIDTH = (128 - 16);
|
||||
const uint8_t OUTPUT_OFFSET = 0;
|
||||
#endif
|
||||
const int SCREEN_HEIGHT = 64;
|
||||
const int BLOCK_WIDTH = 16;
|
||||
const int PLATFORM_HEIGHT = 10;
|
||||
const int INITIAL_PLATFORM_WIDTH = 16;
|
||||
const int INITIAL_H_SPEED = -1;
|
||||
const int INITIAL_V_SPEED = -4;
|
||||
const int PLATFORM_SPEED = 1;
|
||||
const int MAX_GAME_OBJECTS = 4;
|
||||
const int PLATFORM_ROW = 7;
|
||||
|
||||
const uint8_t SPEED_SHIFT = 2;
|
||||
|
||||
uint8_t platformPos; // platform position
|
||||
bool updateStatusPanel; // Set to true if status panel update is required
|
||||
static const int platformWidth = INITIAL_PLATFORM_WIDTH;
|
||||
int ballx;
|
||||
int bally;
|
||||
int8_t vSpeed;
|
||||
int8_t hSpeed;
|
||||
uint8_t hearts;
|
||||
uint16_t lastDrawTimestamp;
|
||||
uint8_t gameField[BLOCK_NUM_ROWS][MAX_BLOCKS_PER_ROW];
|
||||
GameObject objects[MAX_GAME_OBJECTS];
|
||||
uint16_t score;
|
||||
uint8_t level = 1;
|
||||
uint8_t blocksLeft = 0;
|
||||
uint8_t platformPower;
|
||||
|
||||
void nextLevel();
|
||||
void beep(int bCount,int bDelay);
|
||||
void movePlatform();
|
||||
bool moveObjects();
|
||||
void drawBall(uint8_t lastx, uint8_t lasty);
|
||||
bool moveBall();
|
||||
void drawObjects();
|
||||
void system_sleep();
|
||||
void onKill();
|
||||
|
||||
static char tempStr[4] = {0};
|
||||
void arkanoidUtoa(uint16_t b)
|
||||
{
|
||||
utoa(b,tempStr,10);
|
||||
}
|
||||
|
||||
|
||||
void drawIntro()
|
||||
{
|
||||
#ifdef ARKANOID_SSD1331
|
||||
ssd1331_96x64_spi_init(3,4,5);
|
||||
#elif defined(__AVR_ATtiny85__)
|
||||
ssd1306_i2cInitEx(-1,-1,0);
|
||||
#elif defined(CONFIG_SOFTWARE_I2C_AVAILABLE)
|
||||
ssd1306_i2cInit_Embedded(-1,-1,0);
|
||||
#elif defined(CONFIG_PLATFORM_I2C_AVAILABLE)
|
||||
ssd1306_platform_i2cInit(-1,0,-1);
|
||||
#elif defined(CONFIG_TWI_I2C_AVAILABLE)
|
||||
ssd1306_i2cInit_Twi(0);
|
||||
#else
|
||||
#error "Not supported microcontroller or board"
|
||||
#endif
|
||||
#ifndef ARKANOID_SSD1331
|
||||
ssd1306_128x64_init();
|
||||
#endif
|
||||
ssd1306_clearScreen( );
|
||||
ssd1306_setColor(RGB_COLOR8(255,0,0));
|
||||
for (int8_t y=-24; y<16; y++)
|
||||
{
|
||||
gfx_drawMonoBitmap(16 - OUTPUT_OFFSET, y, 96, 24, arkanoid_2);
|
||||
delay(20);
|
||||
}
|
||||
ssd1306_setColor(RGB_COLOR8(255,255,0));
|
||||
ssd1306_printFixed_oldStyle(40 - OUTPUT_OFFSET, 40, "BREAKOUT", STYLE_NORMAL);
|
||||
beep(200,600);
|
||||
beep(300,200);
|
||||
beep(400,300);
|
||||
}
|
||||
|
||||
void drawStatusPanel()
|
||||
{
|
||||
ssd1306_setColor(RGB_COLOR8(255,0,0));
|
||||
for(uint8_t i=0; i<min(hearts,3); i++)
|
||||
{
|
||||
SPRITE heart = ssd1306_createSprite( RIGHT_EDGE + 4, 16 + (i<<3), 8, heartSprite );
|
||||
heart.draw();
|
||||
}
|
||||
ssd1306_setColor(RGB_COLOR8(255,255,0));
|
||||
arkanoidUtoa(score);
|
||||
tempStr[2] = '\0';
|
||||
ssd1306_printFixed_oldStyle(RIGHT_EDGE + 1, 8, tempStr, STYLE_NORMAL);
|
||||
ssd1306_setColor(RGB_COLOR8(0,255,255));
|
||||
SPRITE power = ssd1306_createSprite( RIGHT_EDGE + 4, 40, 8, powerSprite );
|
||||
if (platformPower)
|
||||
power.draw();
|
||||
else
|
||||
power.erase();
|
||||
}
|
||||
|
||||
/* Draws and clears platform */
|
||||
void drawPlatform()
|
||||
{
|
||||
uint8_t pos = (platformPos < PLATFORM_SPEED) ? 0: (platformPos - PLATFORM_SPEED);
|
||||
ssd1306_setColor(RGB_COLOR8(255,255,0));
|
||||
ssd1306_lcd.set_block( pos + LEFT_EDGE + 1, PLATFORM_ROW, platformWidth + PLATFORM_SPEED * 2 );
|
||||
while (pos < platformPos)
|
||||
{
|
||||
ssd1306_lcd.send_pixels1(0B00000000);
|
||||
pos++;
|
||||
}
|
||||
ssd1306_lcd.send_pixels1(0B00001110);
|
||||
pos++;
|
||||
while (pos < platformPos + platformWidth - 1)
|
||||
{
|
||||
ssd1306_lcd.send_pixels1(0B00000111);
|
||||
pos++;
|
||||
}
|
||||
ssd1306_lcd.send_pixels1(0B00001110);
|
||||
while (pos < platformPos + platformWidth + PLATFORM_SPEED - 1)
|
||||
{
|
||||
if (pos >= (RIGHT_EDGE - LEFT_EDGE - 2))
|
||||
{
|
||||
break;
|
||||
}
|
||||
ssd1306_lcd.send_pixels1(0B00000000);
|
||||
pos++;
|
||||
}
|
||||
ssd1306_intf.stop();
|
||||
}
|
||||
|
||||
void drawFieldEdges()
|
||||
{
|
||||
uint8_t i=8;
|
||||
ssd1306_setColor(RGB_COLOR8(255,0,0));
|
||||
while (i)
|
||||
{
|
||||
i--;
|
||||
ssd1306_lcd.set_block(LEFT_EDGE, i, 1);
|
||||
ssd1306_lcd.send_pixels1( 0B01010101 );
|
||||
ssd1306_intf.stop();
|
||||
ssd1306_lcd.set_block(RIGHT_EDGE, i, 1);
|
||||
ssd1306_lcd.send_pixels1( 0B01010101 );
|
||||
ssd1306_intf.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void drawBlock(uint8_t x, uint8_t y)
|
||||
{
|
||||
uint8_t block = gameField[y][x];
|
||||
switch(block)
|
||||
{
|
||||
case 1: ssd1306_setColor(RGB_COLOR8(64,64,255)); break;
|
||||
case 2: ssd1306_setColor(RGB_COLOR8(64,255,255)); break;
|
||||
case 3: ssd1306_setColor(RGB_COLOR8(64,255,64)); break;
|
||||
default: ssd1306_setColor(RGB_COLOR8(64,64,255)); break;
|
||||
}
|
||||
ssd1306_drawSpriteEx(LEFT_EDGE + 1 + (x << 4), y, 16, &blockImages[block][0]);
|
||||
}
|
||||
|
||||
|
||||
void resetBlocks()
|
||||
{
|
||||
if (level > MAX_LEVELS)
|
||||
{
|
||||
level = MAX_LEVELS;
|
||||
}
|
||||
blocksLeft = 0;
|
||||
for (uint8_t i =0; i<BLOCKS_PER_ROW; i++)
|
||||
{
|
||||
for (uint8_t j=0; j<BLOCK_NUM_ROWS; j++)
|
||||
{
|
||||
gameField[j][i] = pgm_read_byte( &levels[level-1][j][i] );
|
||||
if ((gameField[j][i]) && (gameField[j][i] != BLOCK_STRONG))
|
||||
{
|
||||
blocksLeft++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawBlocks()
|
||||
{
|
||||
for (uint8_t r=0; r<BLOCK_NUM_ROWS; r++)
|
||||
{
|
||||
for (uint8_t bl = 0; bl<BLOCKS_PER_ROW; bl++)
|
||||
{
|
||||
drawBlock(bl, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawStartScreen()
|
||||
{
|
||||
ssd1306_clearScreen( );
|
||||
drawBlocks();
|
||||
drawFieldEdges();
|
||||
updateStatusPanel = true;
|
||||
}
|
||||
|
||||
void startLevel()
|
||||
{
|
||||
ssd1306_setColor(RGB_COLOR8(255,128,0));
|
||||
arkanoidUtoa(level);
|
||||
ssd1306_clearScreen();
|
||||
ssd1306_printFixed_oldStyle(40 - OUTPUT_OFFSET, 24, "LEVEL ", STYLE_BOLD);
|
||||
ssd1306_printFixed_oldStyle(76 - OUTPUT_OFFSET, 24, tempStr, STYLE_BOLD);
|
||||
delay(2000);
|
||||
resetBlocks();
|
||||
hSpeed = INITIAL_H_SPEED;
|
||||
vSpeed = INITIAL_V_SPEED;
|
||||
platformPos = random(0, (RIGHT_EDGE - LEFT_EDGE - 1 - platformWidth));
|
||||
ballx = ( platformPos + ( platformWidth >> 1 ) ) << SPEED_SHIFT;
|
||||
bally = ( SCREEN_HEIGHT - PLATFORM_HEIGHT ) << SPEED_SHIFT;
|
||||
memset(&objects[0], 0, sizeof(objects));
|
||||
drawStartScreen();
|
||||
lastDrawTimestamp = millis();
|
||||
}
|
||||
|
||||
void resetGame()
|
||||
{
|
||||
score = 0;
|
||||
// platformWidth = INITIAL_PLATFORM_WIDTH;
|
||||
platformPower = 0;
|
||||
hearts = 2;
|
||||
drawIntro();
|
||||
delay(3000);
|
||||
startLevel();
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
ssd1306_setFixedFont_oldStyle(ssd1306xled_font6x8_AB);
|
||||
randomSeed(analogRead(0));
|
||||
#if defined(CONFIG_PLATFORM_I2C_AVAILABLE)
|
||||
// no need to do anything here
|
||||
#elif defined(ARKANOID_SSD1331)
|
||||
#ifndef USE_Z_KEYPAD
|
||||
pinMode(LEFT_BTN, INPUT);
|
||||
pinMode(RIGHT_BTN, INPUT);
|
||||
#endif
|
||||
pinMode(BUZZER, OUTPUT);
|
||||
sei(); // enable all interrupts
|
||||
#elif defined(__AVR_ATtiny85__)
|
||||
DDRB |= 0b00011010; // set PB1 as output (for the speaker), PB0 and PB2 as input
|
||||
sei(); // enable all interrupts
|
||||
#elif defined(CONFIG_ARDUINO_WIRE_LIBRARY_AVAILABLE)
|
||||
Wire.begin();
|
||||
#ifdef SSD1306_WIRE_CLOCK_CONFIGURABLE
|
||||
Wire.setClock( 400000 );
|
||||
#endif
|
||||
#ifndef USE_Z_KEYPAD
|
||||
pinMode(LEFT_BTN, INPUT);
|
||||
pinMode(RIGHT_BTN, INPUT);
|
||||
#endif
|
||||
pinMode(BUZZER, OUTPUT);
|
||||
sei(); // enable all interrupts
|
||||
#elif defined(CONFIG_SOFTWARE_I2C_AVAILABLE)
|
||||
#ifndef USE_Z_KEYPAD
|
||||
pinMode(LEFT_BTN, INPUT);
|
||||
pinMode(RIGHT_BTN, INPUT);
|
||||
#endif
|
||||
pinMode(BUZZER, OUTPUT);
|
||||
sei(); // enable all interrupts
|
||||
#else
|
||||
#error "Not supported microcontroller or board"
|
||||
#endif
|
||||
resetGame();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if ( (uint16_t)(((uint16_t)millis()) - lastDrawTimestamp) > 28 )
|
||||
{
|
||||
uint8_t lastx = (ballx >> SPEED_SHIFT);
|
||||
uint8_t lasty = (bally >> SPEED_SHIFT);
|
||||
lastDrawTimestamp += 28;
|
||||
// continue moving after the interrupt
|
||||
movePlatform();
|
||||
// bounce off the sides of the screen
|
||||
if (moveBall())
|
||||
{
|
||||
if (moveObjects())
|
||||
{
|
||||
// update whats on the screen
|
||||
drawPlatform();
|
||||
drawBall(lastx, lasty);
|
||||
drawObjects();
|
||||
}
|
||||
}
|
||||
if (updateStatusPanel)
|
||||
{
|
||||
updateStatusPanel = false;
|
||||
drawStatusPanel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawBall(uint8_t lastx, uint8_t lasty)
|
||||
{
|
||||
uint8_t newx = ballx >> SPEED_SHIFT;
|
||||
uint8_t newy = bally >> SPEED_SHIFT;
|
||||
uint8_t temp;
|
||||
temp = 0B00000001 << (newy & 0x07);
|
||||
ssd1306_setColor(RGB_COLOR8(255,255,255));
|
||||
ssd1306_lcd.set_block(LEFT_EDGE + 1 + newx, newy >> 3, 1);
|
||||
ssd1306_lcd.send_pixels1( temp );
|
||||
ssd1306_intf.stop();
|
||||
if ((newx != lastx) || ((newy >> 3) != (lasty >> 3)))
|
||||
{
|
||||
ssd1306_lcd.set_block(LEFT_EDGE + 1 + lastx, lasty >> 3, 1);
|
||||
ssd1306_lcd.send_pixels1( 0B00000000 );
|
||||
ssd1306_intf.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void drawObjects()
|
||||
{
|
||||
ssd1306_setColor(RGB_COLOR8(255,0,192));
|
||||
for(uint8_t i=0; i<MAX_GAME_OBJECTS; i++)
|
||||
{
|
||||
if (objects[i].type == 0)
|
||||
{
|
||||
}
|
||||
else if (objects[i].type == 1)
|
||||
{
|
||||
objects[i].sprite.erase();
|
||||
objects[i].type = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
objects[i].sprite.eraseTrace();
|
||||
objects[i].sprite.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t freeObject()
|
||||
{
|
||||
for(uint8_t i=0; i<MAX_GAME_OBJECTS; i++)
|
||||
{
|
||||
if (objects[i].type == 0) return i;
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
|
||||
bool platformHit(uint8_t x, uint8_t y)
|
||||
{
|
||||
if (y >= (SCREEN_HEIGHT - PLATFORM_HEIGHT))
|
||||
{
|
||||
if ((x >= platformPos) && (x <= platformPos + platformWidth))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
BLOCK_HIT_NONE,
|
||||
BLOCK_HIT_UNBREAKABLE,
|
||||
BLOCK_HIT_BREAKABLE,
|
||||
BLOCK_HIT_LEVEL_DONE,
|
||||
};
|
||||
|
||||
uint8_t blockHit(uint8_t x, uint8_t y)
|
||||
{
|
||||
uint8_t ball_row = y>>3;
|
||||
if (ball_row < BLOCK_NUM_ROWS)
|
||||
{
|
||||
uint8_t ball_col = x >> 4;
|
||||
uint8_t blockType = gameField[ball_row][ball_col];
|
||||
if ( blockType > 0 )
|
||||
{
|
||||
if (blockType != BLOCK_STRONG)
|
||||
{
|
||||
gameField[ball_row][ball_col] = 0;
|
||||
score++;
|
||||
blocksLeft--;
|
||||
drawBlock(ball_col, ball_row);
|
||||
updateStatusPanel = true;
|
||||
if (blockType >= BLOCK_BONUS)
|
||||
{
|
||||
uint8_t i = freeObject();
|
||||
if (i != 0xFF)
|
||||
{
|
||||
objects[i].sprite = ssd1306_createSprite( (ball_col << 4) + 6,
|
||||
(ball_row << 3),
|
||||
5,
|
||||
&bonusSprites[blockType - BLOCK_BONUS][0] );
|
||||
objects[i].extra = 0;
|
||||
objects[i].type = blockType;
|
||||
}
|
||||
}
|
||||
}
|
||||
// reset blocks if all have been hit
|
||||
if (blocksLeft == 0)
|
||||
{
|
||||
level++;
|
||||
startLevel();
|
||||
return BLOCK_HIT_LEVEL_DONE;
|
||||
}
|
||||
return (blockType == BLOCK_STRONG ? BLOCK_HIT_UNBREAKABLE : BLOCK_HIT_BREAKABLE);
|
||||
}
|
||||
}
|
||||
return BLOCK_HIT_NONE;
|
||||
}
|
||||
|
||||
|
||||
bool moveObjects()
|
||||
{
|
||||
for(uint8_t i=0; i<MAX_GAME_OBJECTS; i++)
|
||||
{
|
||||
if (objects[i].type <= 1)
|
||||
{
|
||||
}
|
||||
else if (objects[i].type < BLOCKS_MAX)
|
||||
{
|
||||
if (objects[i].sprite.y >= (SCREEN_HEIGHT - PLATFORM_HEIGHT - 4))
|
||||
{
|
||||
objects[i].type = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (objects[i].extra-- == 0)
|
||||
{
|
||||
objects[i].extra = 1;
|
||||
if (platformHit(objects[i].sprite.x + 3, objects[i].sprite.y + 8))
|
||||
{
|
||||
if (objects[i].type == BLOCK_BOMB)
|
||||
{
|
||||
onKill();
|
||||
return false;
|
||||
}
|
||||
else if (objects[i].type == BLOCK_HEART)
|
||||
{
|
||||
hearts++;
|
||||
updateStatusPanel = true;
|
||||
}
|
||||
else if (objects[i].type == BLOCK_POWER)
|
||||
{
|
||||
platformPower = 255;
|
||||
updateStatusPanel = true;
|
||||
}
|
||||
objects[i].type = 1;
|
||||
}
|
||||
objects[i].sprite.y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (objects[i].type == 0xFF)
|
||||
{
|
||||
if (objects[i].sprite.y <= 1)
|
||||
{
|
||||
objects[i].type = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t hitType = blockHit( objects[i].sprite.x, objects[i].sprite.y - 1 );
|
||||
if (hitType != BLOCK_HIT_NONE)
|
||||
{
|
||||
if (hitType == BLOCK_HIT_LEVEL_DONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
objects[i].type = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
objects[i].sprite.y -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// continues moving after interrupt
|
||||
void movePlatform()
|
||||
{
|
||||
// Use A0 ADC input (channel 0) if Z_KEYPAD is attached
|
||||
uint8_t buttonCode = getPressedButton(0);
|
||||
if (buttonCode == BUTTON_RIGHT)
|
||||
{
|
||||
platformPos = min(RIGHT_EDGE - LEFT_EDGE - 1 - platformWidth, platformPos + PLATFORM_SPEED);
|
||||
}
|
||||
if (buttonCode == BUTTON_LEFT)
|
||||
{
|
||||
platformPos = max(0, platformPos - PLATFORM_SPEED);
|
||||
}
|
||||
if (platformPower != 0)
|
||||
{
|
||||
platformPower--;
|
||||
if (!(platformPower & 0x1F))
|
||||
{
|
||||
uint8_t i = freeObject();
|
||||
if (i != 0xFF)
|
||||
{
|
||||
objects[i].sprite = ssd1306_createSprite( platformPos + (platformWidth >> 1),
|
||||
SCREEN_HEIGHT - PLATFORM_HEIGHT - 8,
|
||||
1,
|
||||
shootSprite );
|
||||
objects[i].extra = 0;
|
||||
objects[i].type = 0xFF;
|
||||
}
|
||||
}
|
||||
if (platformPower == 0) updateStatusPanel = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void gameOver()
|
||||
{
|
||||
ssd1306_setColor(RGB_COLOR8(255,255,255));
|
||||
#if defined(ESP32) || defined(ESP8266)
|
||||
uint16_t topScore = score;
|
||||
#else
|
||||
uint16_t topScore = eeprom_read_word(EEPROM_ADDR);
|
||||
if (topScore == 0xFFFF)
|
||||
{
|
||||
eeprom_write_word(EEPROM_ADDR, 0);
|
||||
topScore = 0;
|
||||
}
|
||||
if (score>topScore)
|
||||
{
|
||||
topScore = score;
|
||||
eeprom_write_word(EEPROM_ADDR, topScore);
|
||||
}
|
||||
#endif
|
||||
ssd1306_clearScreen( );
|
||||
ssd1306_printFixed_oldStyle(32 - OUTPUT_OFFSET, 16, "GAME OVER", STYLE_NORMAL);
|
||||
ssd1306_printFixed_oldStyle(32 - OUTPUT_OFFSET, 32, "SCORE ", STYLE_NORMAL);
|
||||
arkanoidUtoa(score);
|
||||
ssd1306_printFixed_oldStyle(70 - OUTPUT_OFFSET, 32, tempStr, STYLE_NORMAL);
|
||||
ssd1306_printFixed_oldStyle(32 - OUTPUT_OFFSET, 40, "TOP SCORE ", STYLE_NORMAL);
|
||||
arkanoidUtoa(topScore);
|
||||
ssd1306_printFixed_oldStyle(90 - OUTPUT_OFFSET, 40, tempStr, STYLE_NORMAL);
|
||||
for (int i = 0; i<1000; i++)
|
||||
{
|
||||
beep(1,random(0,i*2));
|
||||
}
|
||||
delay(2000);
|
||||
}
|
||||
|
||||
void platformCrashAnimation()
|
||||
{
|
||||
for (uint8_t j = 4; j > 0; j--)
|
||||
{
|
||||
for ( uint8_t i = 0; i < platformWidth >> 2; i++ )
|
||||
{
|
||||
ssd1306_lcd.set_block( platformPos + ((j & 0x01)<<1) + ((j & 0x02)>>1) + (i<<2) + LEFT_EDGE + 1, PLATFORM_ROW, platformWidth );
|
||||
ssd1306_lcd.send_pixels1( 0B00000000 );
|
||||
ssd1306_intf.stop();
|
||||
}
|
||||
delay(150);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void onKill()
|
||||
{
|
||||
platformCrashAnimation();
|
||||
if (hearts == 0)
|
||||
{
|
||||
// game over if the ball misses the platform
|
||||
gameOver();
|
||||
system_sleep();
|
||||
level = 1;
|
||||
resetGame();
|
||||
}
|
||||
else
|
||||
{
|
||||
hearts--;
|
||||
startLevel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// the collsision check is actually done before this is called, this code works
|
||||
// out where the ball will bounce
|
||||
void collision(uint8_t partx, uint8_t party)
|
||||
{
|
||||
/* botton / top collision */
|
||||
if ((party <= 0) || (party >= 7))
|
||||
{
|
||||
vSpeed = -vSpeed;
|
||||
}
|
||||
else if ((partx <= 0) || (partx >= 15))
|
||||
{
|
||||
hSpeed = -hSpeed;
|
||||
}
|
||||
beep(30,300);
|
||||
}
|
||||
|
||||
|
||||
// move and bounce the ball when reaches the screen limits
|
||||
bool moveBall()
|
||||
{
|
||||
uint8_t nextx = (ballx + hSpeed) >> SPEED_SHIFT;
|
||||
uint8_t nexty = (bally + vSpeed) >> SPEED_SHIFT;
|
||||
/* checkplatform Hit */
|
||||
if (platformHit(nextx, nexty))
|
||||
{
|
||||
int middle = platformPos + (platformWidth >> 1);
|
||||
hSpeed = (nextx - middle) / (platformWidth >> (SPEED_SHIFT + 1));
|
||||
vSpeed = -max(4 - abs(hSpeed), 2);
|
||||
beep(20,600);
|
||||
}
|
||||
/* Check screen hit */
|
||||
nextx = (ballx + hSpeed) >> SPEED_SHIFT;
|
||||
nexty = (bally + vSpeed) >> SPEED_SHIFT;
|
||||
if ((nextx <= 0) || (nextx >= RIGHT_EDGE - LEFT_EDGE - 1))
|
||||
{
|
||||
hSpeed = -hSpeed;
|
||||
}
|
||||
if (nexty <= 0)
|
||||
{
|
||||
vSpeed = -vSpeed;
|
||||
}
|
||||
/* Check game over */
|
||||
if (nexty >=(SCREEN_HEIGHT - PLATFORM_HEIGHT + 2))
|
||||
{
|
||||
onKill();
|
||||
return false;
|
||||
}
|
||||
ballx += hSpeed;
|
||||
bally += vSpeed;
|
||||
/* Check bar hit */
|
||||
uint8_t hitType = blockHit( ballx >> SPEED_SHIFT, bally >> SPEED_SHIFT );
|
||||
if (hitType != BLOCK_HIT_NONE)
|
||||
{
|
||||
if (hitType == BLOCK_HIT_LEVEL_DONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (hitType == BLOCK_HIT_UNBREAKABLE)
|
||||
{
|
||||
ballx -= hSpeed;
|
||||
bally -= vSpeed;
|
||||
}
|
||||
uint8_t partx = (ballx >> SPEED_SHIFT) & 0x0F;
|
||||
uint8_t party = (bally >> SPEED_SHIFT) & 0x07;
|
||||
collision(partx, party);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void beep(int bCount,int bDelay)
|
||||
{
|
||||
for (int i = bCount*2; i>0; i--)
|
||||
{
|
||||
digitalWrite(BUZZER, i & 1);
|
||||
for(int i2 = 0; i2 < bDelay; i2++)
|
||||
{
|
||||
__asm__("nop\n\t");
|
||||
#if F_CPU > 8000000
|
||||
__asm__("nop\n\t");
|
||||
__asm__("nop\n\t");
|
||||
__asm__("nop\n\t");
|
||||
__asm__("nop\n\t");
|
||||
__asm__("nop\n\t");
|
||||
__asm__("nop\n\t");
|
||||
__asm__("nop\n\t");
|
||||
__asm__("nop\n\t");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
digitalWrite(BUZZER,LOW);
|
||||
}
|
||||
|
||||
#ifdef DEEP_SLEEP_NOT_SUPPORTED
|
||||
|
||||
void system_sleep()
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
void system_sleep()
|
||||
{
|
||||
ssd1306_clearScreen( );
|
||||
ssd1306_displayOff();
|
||||
ADCSRA &= ~(1<<ADEN);
|
||||
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
|
||||
sleep_enable();
|
||||
sleep_mode(); // System actually sleeps here
|
||||
sleep_disable(); // System continues execution here when watchdog timed out
|
||||
ADCSRA |= (1<<ADEN);
|
||||
ssd1306_displayOn();
|
||||
}
|
||||
#endif
|
||||
|
||||
171
libraries/ssd1306/examples/games/arkanoid/blocks.h
Normal file
171
libraries/ssd1306/examples/games/arkanoid/blocks.h
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
enum
|
||||
{
|
||||
NO_BLOCK, // 0
|
||||
BLOCK_SIMPLE, // 1
|
||||
BLOCK_DASHED, // 2
|
||||
BLOCK_STRONG, // 3
|
||||
|
||||
BLOCK_BOMB, // 4
|
||||
BLOCK_HEART, // 5
|
||||
BLOCK_POWER, // 6
|
||||
BLOCKS_MAX,
|
||||
BLOCK_BONUS = BLOCK_BOMB,
|
||||
};
|
||||
|
||||
|
||||
const PROGMEM uint8_t blockImages[BLOCKS_MAX][16] =
|
||||
{
|
||||
{ /* EMPTY */
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000
|
||||
},
|
||||
{ /* SIMPLE 1 */
|
||||
0B00000000,
|
||||
0B00111100,
|
||||
0B01111110,
|
||||
0B01100110,
|
||||
0B01100110,
|
||||
0B01100110,
|
||||
0B01100110,
|
||||
0B01100110,
|
||||
0B01100110,
|
||||
0B01100110,
|
||||
0B01100110,
|
||||
0B01100110,
|
||||
0B01100110,
|
||||
0B01111110,
|
||||
0B00111100,
|
||||
0B00000000
|
||||
},
|
||||
{ /* DASHED 2 */
|
||||
0B00000000,
|
||||
0B00111100,
|
||||
0B01010010,
|
||||
0B01001010,
|
||||
0B01100110,
|
||||
0B01010010,
|
||||
0B01001010,
|
||||
0B01100110,
|
||||
0B01010010,
|
||||
0B01001010,
|
||||
0B01100110,
|
||||
0B01010010,
|
||||
0B01001010,
|
||||
0B01100110,
|
||||
0B00111100,
|
||||
0B00000000
|
||||
},
|
||||
{ /* STRONG 3 */
|
||||
0B00000000,
|
||||
0B00111100,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B00111100,
|
||||
0B00000000
|
||||
},
|
||||
{ /* BOMB 4 */
|
||||
0B00000000,
|
||||
0B00111100,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01011010,
|
||||
0B01011010,
|
||||
0B01100110,
|
||||
0B01100110,
|
||||
0B01011010,
|
||||
0B01011010,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111010,
|
||||
0B01110110,
|
||||
0B00111100,
|
||||
0B00000000
|
||||
},
|
||||
{ /* HEART 5 */
|
||||
0B00000000,
|
||||
0B00111100,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01110110,
|
||||
0B01100010,
|
||||
0B01000110,
|
||||
0B01100010,
|
||||
0B01110110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B00111100,
|
||||
0B00000000
|
||||
},
|
||||
{ /* POWER 6 */
|
||||
0B00000000,
|
||||
0B00111100,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01000010,
|
||||
0B01101010,
|
||||
0B01101010,
|
||||
0B01101010,
|
||||
0B01101010,
|
||||
0B01110110,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B01111010,
|
||||
0B01110110,
|
||||
0B00111100,
|
||||
0B00000000
|
||||
},
|
||||
};
|
||||
|
||||
43
libraries/ssd1306/examples/games/arkanoid/buttons.cpp
Normal file
43
libraries/ssd1306/examples/games/arkanoid/buttons.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "buttons.h"
|
||||
|
||||
#include "ssd1306.h"
|
||||
|
||||
uint8_t getPressedButton(uint8_t analogPin)
|
||||
{
|
||||
#ifdef USE_Z_KEYPAD
|
||||
int buttonValue = analogRead(analogPin);
|
||||
if (buttonValue < 100) return BUTTON_RIGHT;
|
||||
if (buttonValue < 200) return BUTTON_UP;
|
||||
if (buttonValue < 400) return BUTTON_DOWN;
|
||||
if (buttonValue < 600) return BUTTON_LEFT;
|
||||
if (buttonValue < 800) return BUTTON_SELECT;
|
||||
#else
|
||||
if (digitalRead(RIGHT_BTN) != LOW) return BUTTON_RIGHT;
|
||||
if (digitalRead(LEFT_BTN) != LOW) return BUTTON_LEFT;
|
||||
#endif
|
||||
return BUTTON_NONE;
|
||||
}
|
||||
48
libraries/ssd1306/examples/games/arkanoid/buttons.h
Normal file
48
libraries/ssd1306/examples/games/arkanoid/buttons.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__AVR_ATtiny45__) | defined(__AVR_ATtiny85__)
|
||||
# define LEFT_BTN 2
|
||||
# define RIGHT_BTN 0
|
||||
#else // For Arduino Nano/Atmega328 we use different pins
|
||||
# define USE_Z_KEYPAD // use analog Z-keypad ADC module on A0 pin.
|
||||
# ifndef USE_Z_KEYPAD
|
||||
# define LEFT_BTN 4
|
||||
# define RIGHT_BTN 2
|
||||
# endif
|
||||
#endif
|
||||
|
||||
const uint8_t BUTTON_NONE = 0;
|
||||
const uint8_t BUTTON_RIGHT = 1;
|
||||
const uint8_t BUTTON_UP = 2;
|
||||
const uint8_t BUTTON_DOWN = 3;
|
||||
const uint8_t BUTTON_LEFT = 4;
|
||||
const uint8_t BUTTON_SELECT = 5;
|
||||
|
||||
uint8_t getPressedButton(uint8_t analogPin);
|
||||
|
||||
82
libraries/ssd1306/examples/games/arkanoid/levels.h
Normal file
82
libraries/ssd1306/examples/games/arkanoid/levels.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2019, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
const int MAX_LEVELS = 5;
|
||||
#ifdef ARKANOID_SSD1331
|
||||
const int BLOCKS_PER_ROW = 5;
|
||||
#else
|
||||
const int BLOCKS_PER_ROW = 7;
|
||||
#endif
|
||||
const int MAX_BLOCKS_PER_ROW = 8;
|
||||
const int BLOCK_NUM_ROWS = 3;
|
||||
|
||||
|
||||
const PROGMEM uint8_t levels[MAX_LEVELS][BLOCK_NUM_ROWS][MAX_BLOCKS_PER_ROW] =
|
||||
{
|
||||
{
|
||||
{ 1,1,1,1,1,1,1,0 },
|
||||
{ 0,2,2,2,2,2,0,0 },
|
||||
{ 0,0,0,0,0,0,0,0 }
|
||||
},
|
||||
{
|
||||
{ 0,3,3,3,3,3,0,0 },
|
||||
{ 0,1,2,2,2,1,0,0 },
|
||||
{ 0,0,1,1,1,0,0,0 }
|
||||
},
|
||||
{
|
||||
{ 2,1,3,1,3,1,2,0 },
|
||||
{ 0,2,2,5,2,2,0,0 },
|
||||
{ 2,1,1,1,1,1,2,0 }
|
||||
},
|
||||
{
|
||||
{ 2,1,4,3,3,4,2,0 },
|
||||
{ 1,2,2,2,2,2,1,0 },
|
||||
{ 0,3,3,3,3,3,0,0 }
|
||||
},
|
||||
{
|
||||
{ 0,0,1,0,1,0,0,0 },
|
||||
{ 0,1,2,6,2,1,0,0 },
|
||||
{ 0,0,1,5,1,0,0,0 }
|
||||
},
|
||||
#if 0
|
||||
{
|
||||
{ 0,4,0,4,0,4,0,0 },
|
||||
{ 4,5,4,5,4,5,4,0 },
|
||||
{ 0,4,0,4,0,4,0,0 }
|
||||
},
|
||||
{
|
||||
{ 2,1,1,5,1,1,2,0 },
|
||||
{ 2,6,4,1,4,6,2,0 },
|
||||
{ 2,3,0,0,0,3,2,0 }
|
||||
},
|
||||
{
|
||||
{ 0,0,0,0,0,0,0,0 },
|
||||
{ 0,0,0,0,0,0,0,0 },
|
||||
{ 0,0,0,0,0,0,0,0 }
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 75 KiB |
BIN
libraries/ssd1306/examples/games/arkanoid/schematics/case.3mf
Normal file
BIN
libraries/ssd1306/examples/games/arkanoid/schematics/case.3mf
Normal file
Binary file not shown.
83
libraries/ssd1306/examples/games/arkanoid/sprites.h
Normal file
83
libraries/ssd1306/examples/games/arkanoid/sprites.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
const PROGMEM uint8_t heartSprite[8] =
|
||||
{
|
||||
0B00001110,
|
||||
0B00011111,
|
||||
0B00111111,
|
||||
0B01111110,
|
||||
0B01111110,
|
||||
0B00111101,
|
||||
0B00011001,
|
||||
0B00001110
|
||||
};
|
||||
|
||||
|
||||
const PROGMEM uint8_t powerSprite[8] =
|
||||
{
|
||||
0B11001110,
|
||||
0B11111110,
|
||||
0B00111110,
|
||||
0B00010110,
|
||||
0B00001110,
|
||||
0B00001110,
|
||||
0B00001111,
|
||||
0B00001110
|
||||
};
|
||||
|
||||
|
||||
const PROGMEM uint8_t shootSprite[1] =
|
||||
{
|
||||
0B00111100,
|
||||
};
|
||||
|
||||
const PROGMEM uint8_t bonusSprites[][5] =
|
||||
{
|
||||
{ /* BLOCK_BOMB */
|
||||
0B01111001,
|
||||
0B11111110,
|
||||
0B11101110,
|
||||
0B01111001,
|
||||
0B00000000,
|
||||
},
|
||||
{ /* BLOCK_HEART */
|
||||
0B00011100,
|
||||
0B00111110,
|
||||
0B01111100,
|
||||
0B00111010,
|
||||
0B00011100,
|
||||
},
|
||||
{ /* BLOCK_POWER */
|
||||
0B00000000,
|
||||
0B01111110,
|
||||
0B00010010,
|
||||
0B00010010,
|
||||
0B00001100,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
27
libraries/ssd1306/examples/games/arkanoid8/arkanoid.h
Normal file
27
libraries/ssd1306/examples/games/arkanoid8/arkanoid.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File generated by LCD Assistant
|
||||
// http://en.radzio.dxp.pl/bitmap_converter/
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const unsigned char arkanoid_2 [] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0x60, 0x30, 0x18, 0xFC, 0x00, 0xFC, 0x04, 0xE4,
|
||||
0x28, 0xA4, 0x4C, 0x18, 0xB0, 0xE0, 0x40, 0x00, 0xFC, 0x04, 0xFC, 0x00, 0x00, 0x80, 0xC0, 0x60,
|
||||
0xB0, 0xE0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0x60, 0x30, 0x18, 0xFC, 0x00, 0xFC,
|
||||
0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x04, 0xFC, 0x00, 0x80, 0xE0, 0x30,
|
||||
0xD0, 0x78, 0x28, 0x38, 0x1C, 0x14, 0x14, 0x1C, 0x38, 0x28, 0x78, 0xD0, 0x30, 0xE0, 0x80, 0x00,
|
||||
0xFC, 0x04, 0xFC, 0x00, 0xFC, 0x04, 0xFC, 0x04, 0x0E, 0x9B, 0xF6, 0x0C, 0x98, 0xF0, 0x60, 0x00,
|
||||
|
||||
0x00, 0x30, 0x78, 0xFC, 0xFE, 0xFF, 0xCD, 0x84, 0x02, 0xFC, 0xFE, 0xFF, 0x00, 0xFF, 0x7C, 0x3F,
|
||||
0x1D, 0x1C, 0x3E, 0x7B, 0xF1, 0xE0, 0x40, 0x00, 0xFF, 0x7C, 0x3F, 0x1E, 0x1F, 0x3F, 0x7E, 0xFB,
|
||||
0xF1, 0xE0, 0x40, 0x30, 0x78, 0xFC, 0xFE, 0xFF, 0xCD, 0x84, 0x02, 0xFC, 0xFE, 0xFF, 0x00, 0xFF,
|
||||
0xFC, 0xFE, 0x02, 0x06, 0x0D, 0x1F, 0x3E, 0x7C, 0xF8, 0xFF, 0xFC, 0x7F, 0x00, 0x0F, 0x3C, 0x7F,
|
||||
0x78, 0xF0, 0xE0, 0xE0, 0xC0, 0xC0, 0xC0, 0xC0, 0xE0, 0xE0, 0xF0, 0x78, 0x7F, 0x3C, 0x0F, 0x00,
|
||||
0xFF, 0xFC, 0x7F, 0x00, 0xFF, 0xFC, 0x7F, 0x3E, 0x1F, 0x0D, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x03, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01,
|
||||
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
375
libraries/ssd1306/examples/games/arkanoid8/arkanoid8.ino
Normal file
375
libraries/ssd1306/examples/games/arkanoid8/arkanoid8.ino
Normal file
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* Nano/Atmega328 PINS: connect LCD to D5 (D/C), D4 (CS), D3 (RES), D11(DIN), D13(CLK)
|
||||
* Attiny SPI PINS: connect LCD to D4 (D/C), GND (CS), D3 (RES), D1(DIN), D2(CLK)
|
||||
* ESP8266: connect LCD to D1(D/C), D2(CS), RX(RES), D7(DIN), D5(CLK)
|
||||
*/
|
||||
|
||||
#include "ssd1306.h"
|
||||
#include "nano_engine.h"
|
||||
|
||||
#include "arkanoid.h"
|
||||
#include "levels.h"
|
||||
|
||||
#define PIX_BITS 2
|
||||
|
||||
NanoEngine8 engine;
|
||||
|
||||
static uint8_t g_level = 0;
|
||||
static uint8_t g_score = 0;
|
||||
static const NanoRect gameArea = { {16, 0}, {79, 63} };
|
||||
static const NanoRect blockArea = { {0, 8},
|
||||
{BLOCKS_PER_ROW*8 - 1, 8 + BLOCK_NUM_ROWS*4 - 1} };
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
lcdint_t intro_y;
|
||||
lcdint_t pauseFrames;
|
||||
} intro;
|
||||
struct
|
||||
{
|
||||
lcdint_t intro_y;
|
||||
lcdint_t pauseFrames;
|
||||
} info;
|
||||
struct
|
||||
{
|
||||
NanoRect platform; // platform position on the screen
|
||||
NanoPoint ball; // ball position on the screen
|
||||
NanoPoint ballScaled;// ball position in ^PIX_BITS coordinates
|
||||
NanoPoint ballSpeed; // ball speed in *2 coordinates
|
||||
uint8_t blocks[BLOCK_NUM_ROWS][MAX_BLOCKS_PER_ROW];
|
||||
uint8_t blocksLeft;
|
||||
uint8_t frames;
|
||||
} battleField;
|
||||
} gameState;
|
||||
|
||||
void startBattleField(bool reload);
|
||||
|
||||
bool drawIntro(void)
|
||||
{
|
||||
engine.canvas.clear();
|
||||
engine.canvas.setColor(RGB_COLOR8(255,0,0));
|
||||
engine.canvas.drawBitmap1(0, gameState.intro.intro_y, 96, 24, arkanoid_2);
|
||||
return true;
|
||||
}
|
||||
|
||||
void introLoop(void)
|
||||
{
|
||||
if (gameState.intro.intro_y < 16)
|
||||
{
|
||||
engine.refresh( 0, gameState.intro.intro_y, 95, gameState.intro.intro_y + 24 );
|
||||
gameState.intro.intro_y++;
|
||||
}
|
||||
else
|
||||
{
|
||||
gameState.intro.pauseFrames++;
|
||||
if (gameState.intro.pauseFrames > engine.getFrameRate() * 3 )
|
||||
{
|
||||
startBattleField( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startIntro(void)
|
||||
{
|
||||
engine.refresh();
|
||||
g_level = 0;
|
||||
g_score = 0;
|
||||
gameState.intro.intro_y = -24;
|
||||
gameState.intro.pauseFrames = 0;
|
||||
engine.drawCallback( drawIntro );
|
||||
engine.loopCallback( introLoop );
|
||||
}
|
||||
|
||||
bool drawBattleField(void)
|
||||
{
|
||||
/* If engine requests to redraw main game field */
|
||||
if (gameArea.contains(engine.canvas.rect()))
|
||||
{
|
||||
/* Set non-transparent mode */
|
||||
engine.canvas.setMode(CANVAS_MODE_BASIC);
|
||||
engine.canvas.setColor(RGB_COLOR8(0,0,64));
|
||||
NanoRect tileBlocks = engine.canvas.rect() >> 3;
|
||||
tileBlocks.crop(gameArea >> 3);
|
||||
for (uint8_t row = tileBlocks.p1.y; row <= tileBlocks.p2.y; row++)
|
||||
for (uint8_t col = tileBlocks.p1.x; col <= tileBlocks.p2.x; col++)
|
||||
engine.canvas.drawBitmap1(col << 3, row << 3, 8, 8, bgTile);
|
||||
engine.canvas.setColor(RGB_COLOR8(255,255,255));
|
||||
engine.canvas.drawHLine(gameArea.p1.x,gameArea.p1.y,gameArea.p2.x);
|
||||
|
||||
/* Now draw everything in game coordinates */
|
||||
engine.worldCoordinates();
|
||||
engine.canvas.setColor(RGB_COLOR8(0,128,255));
|
||||
engine.canvas.drawRect(gameState.battleField.platform);
|
||||
engine.canvas.setColor(RGB_COLOR8(0,0,0));
|
||||
engine.canvas.putPixel(gameState.battleField.platform.p1);
|
||||
engine.canvas.putPixel(gameState.battleField.platform.p2.x,
|
||||
gameState.battleField.platform.p1.y);
|
||||
for (uint8_t r = 0; r<BLOCK_NUM_ROWS; r++)
|
||||
{
|
||||
for (uint8_t bl = 0; bl<BLOCKS_PER_ROW; bl++)
|
||||
{
|
||||
uint8_t block = gameState.battleField.blocks[r][bl];
|
||||
if (block)
|
||||
{
|
||||
NanoRect rect = {{bl*8, r*4}, {bl*8 + 8, r*4+4}};
|
||||
rect += blockArea.p1;
|
||||
engine.canvas.setColor(blockColors[block]);
|
||||
engine.canvas.fillRect(rect);
|
||||
engine.canvas.setColor(0);
|
||||
engine.canvas.drawRect(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
engine.canvas.setColor(RGB_COLOR8(255,255,255));
|
||||
engine.canvas.putPixel(gameState.battleField.ball);
|
||||
}
|
||||
else
|
||||
{
|
||||
char str[8] = {0};
|
||||
engine.canvas.clear();
|
||||
engine.canvas.setColor(RGB_COLOR8(255,255,255));
|
||||
engine.canvas.drawVLine(gameArea.p1.x-1,0,64);
|
||||
engine.canvas.drawVLine(gameArea.p2.x+1,0,64);
|
||||
utoa(g_score, str, 10);
|
||||
engine.canvas.setColor(RGB_COLOR8(192,192,192));
|
||||
engine.canvas.printFixed(gameArea.p2.x+3, 16, str );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Moves platform right or left according to pressed keys */
|
||||
void movePlatform(void)
|
||||
{
|
||||
if (engine.pressed( BUTTON_LEFT ) && (gameState.battleField.platform.p1.x > 0))
|
||||
{
|
||||
engine.refreshWorld( gameState.battleField.platform );
|
||||
gameState.battleField.platform.move(-1, 0);
|
||||
engine.refreshWorld( gameState.battleField.platform );
|
||||
}
|
||||
if (engine.pressed( BUTTON_RIGHT ) && (gameState.battleField.platform.p2.x < gameArea.width() - 1))
|
||||
{
|
||||
engine.refreshWorld( gameState.battleField.platform );
|
||||
gameState.battleField.platform.move(+1, 0);
|
||||
engine.refreshWorld( gameState.battleField.platform );
|
||||
}
|
||||
}
|
||||
|
||||
bool checkBlockHit(void)
|
||||
{
|
||||
if (!blockArea.collision(gameState.battleField.ball))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
NanoPoint p = gameState.battleField.ball - blockArea.p1;
|
||||
uint8_t row = p.y >> 2;
|
||||
uint8_t column = p.x >> 3;
|
||||
if (!gameState.battleField.blocks[row][column])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
gameState.battleField.blocks[row][column] = 0;
|
||||
gameState.battleField.blocksLeft--;
|
||||
g_score++;
|
||||
engine.refreshWorld( gameArea.p2.x + 1, 0, 95, 63 );
|
||||
if (((p.y & 3) == 2) || (p.y & 3) == 1)
|
||||
{
|
||||
gameState.battleField.ballSpeed.x = -gameState.battleField.ballSpeed.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
gameState.battleField.ballSpeed.y = -gameState.battleField.ballSpeed.y;
|
||||
}
|
||||
engine.refreshWorld( gameState.battleField.ball );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkPlatformHit()
|
||||
{
|
||||
if (gameState.battleField.platform.collisionX( gameState.battleField.ball.x ) &&
|
||||
!gameState.battleField.platform.above( gameState.battleField.ball ) &&
|
||||
!gameState.battleField.platform.below( gameState.battleField.ball ) )
|
||||
{
|
||||
if (gameState.battleField.ball.x < gameState.battleField.platform.p1.x + 3)
|
||||
{
|
||||
gameState.battleField.ballSpeed.x = -3;
|
||||
gameState.battleField.ballSpeed.y = -gameState.battleField.ballSpeed.y;
|
||||
}
|
||||
else if (gameState.battleField.ball.x > gameState.battleField.platform.p2.x - 3)
|
||||
{
|
||||
gameState.battleField.ballSpeed.x = +3;
|
||||
gameState.battleField.ballSpeed.y = -gameState.battleField.ballSpeed.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
gameState.battleField.ballSpeed.x = gameState.battleField.ballSpeed.x > 0 ? 2: -2;
|
||||
gameState.battleField.ballSpeed.y = -gameState.battleField.ballSpeed.y;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool checkGameAreaHit(void)
|
||||
{
|
||||
bool hit = false;
|
||||
if ((gameState.battleField.ball.x < 0) ||
|
||||
(gameState.battleField.ball.x >= gameArea.width()))
|
||||
{
|
||||
hit = true;
|
||||
gameState.battleField.ballSpeed.x = -gameState.battleField.ballSpeed.x;
|
||||
}
|
||||
if ((gameState.battleField.ball.y < 0) ||
|
||||
(gameState.battleField.ball.y >= gameArea.height()))
|
||||
{
|
||||
hit = true;
|
||||
gameState.battleField.ballSpeed.y = -gameState.battleField.ballSpeed.y;
|
||||
if (gameState.battleField.ball.y >= gameArea.height())
|
||||
{
|
||||
startBattleField( false );
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
void moveBall(void)
|
||||
{
|
||||
engine.refreshWorld( gameState.battleField.ball );
|
||||
bool moveBall;
|
||||
do
|
||||
{
|
||||
gameState.battleField.ballScaled += gameState.battleField.ballSpeed;
|
||||
gameState.battleField.ball = gameState.battleField.ballScaled >> PIX_BITS;
|
||||
moveBall = false;
|
||||
if (checkGameAreaHit())
|
||||
{
|
||||
moveBall = true;
|
||||
}
|
||||
if (checkPlatformHit())
|
||||
{
|
||||
moveBall = true;
|
||||
}
|
||||
if (checkBlockHit())
|
||||
{
|
||||
moveBall = true;
|
||||
}
|
||||
}
|
||||
while (moveBall);
|
||||
engine.refreshWorld( gameState.battleField.ball );
|
||||
}
|
||||
|
||||
void battleFieldLoop(void)
|
||||
{
|
||||
movePlatform();
|
||||
moveBall();
|
||||
/* Refresh debug information if we need it */
|
||||
gameState.battleField.frames++;
|
||||
if (gameState.battleField.blocksLeft == 0)
|
||||
{
|
||||
g_level++;
|
||||
startBattleField( true );
|
||||
}
|
||||
}
|
||||
|
||||
void loadLevel(void)
|
||||
{
|
||||
/* Loading level */
|
||||
if (g_level > MAX_LEVELS)
|
||||
{
|
||||
g_level = MAX_LEVELS;
|
||||
}
|
||||
gameState.battleField.blocksLeft = 0;
|
||||
for (uint8_t i =0; i<BLOCKS_PER_ROW; i++)
|
||||
{
|
||||
for (uint8_t j=0; j<BLOCK_NUM_ROWS; j++)
|
||||
{
|
||||
uint8_t block = pgm_read_byte( &levels[g_level][j][i] );
|
||||
gameState.battleField.blocks[j][i] = block;
|
||||
if (block)
|
||||
{
|
||||
gameState.battleField.blocksLeft++;
|
||||
}
|
||||
}
|
||||
}
|
||||
gameState.battleField.frames = 0;
|
||||
}
|
||||
|
||||
void startBattleField(bool reload)
|
||||
{
|
||||
engine.refresh();
|
||||
gameState.battleField.platform.setRect( 4, 56, 15, 58 );
|
||||
gameState.battleField.ball.setPoint( 9, 55);
|
||||
gameState.battleField.ballScaled = gameState.battleField.ball << PIX_BITS;
|
||||
gameState.battleField.ballSpeed.setPoint( 3, -(1<<PIX_BITS) );
|
||||
engine.drawCallback( drawBattleField );
|
||||
engine.loopCallback( battleFieldLoop );
|
||||
if ( reload )
|
||||
{
|
||||
loadLevel();
|
||||
}
|
||||
|
||||
/* Show level info in popup message */
|
||||
char levelInfo[8] = "LEVEL X";
|
||||
levelInfo[6] = g_level + '0';
|
||||
engine.notify(levelInfo);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
/* Set font to use in the game. The font has only capital letters and digits */
|
||||
ssd1306_setFixedFont(ssd1306xled_font6x8_AB);
|
||||
|
||||
/* Init SPI oled display. 3 - RESET, 4 - CS (can be omitted, oled CS must be pulled down), 5 - D/C */
|
||||
|
||||
/* ssd1351 must be initialized in Horizontal addressing mode */
|
||||
// ssd1351_128x128_spi_init(3, 4, 5);
|
||||
|
||||
/* il9163 must be initialized in Horizontal addressing mode */
|
||||
// il9163_128x128_spi_init(3, 4, 5);
|
||||
|
||||
/* ssd1331 must be initialized in Horizontal addressing mode */
|
||||
ssd1331_96x64_spi_init(3, 4, 5);
|
||||
|
||||
/* Configure engine to use ZKeypand on A0 as control board. */
|
||||
engine.connectZKeypad(0);
|
||||
|
||||
/* Start engine */
|
||||
engine.begin();
|
||||
|
||||
/* Set frame rate. 30 fps is too slow */
|
||||
engine.setFrameRate(45);
|
||||
|
||||
engine.moveTo({ -gameArea.p1.x, -gameArea.p1.y });
|
||||
|
||||
startIntro();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (!engine.nextFrame()) return;
|
||||
engine.display();
|
||||
}
|
||||
79
libraries/ssd1306/examples/games/arkanoid8/levels.cpp
Normal file
79
libraries/ssd1306/examples/games/arkanoid8/levels.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ssd1306.h"
|
||||
#include "levels.h"
|
||||
|
||||
const uint8_t blockColors[]=
|
||||
{
|
||||
0,
|
||||
RGB_COLOR8(128,128,128), // Grey 1
|
||||
RGB_COLOR8(255,64,64), // Red 2
|
||||
RGB_COLOR8(255,255,64), // Yellow 3
|
||||
RGB_COLOR8(64,64,255), // Blue 4
|
||||
RGB_COLOR8(255,64,255), // Cyan 5
|
||||
RGB_COLOR8(64,255,64), // Green 6
|
||||
RGB_COLOR8(255,255,255), // White 7
|
||||
RGB_COLOR8(255,192,64), // Orange 8
|
||||
RGB_COLOR8(128,255,192), // Light-blue 9
|
||||
};
|
||||
|
||||
|
||||
const PROGMEM uint8_t bgTile[] =
|
||||
{
|
||||
0B00000001,
|
||||
0B11000010,
|
||||
0B00101100,
|
||||
0B00010000,
|
||||
0B00101100,
|
||||
0B01000010,
|
||||
0B10000001,
|
||||
0B00000001,
|
||||
};
|
||||
|
||||
const PROGMEM uint8_t levels[MAX_LEVELS][BLOCK_NUM_ROWS][MAX_BLOCKS_PER_ROW] =
|
||||
{
|
||||
{ // LEVEL 1
|
||||
{ 1,1,1,1,1,1,1,1, },
|
||||
{ 2,2,2,2,2,2,2,2, },
|
||||
{ 3,3,3,3,3,3,3,3, },
|
||||
{ 4,4,4,4,4,4,4,4, },
|
||||
{ 5,5,5,5,5,5,5,5, },
|
||||
},
|
||||
{ // LEVEL 2
|
||||
{ 7,8,0,0,0,0,0,0, },
|
||||
{ 7,8,9,6,0,0,0,0, },
|
||||
{ 7,8,9,6,1,4,0,0, },
|
||||
{ 7,8,9,6,1,4,5,3, },
|
||||
{ 1,1,1,1,1,1,1,2, },
|
||||
},
|
||||
{ // LEVEL 3
|
||||
{ 0,0,1,1,1,1,0,0, },
|
||||
{ 0,1,2,1,1,2,1,0, },
|
||||
{ 1,1,1,1,1,1,1,1, },
|
||||
{ 1,0,1,1,1,1,0,1, },
|
||||
{ 0,0,1,0,0,1,0,0, },
|
||||
},
|
||||
};
|
||||
|
||||
41
libraries/ssd1306/examples/games/arkanoid8/levels.h
Normal file
41
libraries/ssd1306/examples/games/arkanoid8/levels.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
static const int MAX_LEVELS = 3;
|
||||
#ifdef ARKANOID_SSD1331
|
||||
static const int BLOCKS_PER_ROW = 8;
|
||||
#else
|
||||
static const int BLOCKS_PER_ROW = 8;
|
||||
#endif
|
||||
static const int MAX_BLOCKS_PER_ROW = 8;
|
||||
static const int BLOCK_NUM_ROWS = 5;
|
||||
|
||||
extern const uint8_t blockColors[];
|
||||
|
||||
extern const PROGMEM uint8_t bgTile[];
|
||||
|
||||
extern const PROGMEM uint8_t levels[MAX_LEVELS][BLOCK_NUM_ROWS][MAX_BLOCKS_PER_ROW];
|
||||
|
||||
17
libraries/ssd1306/examples/games/lode_runner/README.md
Normal file
17
libraries/ssd1306/examples/games/lode_runner/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# HOW to run Lode runner in emulator mode
|
||||
|
||||
Read [instructions](https://github.com/lexus2k/ssd1306/wiki/How-to-run-emulator-mode) and
|
||||
install all required prerequisites.
|
||||
|
||||
## Compiling game and running emulation in Linux
|
||||
|
||||
> cd ssd1306/tools<br>
|
||||
> ./build_and_run.sh -p linux -e -f games/lode_runner<br>
|
||||
|
||||
## Compiling game and running emulation in Windows
|
||||
|
||||
For MinGW32 use the script below:
|
||||
> cd ssd1306\tools<br>
|
||||
> build_and_run.bat "games/lode_runner"<br>
|
||||
|
||||
|
||||
46
libraries/ssd1306/examples/games/lode_runner/game_basic.cpp
Normal file
46
libraries/ssd1306/examples/games/lode_runner/game_basic.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "game_basic.h"
|
||||
|
||||
|
||||
uint8_t gameField[24*14] =
|
||||
{
|
||||
5,0,0,0,0,3,3,0,0,0,0,5,5,0,0,0,0,3,3,0,0,0,0,5,
|
||||
5,0,2,0,0,4,0,2,1,1,2,0,0,0,0,0,4,0,0,2,1,1,2,5,
|
||||
5,0,2,0,0,1,0,2,0,0,1,1,5,2,0,0,1,1,0,2,0,0,1,1,
|
||||
5,0,2,1,0,0,0,2,0,4,0,0,0,2,0,0,0,0,0,2,0,4,0,5,
|
||||
5,1,2,1,1,1,1,1,1,1,1,1,5,1,5,2,1,1,1,1,1,1,1,1,
|
||||
5,0,2,0,0,0,0,0,4,0,0,0,0,0,5,2,0,0,0,0,4,0,0,5,
|
||||
1,1,1,1,1,1,1,2,1,1,1,1,1,2,0,2,1,1,1,1,1,1,1,1,
|
||||
5,0,0,0,0,3,3,2,0,0,0,5,5,1,1,1,0,3,3,0,0,0,0,5,
|
||||
5,0,2,0,4,0,0,2,1,1,2,0,0,0,0,0,4,0,0,2,1,1,2,5,
|
||||
5,0,2,0,1,1,0,2,0,0,1,1,5,2,0,0,1,1,0,2,0,0,1,1,
|
||||
5,0,2,0,0,0,0,2,0,4,0,0,0,2,0,0,0,0,0,2,0,4,0,5,
|
||||
5,1,2,1,1,1,1,1,1,1,1,1,5,1,2,1,1,1,1,1,1,1,1,1,
|
||||
5,0,2,0,0,0,0,0,4,0,0,5,5,0,2,0,0,0,0,0,4,0,0,5,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
};
|
||||
|
||||
GraphicsEngine engine;
|
||||
79
libraries/ssd1306/examples/games/lode_runner/game_basic.h
Normal file
79
libraries/ssd1306/examples/games/lode_runner/game_basic.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ssd1306.h"
|
||||
#include "nano_engine.h"
|
||||
|
||||
typedef NanoEngine<TILE_16x16_RGB8> GraphicsEngine;
|
||||
|
||||
extern uint8_t gameField[];
|
||||
extern GraphicsEngine engine;
|
||||
|
||||
static inline bool isWalkable(uint8_t type) { return (type == 0) || (type == 2) || (type == 3) || (type == 4); }
|
||||
static inline bool isSolid(uint8_t type) { return (type == 1) || (type == 2) || (type == 5); }
|
||||
static inline bool isPipe(uint8_t type) { return type == 3; }
|
||||
static inline bool isGold(uint8_t type) { return type == 4; }
|
||||
static inline bool isStair(uint8_t type) { return type == 2; }
|
||||
|
||||
static inline uint16_t block_index(const NanoPoint& block)
|
||||
{
|
||||
return block.x + block.y * 24;
|
||||
}
|
||||
|
||||
static inline NanoPoint pos_to_block(const NanoPoint& pos)
|
||||
{
|
||||
return pos >> 3;
|
||||
}
|
||||
|
||||
static inline NanoPoint block_to_pos(const NanoPoint& block)
|
||||
{
|
||||
return block << 3;
|
||||
}
|
||||
|
||||
static inline NanoRect rect_to_blocks(const NanoRect& rect)
|
||||
{
|
||||
return rect >> 3;
|
||||
}
|
||||
|
||||
static inline uint8_t block_value(const NanoPoint& block)
|
||||
{
|
||||
uint16_t index = block_index(block);
|
||||
if (index >= 24*14) index = 0;
|
||||
return gameField[index];
|
||||
}
|
||||
|
||||
static inline uint8_t block_at(const NanoPoint& p)
|
||||
{
|
||||
return block_value(pos_to_block(p));
|
||||
}
|
||||
|
||||
static inline void set_block_at(const NanoPoint& p, uint8_t v)
|
||||
{
|
||||
uint16_t index = block_index(pos_to_block(p));
|
||||
if (index >= 24*14) index = 0;
|
||||
gameField[index] = v;
|
||||
}
|
||||
|
||||
353
libraries/ssd1306/examples/games/lode_runner/lode_runner.ino
Normal file
353
libraries/ssd1306/examples/games/lode_runner/lode_runner.ino
Normal file
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* Attiny85 PINS
|
||||
* ____
|
||||
* RESET -|_| |- 3V
|
||||
* SCL (3) -| |- (2)
|
||||
* SDA (4) -| |- (1) - BUZZER
|
||||
* GND -|____|- (0) - BUTTONS module
|
||||
*
|
||||
* Atmega328 PINS with i2c SSD1306 to A4/A5, BUZZER on D8,
|
||||
* Z-keypad ADC module on A0 pin.
|
||||
* If you want to use GPIO keys, uncomment USE_GPIO_BUTTONS below
|
||||
*
|
||||
* Atmega328 PINS with spi Nokia 5110 LCD:
|
||||
* LCD RST to D3
|
||||
* LCD CES to D4
|
||||
* LCD DC to D5
|
||||
* LCD DIN to D11
|
||||
* LCD CLK to D13
|
||||
* LCD BL to VCC
|
||||
*/
|
||||
|
||||
#include "game_basic.h"
|
||||
#include "ninja.h"
|
||||
#include "sprites.h"
|
||||
#include "intf/ssd1306_interface.h"
|
||||
#include "intf/spi/ssd1306_spi.h"
|
||||
|
||||
// Uncomment if you have ssd1331 oled display
|
||||
//#define SSD1331_ACCELERATION
|
||||
|
||||
// Uncomment if you want to use gpio buttons
|
||||
//#define USE_GPIO_BUTTONS
|
||||
|
||||
#if defined(__AVR_ATtiny25__) | defined(__AVR_ATtiny45__) | defined(__AVR_ATtiny85__)
|
||||
#define BUZZER 1
|
||||
#define BUTTON_PIN 0
|
||||
#else // For Arduino Nano/Atmega328 we use different pins
|
||||
#define BUZZER 8
|
||||
#define BUTTON_PIN 0
|
||||
#ifdef USE_GPIO_BUTTONS
|
||||
static const uint8_t g_buttonsPins[6] = { 2, 6, 7, 8, 9, 12 };
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
const NanoRect game_window = { {0, 0}, {95, 63} };
|
||||
|
||||
uint8_t blockColors[] =
|
||||
{
|
||||
RGB_COLOR8(255,96,0),
|
||||
RGB_COLOR8(255,255,192),
|
||||
RGB_COLOR8(255,255,255),
|
||||
RGB_COLOR8(255,255,64),
|
||||
RGB_COLOR8(128,128,128),
|
||||
};
|
||||
|
||||
/**
|
||||
* Just produces some sound depending on params
|
||||
*/
|
||||
void beep(int bCount,int bDelay);
|
||||
|
||||
NanoFixedSprite<GraphicsEngine, engine> player( { 8, 8 }, { 8, 8 }, playerFlyingImage[0][0] );
|
||||
|
||||
/* The variable is used for player animation *
|
||||
* The graphics defined for the hero has 2 images *
|
||||
* for each direction. So, the variable is either *
|
||||
* 0 or 1. */
|
||||
uint8_t playerAnimation = 0;
|
||||
|
||||
/* Timestamp when playerAnimation was changed last time */
|
||||
uint16_t playerAnimationTs = 0;
|
||||
|
||||
/* Number of coins collected */
|
||||
uint8_t goldCollection = 0;
|
||||
|
||||
void showGameInfo()
|
||||
{
|
||||
engine.canvas.setMode(CANVAS_MODE_TRANSPARENT);
|
||||
engine.canvas.setColor(RGB_COLOR8(0,0,0));
|
||||
engine.canvas.drawBitmap1(1, 1, 8, 8, coinImage);
|
||||
engine.canvas.setColor(RGB_COLOR8(255,255,0));
|
||||
engine.canvas.drawBitmap1(0, 0, 8, 8, coinImage);
|
||||
|
||||
ssd1306_setFixedFont(digital_font5x7_AB);
|
||||
char score[3] = {goldCollection/10 + '0', goldCollection%10 + '0', 0};
|
||||
engine.canvas.setColor(RGB_COLOR8(0,0,0));
|
||||
engine.canvas.printFixed(9,1,score);
|
||||
engine.canvas.setColor(RGB_COLOR8(255,255,255));
|
||||
engine.canvas.printFixed(8,0,score);
|
||||
ssd1306_setFixedFont(digital_font5x7_AB);
|
||||
}
|
||||
|
||||
static bool onDraw()
|
||||
{
|
||||
engine.canvas.clear();
|
||||
engine.canvas.setMode(CANVAS_MODE_BASIC);
|
||||
if (game_window.containsPartOf( engine.canvas.rect() ))
|
||||
{
|
||||
engine.worldCoordinates();
|
||||
NanoRect blocks = rect_to_blocks( engine.canvas.rect() );
|
||||
for (uint8_t row = max(0,blocks.p1.y);
|
||||
row <= min(13,blocks.p2.y); row++)
|
||||
{
|
||||
for (uint8_t col = max(0,blocks.p1.x);
|
||||
col <= min(23,blocks.p2.x); col++)
|
||||
{
|
||||
uint8_t blockType = block_value({col,row});
|
||||
if (blockType != 0)
|
||||
{
|
||||
engine.canvas.setColor(blockColors[blockType - 1]);
|
||||
NanoPoint pos = block_to_pos({col,row});
|
||||
engine.canvas.drawBitmap1(pos.x, pos.y,
|
||||
8, 8, bgSprites[blockType - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
engine.canvas.setMode(CANVAS_MODE_TRANSPARENT);
|
||||
engine.canvas.setColor(RGB_COLOR8(64,255,255));
|
||||
player.draw();
|
||||
engine.canvas.setColor(RGB_COLOR8(64,64,255));
|
||||
ninja.draw();
|
||||
engine.localCoordinates();
|
||||
}
|
||||
showGameInfo();
|
||||
return true;
|
||||
}
|
||||
|
||||
static NanoPoint calc_new_screen_position()
|
||||
{
|
||||
NanoPoint position = engine.getPosition() + game_window.p1;
|
||||
if (player.x() - position.x >= game_window.width() - 24)
|
||||
{
|
||||
position.x = min(player.x() - (game_window.width() - 24), 128);
|
||||
}
|
||||
else if (player.x() - position.x < 24)
|
||||
{
|
||||
position.x = max(0, player.x() - 24);
|
||||
}
|
||||
if (player.y() - position.y >= game_window.height() - 24)
|
||||
{
|
||||
position.y = min(player.y() - (game_window.height() - 24), 64);
|
||||
}
|
||||
else if (player.y() - position.y < 24)
|
||||
{
|
||||
position.y = max(0, player.y() - 24);
|
||||
}
|
||||
return position - game_window.p1;
|
||||
}
|
||||
|
||||
#ifdef SSD1331_ACCELERATION
|
||||
static void moveGameScreen()
|
||||
{
|
||||
NanoPoint position = calc_new_screen_position();
|
||||
if (position != engine.getPosition())
|
||||
{
|
||||
NanoPoint delta = position - engine.getPosition();
|
||||
NanoRect block = game_window + delta;
|
||||
block.crop(game_window);
|
||||
// Copy most part of OLED content via hardware accelerator
|
||||
ssd1331_copyBlock(block.p1.x, block.p1.y, block.p2.x, block.p2.y,
|
||||
block.p1.x - delta.x, block.p1.y - delta.y);
|
||||
// give some time oled to complete HW copy operation
|
||||
delayMicroseconds(250);
|
||||
engine.moveTo( position );
|
||||
// Now tell the engine to redraw only new areas
|
||||
if ( delta.x > 0)
|
||||
engine.refresh(game_window.p2.x - delta.x, game_window.p1.y, game_window.p2.x, game_window.p2.y);
|
||||
else if ( delta.x < 0 )
|
||||
engine.refresh(game_window.p1.x, game_window.p1.y, game_window.p1.x - delta.x, game_window.p2.y);
|
||||
if ( delta.y > 0)
|
||||
engine.refresh(game_window.p1.x, game_window.p2.y - delta.y, game_window.p2.x, game_window.p2.y);
|
||||
else if ( delta.y < 0 )
|
||||
engine.refresh(game_window.p1.x, game_window.p1.y, game_window.p2.x, game_window.p1.y - delta.y);
|
||||
// refresh status line
|
||||
engine.refresh(0,0,23,7);
|
||||
}
|
||||
}
|
||||
|
||||
#else // NO SSD1331 Acceleration
|
||||
|
||||
static void moveGameScreen()
|
||||
{
|
||||
NanoPoint position = calc_new_screen_position();
|
||||
if (position != engine.getPosition())
|
||||
{
|
||||
engine.moveTo( position );
|
||||
engine.refresh( game_window );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void movePlayer(uint8_t direction)
|
||||
{
|
||||
bool animated = false;
|
||||
uint8_t bottomBlock = block_at(player.bottom());
|
||||
uint8_t feetBlock = block_at(player.bottom() + (NanoPoint){0,1});
|
||||
uint8_t handBlock = block_at(player.top());
|
||||
uint8_t centerBlock = block_at(player.center());
|
||||
uint8_t rightBlock = block_at(player.right());
|
||||
uint8_t leftBlock = block_at(player.left());
|
||||
moveGameScreen();
|
||||
/* If player doesn't stand on the ground, and doesn't hold the pipe,
|
||||
* make the player to fall down. */
|
||||
if ( !isSolid(feetBlock) &&
|
||||
(!isPipe(handBlock) || !isPipe(bottomBlock)) )
|
||||
{
|
||||
player.moveTo( { player.center().x & ~0x07, player.y() + 1 } );
|
||||
player.setBitmap( &playerFlyingImage[MAN_ANIM_FLYING][playerAnimation][0] );
|
||||
animated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case BUTTON_RIGHT:
|
||||
if (isWalkable(rightBlock))
|
||||
{
|
||||
player.moveBy( { 1, 0 } );
|
||||
if (isPipe(centerBlock))
|
||||
player.setBitmap( &playerFlyingImage[MAN_ANIM_RIGHT_PIPE][playerAnimation][0] );
|
||||
else
|
||||
player.setBitmap( &playerFlyingImage[MAN_ANIM_RIGHT][playerAnimation][0] );
|
||||
animated = true;
|
||||
}
|
||||
break;
|
||||
case BUTTON_LEFT:
|
||||
if (isWalkable(leftBlock))
|
||||
{
|
||||
player.moveBy( { -1, 0 } );
|
||||
if (isPipe(centerBlock))
|
||||
player.setBitmap( &playerFlyingImage[MAN_ANIM_LEFT_PIPE][playerAnimation][0] );
|
||||
else
|
||||
player.setBitmap( &playerFlyingImage[MAN_ANIM_LEFT][playerAnimation][0] );
|
||||
animated = true;
|
||||
}
|
||||
break;
|
||||
case BUTTON_UP:
|
||||
if (isStair(bottomBlock) || isStair(centerBlock))
|
||||
{
|
||||
player.moveTo( { player.top().x & ~0x07, player.top().y - 1 } );
|
||||
player.setBitmap( &playerFlyingImage[MAN_ANIM_UP][playerAnimation][0] );
|
||||
animated = true;
|
||||
}
|
||||
break;
|
||||
case BUTTON_DOWN:
|
||||
if ( isStair(feetBlock) ||
|
||||
(!isSolid(feetBlock) &&
|
||||
isPipe(handBlock)) )
|
||||
{
|
||||
player.moveTo( { player.top().x & ~0x07, player.top().y + 1 } );
|
||||
player.setBitmap( &playerFlyingImage[MAN_ANIM_DOWN][playerAnimation][0] );
|
||||
animated = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (animated && ((uint16_t)(millis() - playerAnimationTs) > 150))
|
||||
{
|
||||
playerAnimationTs = millis();
|
||||
playerAnimation = playerAnimation ? 0 : 1;
|
||||
beep(10,20);
|
||||
if (isGold(centerBlock))
|
||||
{
|
||||
engine.notify( "GOLD COIN" );
|
||||
set_block_at(player.center(), 0);
|
||||
goldCollection++;
|
||||
showGameInfo();
|
||||
engine.refresh(0,0,63,7);
|
||||
/* Produce sound every time the player moves */
|
||||
beep(20,40);
|
||||
beep(20,80);
|
||||
beep(20,120);
|
||||
beep(20,80);
|
||||
beep(20,40);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
ssd1331_96x64_spi_init(3, 4, 5); // 3 RST, 4 CES, 5 DS
|
||||
|
||||
// ssd1306_128x64_i2c_init();
|
||||
// pcd8544_84x48_spi_init(3, 4, 5); // 3 RST, 4 CES, 5 DS
|
||||
// il9163_128x128_spi_init(3, 4, 5);
|
||||
// st7735_128x160_spi_init(3, 4, 5);
|
||||
|
||||
player.setBitmap( playerFlyingImage[MAN_ANIM_FLYING][playerAnimation] );
|
||||
|
||||
#ifdef USE_GPIO_BUTTONS
|
||||
engine.connectGpioKeypad(g_buttonsPins);
|
||||
#else
|
||||
engine.connectZKeypad(BUTTON_PIN);
|
||||
#endif
|
||||
engine.drawCallback( onDraw );
|
||||
engine.begin();
|
||||
engine.setFrameRate(45);
|
||||
engine.refresh();
|
||||
pinMode(BUZZER, OUTPUT);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (!engine.nextFrame()) return;
|
||||
movePlayer(engine.buttonsState());
|
||||
ninja.move(player.getPosition());
|
||||
engine.display();
|
||||
}
|
||||
|
||||
|
||||
void beep(int bCount,int bDelay)
|
||||
{
|
||||
for (int i = 0; i<=bCount*2; i++)
|
||||
{
|
||||
digitalWrite(BUZZER,i&1);
|
||||
for(int i2=0; i2<bDelay; i2++)
|
||||
{
|
||||
__asm__("nop\n\t");
|
||||
#if F_CPU > 8000000
|
||||
__asm__("nop\n\t");
|
||||
__asm__("nop\n\t");
|
||||
__asm__("nop\n\t");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
digitalWrite(BUZZER,LOW);
|
||||
}
|
||||
159
libraries/ssd1306/examples/games/lode_runner/ninja.cpp
Normal file
159
libraries/ssd1306/examples/games/lode_runner/ninja.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ninja.h"
|
||||
#include "sprites.h"
|
||||
|
||||
#include "intf/ssd1306_interface.h"
|
||||
#include "intf/spi/ssd1306_spi.h"
|
||||
|
||||
Ninja ninja({72, 8});
|
||||
|
||||
void Ninja::move(const NanoPoint &target)
|
||||
{
|
||||
static uint16_t ninjaAnimationTs = 0;
|
||||
static uint8_t ninjaAnimation = 0;
|
||||
bool animated = false;
|
||||
uint8_t direction = BUTTON_NONE;
|
||||
uint8_t bottomBlock = block_at(bottom());
|
||||
uint8_t feetBlock = block_at(bottom() + (NanoPoint){0,1});
|
||||
uint8_t handBlock = block_at(top());
|
||||
uint8_t centerBlock = block_at(center());
|
||||
uint8_t rightBlock = block_at(right());
|
||||
uint8_t leftBlock = block_at(left());
|
||||
if ( !isSolid(feetBlock) &&
|
||||
(!isPipe(handBlock) || !isPipe(bottomBlock)) )
|
||||
{
|
||||
moveTo( { center().x & ~0x07, m_pos.y + 1 } );
|
||||
setBitmap( &playerFlyingImage[MAN_ANIM_FLYING][ninjaAnimation][0] );
|
||||
animated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target.y < m_pos.y - 1)
|
||||
{
|
||||
bool right = true;
|
||||
bool left = true;
|
||||
// search for stairs
|
||||
for (int8_t i=0; i < 80; i=i+8)
|
||||
{
|
||||
if (right)
|
||||
{
|
||||
uint8_t block = block_at(center() + (NanoPoint){i,0});
|
||||
if (!isWalkable(block)) { right = false; }
|
||||
if (isStair(block)) { direction = BUTTON_RIGHT; break; }
|
||||
}
|
||||
if (left)
|
||||
{
|
||||
uint8_t block = block_at(center() - (NanoPoint){i,0});
|
||||
if (!isWalkable(block)) { left = false; }
|
||||
if (isStair(block)) { direction = BUTTON_LEFT; break; }
|
||||
}
|
||||
}
|
||||
if (isStair(centerBlock) || isStair(bottomBlock)) direction = BUTTON_UP;
|
||||
}
|
||||
else if (target.y > m_pos.y + 1)
|
||||
{
|
||||
if (isPipe(handBlock))
|
||||
{
|
||||
direction = BUTTON_DOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool right = true;
|
||||
bool left = true;
|
||||
// search for stairs
|
||||
for (int8_t i=0; i < 80; i=i+8)
|
||||
{
|
||||
if (right)
|
||||
{
|
||||
uint8_t block = block_at(center() + (NanoPoint){i,0});
|
||||
if (!isWalkable(block)) right = false;
|
||||
else
|
||||
{
|
||||
block = block_at(bottom() + (NanoPoint){i,1});
|
||||
if (isWalkable(block)) { direction = BUTTON_RIGHT; break; }
|
||||
}
|
||||
}
|
||||
if (left)
|
||||
{
|
||||
uint8_t block = block_at(center() - (NanoPoint){i,0});
|
||||
if (!isWalkable(block)) left = false;
|
||||
else
|
||||
{
|
||||
block = block_at(bottom() + (NanoPoint){-i,1});
|
||||
if (isWalkable(block)) { direction = BUTTON_LEFT; break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isWalkable(feetBlock)) direction = BUTTON_DOWN;
|
||||
}
|
||||
}
|
||||
else if (target.x > m_pos.x)
|
||||
{
|
||||
if (isWalkable(rightBlock)) direction = BUTTON_RIGHT;
|
||||
}
|
||||
else if (target.x < m_pos.x)
|
||||
{
|
||||
if (isWalkable(leftBlock)) direction = BUTTON_LEFT;
|
||||
}
|
||||
switch (direction)
|
||||
{
|
||||
case BUTTON_RIGHT:
|
||||
moveBy( { 1, 0 } );
|
||||
if (isPipe(centerBlock))
|
||||
setBitmap( &playerFlyingImage[MAN_ANIM_RIGHT_PIPE][ninjaAnimation][0] );
|
||||
else
|
||||
setBitmap( &playerFlyingImage[MAN_ANIM_RIGHT][ninjaAnimation][0] );
|
||||
animated = true;
|
||||
break;
|
||||
case BUTTON_LEFT:
|
||||
moveBy( { -1, 0 } );
|
||||
if (isPipe(centerBlock))
|
||||
setBitmap( &playerFlyingImage[MAN_ANIM_LEFT_PIPE][ninjaAnimation][0] );
|
||||
else
|
||||
setBitmap( &playerFlyingImage[MAN_ANIM_LEFT][ninjaAnimation][0] );
|
||||
animated = true;
|
||||
break;
|
||||
case BUTTON_UP:
|
||||
moveTo( { top().x & ~0x07, top().y - 1 } );
|
||||
setBitmap( &playerFlyingImage[MAN_ANIM_UP][ninjaAnimation][0] );
|
||||
animated = true;
|
||||
break;
|
||||
case BUTTON_DOWN:
|
||||
moveTo( { top().x & ~0x07, top().y + 1 } );
|
||||
setBitmap( &playerFlyingImage[MAN_ANIM_DOWN][ninjaAnimation][0] );
|
||||
animated = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (animated && ((uint16_t)(millis() - ninjaAnimationTs) > 150))
|
||||
{
|
||||
ninjaAnimationTs = millis();
|
||||
ninjaAnimation = ninjaAnimation ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
39
libraries/ssd1306/examples/games/lode_runner/ninja.h
Normal file
39
libraries/ssd1306/examples/games/lode_runner/ninja.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "game_basic.h"
|
||||
#include "sprites.h"
|
||||
|
||||
class Ninja: public NanoFixedSprite<GraphicsEngine, engine>
|
||||
{
|
||||
public:
|
||||
explicit Ninja(NanoPoint pos)
|
||||
: NanoFixedSprite<GraphicsEngine, engine>(pos, {8,8}, playerFlyingImage[0][0]) {}
|
||||
|
||||
void move(const NanoPoint &target);
|
||||
};
|
||||
|
||||
extern Ninja ninja;
|
||||
Binary file not shown.
Binary file not shown.
154
libraries/ssd1306/examples/games/lode_runner/sprites.cpp
Normal file
154
libraries/ssd1306/examples/games/lode_runner/sprites.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "sprites.h"
|
||||
|
||||
PROGMEM const uint8_t bgSprites[5][8] =
|
||||
{
|
||||
{
|
||||
0B01110111,
|
||||
0B01110111,
|
||||
0B01110000,
|
||||
0B01110111,
|
||||
0B01110111,
|
||||
0B00000111,
|
||||
0B01110111,
|
||||
0B01110111,
|
||||
},
|
||||
{
|
||||
0B00010001,
|
||||
0B11111111,
|
||||
0B00010001,
|
||||
0B00010001,
|
||||
0B00010001,
|
||||
0B11111111,
|
||||
0B00010001,
|
||||
0B00000000,
|
||||
},
|
||||
{
|
||||
0B00000010,
|
||||
0B00000010,
|
||||
0B00000010,
|
||||
0B00000010,
|
||||
0B00000010,
|
||||
0B00000010,
|
||||
0B00000010,
|
||||
0B00000010,
|
||||
},
|
||||
{
|
||||
0B00000000,
|
||||
0B11000000,
|
||||
0B11100000,
|
||||
0B10110000,
|
||||
0B11010000,
|
||||
0B10100000,
|
||||
0B11000000,
|
||||
0B00000000,
|
||||
},
|
||||
{
|
||||
0B01111111,
|
||||
0B01111111,
|
||||
0B01111111,
|
||||
0B01110111,
|
||||
0B01111111,
|
||||
0B01111111,
|
||||
0B01111111,
|
||||
0B00000000,
|
||||
},
|
||||
};
|
||||
|
||||
const PROGMEM uint8_t playerFlyingImage[MAN_ANIM_MAX][2][8] = {
|
||||
{ // FLYING
|
||||
{ 0x00, 0x04, 0x88, 0x4B, 0x3F, 0x48, 0x88, 0x04 },
|
||||
{ 0x00, 0x10, 0x08, 0xCB, 0x3F, 0xC8, 0x08, 0x10 },
|
||||
},
|
||||
{ // UP + DOWN
|
||||
{ 0x00, 0x00, 0x90, 0x4B, 0x3F, 0x28, 0x66, 0x00 },
|
||||
{ 0x00, 0x00, 0x66, 0x2B, 0x3F, 0x48, 0x90, 0x00 },
|
||||
},
|
||||
{ // LEFT
|
||||
{ 0x00, 0x10, 0x10, 0xCB, 0x3F, 0x48, 0x90, 0x00 },
|
||||
{ 0x00, 0x00, 0x20, 0x1B, 0xFF, 0xD8, 0x00, 0x00 },
|
||||
},
|
||||
{ // RIGHT
|
||||
{ 0x00, 0x90, 0x48, 0x3F, 0xCB, 0x10, 0x10, 0x00 },
|
||||
{ 0x00, 0x00, 0xD8, 0xFF, 0x1B, 0x20, 0x00, 0x00 },
|
||||
},
|
||||
{ // RIGHT PIPE
|
||||
{
|
||||
0B00000110,
|
||||
0B00001000,
|
||||
0B00111110,
|
||||
0B00110000,
|
||||
0B00111000,
|
||||
0B00110110,
|
||||
0B00111000,
|
||||
0B00111000,
|
||||
},
|
||||
{
|
||||
0B00000000,
|
||||
0B00000110,
|
||||
0B00111000,
|
||||
0B00110000,
|
||||
0B00111110,
|
||||
0B00110000,
|
||||
0B00111000,
|
||||
0B00111000,
|
||||
},
|
||||
},
|
||||
{ // LEFT PIPE
|
||||
{
|
||||
0B00111000,
|
||||
0B00111000,
|
||||
0B00110110,
|
||||
0B00111000,
|
||||
0B00110000,
|
||||
0B00111110,
|
||||
0B00001000,
|
||||
0B00000110,
|
||||
},
|
||||
{
|
||||
0B00111000,
|
||||
0B00111000,
|
||||
0B00110000,
|
||||
0B00111110,
|
||||
0B00110000,
|
||||
0B00111000,
|
||||
0B00000110,
|
||||
0B00000000,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const PROGMEM uint8_t coinImage[8] =
|
||||
{
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00111100,
|
||||
0B01100110,
|
||||
0B00111100,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
};
|
||||
46
libraries/ssd1306/examples/games/lode_runner/sprites.h
Normal file
46
libraries/ssd1306/examples/games/lode_runner/sprites.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ssd1306.h"
|
||||
|
||||
enum
|
||||
{
|
||||
MAN_ANIM_FLYING = 0,
|
||||
MAN_ANIM_UP = 1,
|
||||
MAN_ANIM_DOWN = 1,
|
||||
MAN_ANIM_LEFT = 2,
|
||||
MAN_ANIM_RIGHT = 3,
|
||||
MAN_ANIM_RIGHT_PIPE = 4,
|
||||
MAN_ANIM_LEFT_PIPE = 5,
|
||||
|
||||
MAN_ANIM_MAX = 6,
|
||||
};
|
||||
|
||||
extern PROGMEM const uint8_t bgSprites[5][8];
|
||||
|
||||
extern const PROGMEM uint8_t playerFlyingImage[MAN_ANIM_MAX][2][8];
|
||||
|
||||
extern const PROGMEM uint8_t coinImage[8];
|
||||
@@ -0,0 +1,17 @@
|
||||
# HOW to run Lode runner in emulator mode
|
||||
|
||||
Read [instructions](https://github.com/lexus2k/ssd1306/wiki/How-to-run-emulator-mode) and
|
||||
install all required prerequisites.
|
||||
|
||||
## Compiling game and running emulation in Linux
|
||||
|
||||
> cd ssd1306/tools<br>
|
||||
> ./build_and_run.sh -p linux -e -f games/lode_runner<br>
|
||||
|
||||
## Compiling game and running emulation in Windows
|
||||
|
||||
For MinGW32 use the script below:
|
||||
> cd ssd1306\tools<br>
|
||||
> build_and_run.bat "games/lode_runner"<br>
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "game_basic.h"
|
||||
|
||||
|
||||
uint8_t gameField[B_WIDTH*14] =
|
||||
{
|
||||
5,0,0,0,0,3,3,0,0,0,0,5,5,0,0,0,0,3,3,0,0,0,0,5,0,0,0,0,0,5,
|
||||
5,0,2,0,0,4,0,2,1,1,2,0,0,0,0,0,4,0,0,2,1,1,2,5,0,0,0,0,0,5,
|
||||
5,0,2,0,0,1,0,2,0,0,1,1,5,2,0,0,1,1,0,2,0,0,1,1,1,1,1,1,1,5,
|
||||
5,0,2,1,0,0,0,2,0,4,0,0,0,2,0,0,0,0,0,2,0,4,0,5,0,0,0,0,0,5,
|
||||
5,1,2,1,1,1,1,1,1,1,1,1,5,1,5,2,1,1,1,1,1,1,1,1,1,1,1,1,1,5,
|
||||
5,0,2,0,0,0,0,0,4,0,0,0,0,0,5,2,0,0,0,0,4,0,0,5,0,0,0,0,0,5,
|
||||
1,1,1,1,1,1,1,2,1,1,1,1,1,2,0,2,1,1,1,1,1,1,1,1,1,1,1,1,1,5,
|
||||
5,0,0,0,0,3,3,2,0,0,0,5,5,1,1,1,0,3,3,0,0,0,0,5,0,0,0,0,0,5,
|
||||
5,0,2,0,4,0,0,2,1,1,2,0,0,0,0,0,4,0,0,2,1,1,2,5,0,0,0,0,0,5,
|
||||
5,0,2,0,1,1,0,2,0,0,1,1,5,2,0,0,1,1,0,2,0,0,1,1,1,1,1,1,1,5,
|
||||
5,0,2,0,0,0,0,2,0,4,0,0,0,2,0,0,0,0,0,2,0,4,0,5,0,0,0,0,0,5,
|
||||
5,1,2,1,1,1,1,1,1,1,1,1,5,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,
|
||||
5,0,2,0,0,0,0,0,4,0,0,5,5,0,2,0,0,0,0,0,4,0,0,5,0,0,0,0,0,5,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,
|
||||
};
|
||||
|
||||
GraphicsEngine engine;
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ssd1306.h"
|
||||
#include "nano_engine.h"
|
||||
|
||||
#define B_WIDTH 30
|
||||
|
||||
typedef NanoEngine<TILE_16x16_RGB8> GraphicsEngine;
|
||||
|
||||
extern uint8_t gameField[];
|
||||
extern GraphicsEngine engine;
|
||||
|
||||
static inline bool isWalkable(uint8_t type) { return (type == 0) || (type == 2) || (type == 3) || (type == 4); }
|
||||
static inline bool isSolid(uint8_t type) { return (type == 1) || (type == 2) || (type == 5); }
|
||||
static inline bool isPipe(uint8_t type) { return type == 3; }
|
||||
static inline bool isGold(uint8_t type) { return type == 4; }
|
||||
static inline bool isStair(uint8_t type) { return type == 2; }
|
||||
|
||||
static inline uint16_t block_index(const NanoPoint& block)
|
||||
{
|
||||
return block.x + block.y * B_WIDTH;
|
||||
}
|
||||
|
||||
static inline NanoPoint pos_to_block(const NanoPoint& pos)
|
||||
{
|
||||
return pos >> 3;
|
||||
}
|
||||
|
||||
static inline NanoPoint block_to_pos(const NanoPoint& block)
|
||||
{
|
||||
return block << 3;
|
||||
}
|
||||
|
||||
static inline NanoRect rect_to_blocks(const NanoRect& rect)
|
||||
{
|
||||
return rect >> 3;
|
||||
}
|
||||
|
||||
static inline uint8_t block_value(const NanoPoint& block)
|
||||
{
|
||||
uint16_t index = block_index(block);
|
||||
if (index >= B_WIDTH*14) index = 0;
|
||||
return gameField[index];
|
||||
}
|
||||
|
||||
static inline uint8_t block_at(const NanoPoint& p)
|
||||
{
|
||||
return block_value(pos_to_block(p));
|
||||
}
|
||||
|
||||
static inline void set_block_at(const NanoPoint& p, uint8_t v)
|
||||
{
|
||||
uint16_t index = block_index(pos_to_block(p));
|
||||
if (index >= B_WIDTH*14) index = 0;
|
||||
gameField[index] = v;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* Attiny85 PINS
|
||||
* ____
|
||||
* RESET -|_| |- 3V
|
||||
* SCL (3) -| |- (2)
|
||||
* SDA (4) -| |- (1) - BUZZER
|
||||
* GND -|____|- (0) - BUTTONS module
|
||||
*
|
||||
* Atmega328 PINS with i2c SSD1306 to A4/A5, BUZZER on D8,
|
||||
* Z-keypad ADC module on A0 pin.
|
||||
* If you want to use GPIO keys, uncomment USE_GPIO_BUTTONS below
|
||||
*
|
||||
* Atmega328 PINS with spi Nokia 5110 LCD:
|
||||
* LCD RST to D3
|
||||
* LCD CES to D4
|
||||
* LCD DC to D5
|
||||
* LCD DIN to D11
|
||||
* LCD CLK to D13
|
||||
* LCD BL to VCC
|
||||
*/
|
||||
|
||||
#include "game_basic.h"
|
||||
#include "ninja.h"
|
||||
#include "sprites.h"
|
||||
#include "intf/ssd1306_interface.h"
|
||||
#include "intf/spi/ssd1306_spi.h"
|
||||
|
||||
// Uncomment if you want to use gpio buttons
|
||||
//#define USE_GPIO_BUTTONS
|
||||
|
||||
#if defined(__AVR_ATtiny25__) | defined(__AVR_ATtiny45__) | defined(__AVR_ATtiny85__)
|
||||
#define BUZZER 1
|
||||
#define BUTTON_PIN 0
|
||||
#else // For Arduino Nano/Atmega328 we use different pins
|
||||
#define BUZZER 8
|
||||
#define BUTTON_PIN 0
|
||||
#ifdef USE_GPIO_BUTTONS
|
||||
static const uint8_t g_buttonsPins[6] = { 2, 6, 7, 8, 9, 12 };
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
const NanoRect game_window = { {0, 64}, {239, 319} };
|
||||
// Commented line is for 90 degree
|
||||
//const NanoRect game_window = { {64, 64}, {319, 239} };
|
||||
|
||||
uint8_t blockColors[] =
|
||||
{
|
||||
RGB_COLOR8(255,96,0),
|
||||
RGB_COLOR8(255,255,192),
|
||||
RGB_COLOR8(255,255,255),
|
||||
RGB_COLOR8(255,255,64),
|
||||
RGB_COLOR8(128,128,128),
|
||||
};
|
||||
|
||||
/**
|
||||
* Just produces some sound depending on params
|
||||
*/
|
||||
void beep(int bCount,int bDelay);
|
||||
|
||||
NanoFixedSprite<GraphicsEngine, engine> player( { 8, 8 }, { 8, 8 }, playerFlyingImage[0][0] );
|
||||
|
||||
/* The variable is used for player animation *
|
||||
* The graphics defined for the hero has 2 images *
|
||||
* for each direction. So, the variable is either *
|
||||
* 0 or 1. */
|
||||
uint8_t playerAnimation = 0;
|
||||
|
||||
/* Timestamp when playerAnimation was changed last time */
|
||||
uint16_t playerAnimationTs = 0;
|
||||
|
||||
/* Number of coins collected */
|
||||
uint8_t goldCollection = 0;
|
||||
|
||||
void showGameInfo()
|
||||
{
|
||||
engine.canvas.setMode(CANVAS_MODE_TRANSPARENT);
|
||||
engine.canvas.setColor(RGB_COLOR8(0,0,0));
|
||||
engine.canvas.drawBitmap1(1, 1, 8, 8, coinImage);
|
||||
engine.canvas.setColor(RGB_COLOR8(255,255,0));
|
||||
engine.canvas.drawBitmap1(0, 0, 8, 8, coinImage);
|
||||
|
||||
ssd1306_setFixedFont(digital_font5x7_AB);
|
||||
char score[3] = {goldCollection/10 + '0', goldCollection%10 + '0', 0};
|
||||
engine.canvas.setColor(RGB_COLOR8(0,0,0));
|
||||
engine.canvas.printFixed(9,1,score);
|
||||
engine.canvas.setColor(RGB_COLOR8(255,255,255));
|
||||
engine.canvas.printFixed(8,0,score);
|
||||
ssd1306_setFixedFont(digital_font5x7_AB);
|
||||
}
|
||||
|
||||
static bool onDraw()
|
||||
{
|
||||
engine.canvas.clear();
|
||||
engine.canvas.setMode(CANVAS_MODE_BASIC);
|
||||
if (game_window.containsPartOf( engine.canvas.rect() ))
|
||||
{
|
||||
engine.worldCoordinates();
|
||||
NanoRect blocks = rect_to_blocks( engine.canvas.rect() );
|
||||
for (uint8_t row = max(0,blocks.p1.y);
|
||||
row <= min(13,blocks.p2.y); row++)
|
||||
{
|
||||
for (uint8_t col = max(0,blocks.p1.x);
|
||||
col <= min((B_WIDTH-1),blocks.p2.x); col++)
|
||||
{
|
||||
uint8_t blockType = block_value({col,row});
|
||||
if (blockType != 0)
|
||||
{
|
||||
engine.canvas.setColor(blockColors[blockType - 1]);
|
||||
NanoPoint pos = block_to_pos({col,row});
|
||||
engine.canvas.drawBitmap1(pos.x, pos.y,
|
||||
8, 8, bgSprites[blockType - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
engine.canvas.setMode(CANVAS_MODE_TRANSPARENT);
|
||||
engine.canvas.setColor(RGB_COLOR8(64,255,255));
|
||||
player.draw();
|
||||
engine.canvas.setColor(RGB_COLOR8(64,64,255));
|
||||
ninja.draw();
|
||||
engine.localCoordinates();
|
||||
}
|
||||
showGameInfo();
|
||||
return true;
|
||||
}
|
||||
|
||||
static NanoPoint calc_new_screen_position()
|
||||
{
|
||||
NanoPoint position = engine.getPosition() + game_window.p1;
|
||||
if (player.x() - position.x >= game_window.width() - 24)
|
||||
{
|
||||
position.x = min(player.x() - (game_window.width() - 24), 128);
|
||||
}
|
||||
else if (player.x() - position.x < 24)
|
||||
{
|
||||
position.x = max(0, player.x() - 24);
|
||||
}
|
||||
if (player.y() - position.y >= game_window.height() - 24)
|
||||
{
|
||||
position.y = min(player.y() - (game_window.height() - 24), 64);
|
||||
}
|
||||
else if (player.y() - position.y < 24)
|
||||
{
|
||||
position.y = max(0, player.y() - 24);
|
||||
}
|
||||
return position - game_window.p1;
|
||||
}
|
||||
|
||||
static void moveGameScreen()
|
||||
{
|
||||
NanoPoint position = calc_new_screen_position();
|
||||
if (position != engine.getPosition())
|
||||
{
|
||||
engine.moveTo( position );
|
||||
engine.refresh( game_window );
|
||||
}
|
||||
}
|
||||
|
||||
void movePlayer(uint8_t direction)
|
||||
{
|
||||
bool animated = false;
|
||||
uint8_t bottomBlock = block_at(player.bottom());
|
||||
uint8_t feetBlock = block_at(player.bottom() + (NanoPoint){0,1});
|
||||
uint8_t handBlock = block_at(player.top());
|
||||
uint8_t centerBlock = block_at(player.center());
|
||||
uint8_t rightBlock = block_at(player.right());
|
||||
uint8_t leftBlock = block_at(player.left());
|
||||
moveGameScreen();
|
||||
/* If player doesn't stand on the ground, and doesn't hold the pipe,
|
||||
* make the player to fall down. */
|
||||
if ( !isSolid(feetBlock) &&
|
||||
(!isPipe(handBlock) || !isPipe(bottomBlock)) )
|
||||
{
|
||||
player.moveTo( { player.center().x & ~0x07, player.y() + 1 } );
|
||||
player.setBitmap( &playerFlyingImage[MAN_ANIM_FLYING][playerAnimation][0] );
|
||||
animated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case BUTTON_RIGHT:
|
||||
if (isWalkable(rightBlock))
|
||||
{
|
||||
player.moveBy( { 1, 0 } );
|
||||
if (isPipe(centerBlock))
|
||||
player.setBitmap( &playerFlyingImage[MAN_ANIM_RIGHT_PIPE][playerAnimation][0] );
|
||||
else
|
||||
player.setBitmap( &playerFlyingImage[MAN_ANIM_RIGHT][playerAnimation][0] );
|
||||
animated = true;
|
||||
}
|
||||
break;
|
||||
case BUTTON_LEFT:
|
||||
if (isWalkable(leftBlock))
|
||||
{
|
||||
player.moveBy( { -1, 0 } );
|
||||
if (isPipe(centerBlock))
|
||||
player.setBitmap( &playerFlyingImage[MAN_ANIM_LEFT_PIPE][playerAnimation][0] );
|
||||
else
|
||||
player.setBitmap( &playerFlyingImage[MAN_ANIM_LEFT][playerAnimation][0] );
|
||||
animated = true;
|
||||
}
|
||||
break;
|
||||
case BUTTON_UP:
|
||||
if (isStair(bottomBlock) || isStair(centerBlock))
|
||||
{
|
||||
player.moveTo( { player.top().x & ~0x07, player.top().y - 1 } );
|
||||
player.setBitmap( &playerFlyingImage[MAN_ANIM_UP][playerAnimation][0] );
|
||||
animated = true;
|
||||
}
|
||||
break;
|
||||
case BUTTON_DOWN:
|
||||
if ( isStair(feetBlock) ||
|
||||
(!isSolid(feetBlock) &&
|
||||
isPipe(handBlock)) )
|
||||
{
|
||||
player.moveTo( { player.top().x & ~0x07, player.top().y + 1 } );
|
||||
player.setBitmap( &playerFlyingImage[MAN_ANIM_DOWN][playerAnimation][0] );
|
||||
animated = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (animated && ((uint16_t)(millis() - playerAnimationTs) > 150))
|
||||
{
|
||||
playerAnimationTs = millis();
|
||||
playerAnimation = playerAnimation ? 0 : 1;
|
||||
beep(10,20);
|
||||
if (isGold(centerBlock))
|
||||
{
|
||||
engine.notify( "GOLD COIN" );
|
||||
set_block_at(player.center(), 0);
|
||||
goldCollection++;
|
||||
showGameInfo();
|
||||
engine.refresh(0,0,63,7);
|
||||
/* Produce sound every time the player moves */
|
||||
beep(20,40);
|
||||
beep(20,80);
|
||||
beep(20,120);
|
||||
beep(20,80);
|
||||
beep(20,40);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
ili9341_240x320_spi_init(3, 4, 5); // 3 RST, 4 CES, 5 DS
|
||||
|
||||
// ssd1306_128x64_i2c_init();
|
||||
// pcd8544_84x48_spi_init(3, 4, 5); // 3 RST, 4 CES, 5 DS
|
||||
// il9163_128x128_spi_init(3, 4, 5);
|
||||
// st7735_128x160_spi_init(3, 4, 5);
|
||||
|
||||
// Commented line is for 90 degree
|
||||
// ili9341_setRotation(1);
|
||||
player.setBitmap( playerFlyingImage[MAN_ANIM_FLYING][playerAnimation] );
|
||||
|
||||
#ifdef USE_GPIO_BUTTONS
|
||||
engine.connectGpioKeypad(g_buttonsPins);
|
||||
#else
|
||||
engine.connectZKeypad(BUTTON_PIN);
|
||||
#endif
|
||||
engine.drawCallback( onDraw );
|
||||
engine.begin();
|
||||
engine.setFrameRate(45);
|
||||
engine.refresh();
|
||||
pinMode(BUZZER, OUTPUT);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (!engine.nextFrame()) return;
|
||||
movePlayer(engine.buttonsState());
|
||||
ninja.move(player.getPosition());
|
||||
engine.display();
|
||||
}
|
||||
|
||||
|
||||
void beep(int bCount,int bDelay)
|
||||
{
|
||||
for (int i = 0; i<=bCount*2; i++)
|
||||
{
|
||||
digitalWrite(BUZZER,i&1);
|
||||
for(int i2=0; i2<bDelay; i2++)
|
||||
{
|
||||
__asm__("nop\n\t");
|
||||
#if F_CPU > 8000000
|
||||
__asm__("nop\n\t");
|
||||
__asm__("nop\n\t");
|
||||
__asm__("nop\n\t");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
digitalWrite(BUZZER,LOW);
|
||||
}
|
||||
159
libraries/ssd1306/examples/games/lode_runner_ili9341/ninja.cpp
Normal file
159
libraries/ssd1306/examples/games/lode_runner_ili9341/ninja.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ninja.h"
|
||||
#include "sprites.h"
|
||||
|
||||
#include "intf/ssd1306_interface.h"
|
||||
#include "intf/spi/ssd1306_spi.h"
|
||||
|
||||
Ninja ninja({72, 8});
|
||||
|
||||
void Ninja::move(const NanoPoint &target)
|
||||
{
|
||||
static uint16_t ninjaAnimationTs = 0;
|
||||
static uint8_t ninjaAnimation = 0;
|
||||
bool animated = false;
|
||||
uint8_t direction = BUTTON_NONE;
|
||||
uint8_t bottomBlock = block_at(bottom());
|
||||
uint8_t feetBlock = block_at(bottom() + (NanoPoint){0,1});
|
||||
uint8_t handBlock = block_at(top());
|
||||
uint8_t centerBlock = block_at(center());
|
||||
uint8_t rightBlock = block_at(right());
|
||||
uint8_t leftBlock = block_at(left());
|
||||
if ( !isSolid(feetBlock) &&
|
||||
(!isPipe(handBlock) || !isPipe(bottomBlock)) )
|
||||
{
|
||||
moveTo( { center().x & ~0x07, m_pos.y + 1 } );
|
||||
setBitmap( &playerFlyingImage[MAN_ANIM_FLYING][ninjaAnimation][0] );
|
||||
animated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target.y < m_pos.y - 1)
|
||||
{
|
||||
bool right = true;
|
||||
bool left = true;
|
||||
// search for stairs
|
||||
for (int8_t i=0; i < 80; i=i+8)
|
||||
{
|
||||
if (right)
|
||||
{
|
||||
uint8_t block = block_at(center() + (NanoPoint){i,0});
|
||||
if (!isWalkable(block)) { right = false; }
|
||||
if (isStair(block)) { direction = BUTTON_RIGHT; break; }
|
||||
}
|
||||
if (left)
|
||||
{
|
||||
uint8_t block = block_at(center() - (NanoPoint){i,0});
|
||||
if (!isWalkable(block)) { left = false; }
|
||||
if (isStair(block)) { direction = BUTTON_LEFT; break; }
|
||||
}
|
||||
}
|
||||
if (isStair(centerBlock) || isStair(bottomBlock)) direction = BUTTON_UP;
|
||||
}
|
||||
else if (target.y > m_pos.y + 1)
|
||||
{
|
||||
if (isPipe(handBlock))
|
||||
{
|
||||
direction = BUTTON_DOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool right = true;
|
||||
bool left = true;
|
||||
// search for stairs
|
||||
for (int8_t i=0; i < 80; i=i+8)
|
||||
{
|
||||
if (right)
|
||||
{
|
||||
uint8_t block = block_at(center() + (NanoPoint){i,0});
|
||||
if (!isWalkable(block)) right = false;
|
||||
else
|
||||
{
|
||||
block = block_at(bottom() + (NanoPoint){i,1});
|
||||
if (isWalkable(block)) { direction = BUTTON_RIGHT; break; }
|
||||
}
|
||||
}
|
||||
if (left)
|
||||
{
|
||||
uint8_t block = block_at(center() - (NanoPoint){i,0});
|
||||
if (!isWalkable(block)) left = false;
|
||||
else
|
||||
{
|
||||
block = block_at(bottom() + (NanoPoint){-i,1});
|
||||
if (isWalkable(block)) { direction = BUTTON_LEFT; break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isWalkable(feetBlock)) direction = BUTTON_DOWN;
|
||||
}
|
||||
}
|
||||
else if (target.x > m_pos.x)
|
||||
{
|
||||
if (isWalkable(rightBlock)) direction = BUTTON_RIGHT;
|
||||
}
|
||||
else if (target.x < m_pos.x)
|
||||
{
|
||||
if (isWalkable(leftBlock)) direction = BUTTON_LEFT;
|
||||
}
|
||||
switch (direction)
|
||||
{
|
||||
case BUTTON_RIGHT:
|
||||
moveBy( { 1, 0 } );
|
||||
if (isPipe(centerBlock))
|
||||
setBitmap( &playerFlyingImage[MAN_ANIM_RIGHT_PIPE][ninjaAnimation][0] );
|
||||
else
|
||||
setBitmap( &playerFlyingImage[MAN_ANIM_RIGHT][ninjaAnimation][0] );
|
||||
animated = true;
|
||||
break;
|
||||
case BUTTON_LEFT:
|
||||
moveBy( { -1, 0 } );
|
||||
if (isPipe(centerBlock))
|
||||
setBitmap( &playerFlyingImage[MAN_ANIM_LEFT_PIPE][ninjaAnimation][0] );
|
||||
else
|
||||
setBitmap( &playerFlyingImage[MAN_ANIM_LEFT][ninjaAnimation][0] );
|
||||
animated = true;
|
||||
break;
|
||||
case BUTTON_UP:
|
||||
moveTo( { top().x & ~0x07, top().y - 1 } );
|
||||
setBitmap( &playerFlyingImage[MAN_ANIM_UP][ninjaAnimation][0] );
|
||||
animated = true;
|
||||
break;
|
||||
case BUTTON_DOWN:
|
||||
moveTo( { top().x & ~0x07, top().y + 1 } );
|
||||
setBitmap( &playerFlyingImage[MAN_ANIM_DOWN][ninjaAnimation][0] );
|
||||
animated = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (animated && ((uint16_t)(millis() - ninjaAnimationTs) > 150))
|
||||
{
|
||||
ninjaAnimationTs = millis();
|
||||
ninjaAnimation = ninjaAnimation ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
39
libraries/ssd1306/examples/games/lode_runner_ili9341/ninja.h
Normal file
39
libraries/ssd1306/examples/games/lode_runner_ili9341/ninja.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "game_basic.h"
|
||||
#include "sprites.h"
|
||||
|
||||
class Ninja: public NanoFixedSprite<GraphicsEngine, engine>
|
||||
{
|
||||
public:
|
||||
explicit Ninja(NanoPoint pos)
|
||||
: NanoFixedSprite<GraphicsEngine, engine>(pos, {8,8}, playerFlyingImage[0][0]) {}
|
||||
|
||||
void move(const NanoPoint &target);
|
||||
};
|
||||
|
||||
extern Ninja ninja;
|
||||
Binary file not shown.
Binary file not shown.
154
libraries/ssd1306/examples/games/lode_runner_ili9341/sprites.cpp
Normal file
154
libraries/ssd1306/examples/games/lode_runner_ili9341/sprites.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "sprites.h"
|
||||
|
||||
PROGMEM const uint8_t bgSprites[5][8] =
|
||||
{
|
||||
{
|
||||
0B01110111,
|
||||
0B01110111,
|
||||
0B01110000,
|
||||
0B01110111,
|
||||
0B01110111,
|
||||
0B00000111,
|
||||
0B01110111,
|
||||
0B01110111,
|
||||
},
|
||||
{
|
||||
0B00010001,
|
||||
0B11111111,
|
||||
0B00010001,
|
||||
0B00010001,
|
||||
0B00010001,
|
||||
0B11111111,
|
||||
0B00010001,
|
||||
0B00000000,
|
||||
},
|
||||
{
|
||||
0B00000010,
|
||||
0B00000010,
|
||||
0B00000010,
|
||||
0B00000010,
|
||||
0B00000010,
|
||||
0B00000010,
|
||||
0B00000010,
|
||||
0B00000010,
|
||||
},
|
||||
{
|
||||
0B00000000,
|
||||
0B11000000,
|
||||
0B11100000,
|
||||
0B10110000,
|
||||
0B11010000,
|
||||
0B10100000,
|
||||
0B11000000,
|
||||
0B00000000,
|
||||
},
|
||||
{
|
||||
0B01111111,
|
||||
0B01111111,
|
||||
0B01111111,
|
||||
0B01110111,
|
||||
0B01111111,
|
||||
0B01111111,
|
||||
0B01111111,
|
||||
0B00000000,
|
||||
},
|
||||
};
|
||||
|
||||
const PROGMEM uint8_t playerFlyingImage[MAN_ANIM_MAX][2][8] = {
|
||||
{ // FLYING
|
||||
{ 0x00, 0x04, 0x88, 0x4B, 0x3F, 0x48, 0x88, 0x04 },
|
||||
{ 0x00, 0x10, 0x08, 0xCB, 0x3F, 0xC8, 0x08, 0x10 },
|
||||
},
|
||||
{ // UP + DOWN
|
||||
{ 0x00, 0x00, 0x90, 0x4B, 0x3F, 0x28, 0x66, 0x00 },
|
||||
{ 0x00, 0x00, 0x66, 0x2B, 0x3F, 0x48, 0x90, 0x00 },
|
||||
},
|
||||
{ // LEFT
|
||||
{ 0x00, 0x10, 0x10, 0xCB, 0x3F, 0x48, 0x90, 0x00 },
|
||||
{ 0x00, 0x00, 0x20, 0x1B, 0xFF, 0xD8, 0x00, 0x00 },
|
||||
},
|
||||
{ // RIGHT
|
||||
{ 0x00, 0x90, 0x48, 0x3F, 0xCB, 0x10, 0x10, 0x00 },
|
||||
{ 0x00, 0x00, 0xD8, 0xFF, 0x1B, 0x20, 0x00, 0x00 },
|
||||
},
|
||||
{ // RIGHT PIPE
|
||||
{
|
||||
0B00000110,
|
||||
0B00001000,
|
||||
0B00111110,
|
||||
0B00110000,
|
||||
0B00111000,
|
||||
0B00110110,
|
||||
0B00111000,
|
||||
0B00111000,
|
||||
},
|
||||
{
|
||||
0B00000000,
|
||||
0B00000110,
|
||||
0B00111000,
|
||||
0B00110000,
|
||||
0B00111110,
|
||||
0B00110000,
|
||||
0B00111000,
|
||||
0B00111000,
|
||||
},
|
||||
},
|
||||
{ // LEFT PIPE
|
||||
{
|
||||
0B00111000,
|
||||
0B00111000,
|
||||
0B00110110,
|
||||
0B00111000,
|
||||
0B00110000,
|
||||
0B00111110,
|
||||
0B00001000,
|
||||
0B00000110,
|
||||
},
|
||||
{
|
||||
0B00111000,
|
||||
0B00111000,
|
||||
0B00110000,
|
||||
0B00111110,
|
||||
0B00110000,
|
||||
0B00111000,
|
||||
0B00000110,
|
||||
0B00000000,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const PROGMEM uint8_t coinImage[8] =
|
||||
{
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00111100,
|
||||
0B01100110,
|
||||
0B00111100,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
0B00000000,
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ssd1306.h"
|
||||
|
||||
enum
|
||||
{
|
||||
MAN_ANIM_FLYING = 0,
|
||||
MAN_ANIM_UP = 1,
|
||||
MAN_ANIM_DOWN = 1,
|
||||
MAN_ANIM_LEFT = 2,
|
||||
MAN_ANIM_RIGHT = 3,
|
||||
MAN_ANIM_RIGHT_PIPE = 4,
|
||||
MAN_ANIM_LEFT_PIPE = 5,
|
||||
|
||||
MAN_ANIM_MAX = 6,
|
||||
};
|
||||
|
||||
extern PROGMEM const uint8_t bgSprites[5][8];
|
||||
|
||||
extern const PROGMEM uint8_t playerFlyingImage[MAN_ANIM_MAX][2][8];
|
||||
|
||||
extern const PROGMEM uint8_t coinImage[8];
|
||||
Reference in New Issue
Block a user