Showing preview only (620K chars total). Download the full file or copy to clipboard to get everything.
Repository: andyhighnumber/Attiny-Arduino-Games
Branch: master
Commit: f9b99e4980c3
Files: 36
Total size: 598.6 KB
Directory structure:
gitextract_6g324x5n/
├── BatBonanzaAnalog/
│ ├── BatBonanzaAnalog.ino
│ └── font6x8AJ.h
├── BatBonanzaAnalogSinglePot/
│ ├── BatBonanzaAnalogSinglePot.ino
│ └── font6x8AJ.h
├── BatBonanzaAttinyArcade/
│ ├── BatBonanzaAttinyArcade.ino
│ └── font6x8AJ.h
├── Frogger_Attiny_Arcade/
│ ├── Frogger_Attiny_Arcade.ino
│ └── font6x8AJ2.h
├── Frogger_MAKERbuino/
│ ├── Bitmaps/
│ │ └── InfEncoder.jar
│ ├── Frogger_MAKERbuino.ino
│ ├── HEX and INF/
│ │ ├── FROGGER.HEX
│ │ └── FROGGER.INF
│ └── font6x8AJ4.h
├── MorseAttinyArcade/
│ ├── MorseAttinyArcade.ino
│ └── font6x8AJ.h
├── PAK-MAN_MAKERbuino/
│ ├── HEX and INF/
│ │ ├── PAKMAN.HEX
│ │ └── PAKMAN.INF
│ ├── PAK-MAN_MAKERbuino.ino
│ └── font6x8AJ4.h
├── Pacman_Attiny_Arcade/
│ ├── Pacman_Attiny_Arcade.ino
│ └── font6x8AJ3.h
├── README.md
├── SpaceAttackAttiny/
│ ├── SpaceAttackAttiny.ino
│ └── font6x8AJ.h
├── Space_Attack_Analog/
│ ├── Space_Attack_Analog.ino
│ └── font6x8AJ.h
├── Tetris_Attiny_Arcade/
│ ├── Tetris_Attiny_Arcade.ino
│ └── font8x8AJ.h
├── Tetris_Multi_Button/
│ ├── Tetris_Multi_Button.ino
│ └── font8x8AJ.h
├── UFO_Breakout_Arduino/
│ ├── UFO_Breakout_Arduino.ino
│ └── font6x8AJ.h
├── UFO_Stacker_Attiny/
│ ├── UFO_Stacker_Attiny.ino
│ └── font6x8AJ.h
└── WrenRollercoasterAttinyArcade/
├── WrenRollercoasterAttinyArcade.ino
└── font6x8AJ.h
================================================
FILE CONTENTS
================================================
================================================
FILE: BatBonanzaAnalog/BatBonanzaAnalog.ino
================================================
/* 2015 / 2016 /2017
* Pong clone by Andy Jackson - Twitter @andyhighnumber
* Inspired by http://webboggles.com/ and includes some code from the #AttinyArcade games on that site
* The code that does not fall under the licenses of sources listed below can be used non commercially with attribution.
*
* This code takes its inputs from two paddles - one on pin 7 (the centre of a 10k linear pot between the power rails), the other
* on the reset pin - this time with a 6k8 resistor between the negative leg of the pot and ground (to stop it resetting the ATTINY85!)
* You should be able to find the circuit diagram from the folder where these files are (if you got them from my Google Drive) otherwise
* Tweet @andyhighnumber and I will direct you to the circuit.
*
* There's one button in this design (on pin 5). When the game is running, pressing and releasing the button cycles through modes, including
* two-player games and one-player modes with varying degrees of difficulty.
*
* Also, from standby....
* Press and hold the button to reset all settings (good to do when you first flash the chip, since the settings are loaded from EEPROM)
*
* If you have problems uploading this sketch, this is probably due to sketch size - you need to update ld.exe in arduino\hardware\tools\avr\avr\bin
* https://github.com/TCWORLD/ATTinyCore/tree/master/PCREL%20Patch%20for%20GCC
*
* This sketch is using the screen control and font functions written by Neven Boyanov for the http://tinusaur.wordpress.com/ project
* Source code and font files available at: https://bitbucket.org/tinusaur/ssd1306xled
* **Note that this highly size-optimised version requires modified library functions (which are in this source code file)
* and a modified font header
*
* Sleep code is based on this blog post by Matthew Little:
* http://www.re-innovation.co.uk/web12/index.php/en/blog-75/306-sleep-modes-on-attiny85
*/
#include <EEPROM.h>
#include "font6x8AJ.h"
#include <avr/sleep.h>
#include <avr/interrupt.h> // needed for the additional interrupt
#define DIGITAL_WRITE_HIGH(PORT) PORTB |= (1 << PORT)
#define DIGITAL_WRITE_LOW(PORT) PORTB &= ~(1 << PORT)
// Routines to set and clear bits (used in the sleep code)
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
// Defines for OLED output
#define SSD1306XLED_H
#define SSD1306_SCL PORTB4 // SCL, Pin 4 on SSD1306 Board - for webbogles board
#define SSD1306_SDA PORTB3 // SDA, Pin 3 on SSD1306 Board - for webbogles board
#define SSD1306_SA 0x78 // Slave address
#define WINSCORE 7
// Function prototypes
void startGame(void);
void drawPlatform(void);
void drawPlatform2(void);
void sendBlock(int);
void playPong(void);
void beep(int,int);
void drawBall(int x, int y);
void blankBall(int x, int y);
void doDrawLS(long, byte);
void doDrawRS(long, byte);
void doNumber (int x, int y, int value);
void ssd1306_init(void);
void ssd1306_xfer_start(void);
void ssd1306_xfer_stop(void);
void ssd1306_send_byte(uint8_t byte);
void ssd1306_send_command(uint8_t command);
void ssd1306_send_data_start(void);
void ssd1306_send_data_stop(void);
void ssd1306_setpos(uint8_t x, uint8_t y);
void ssd1306_fillscreen(uint8_t fill_Data);
void ssd1306_char_f6x8(uint8_t x, uint8_t y, const char ch[]);
void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t bitmap[]);
int topScoreB = 0;
int player; //0 to 128-platformWidth - this is the position of the player
int player2; //0 to 128-platformWidth - this is the position of the player
int lastPlayer;
int lastPlayer2;
int platformWidth = 16;
boolean stopAnimate = 0; // this is set to 1 when a collision is detected
boolean mute = 0;
int score = 0; // score - this affects the difficulty of the game
int score2 = 0; // score - this affects the difficulty of the game
int ballx = 62*8; // coordinate of the ball
int bally = 50*4; // coordinate of the ball
int vdir = -4; // vertical direction and step distance
int hdir = -8; // horizontal direction and step distance
int mode = 0;
int perturbation = 0;
int pFactor = 12;
// Interrupt handlers
ISR(PCINT0_vect){ // PB0 pin button interrupt
}
void playerIncPong(){ // PB2 pin button interrupt
}
// Arduino stuff - setup
void setup() {
DDRB = 0b00000010; // set PB1 as output (for the speaker)
PCMSK = 0b00000001; // pin change mask: listen to portb bit 1
GIMSK |= 0b00100000; // enable PCINT interrupt
sei(); // enable all interrupts
}
// Arduino stuff - loop
void loop() {
ssd1306_init();
ssd1306_fillscreen(0x00);
// The lower case character set is seriously compromised because I've had to truncate the ASCII table
// to release space for executable code - hence lower case y and w are remapped to h and / respectively.
// There is no z in the table (or h!) as these aren't used anywhere in the text here and most of the
// symbols are also missing for the same reason (see my hacked version of font6x8.h - font6x8AJ.h for more detail)
ssd1306_char_f6x8(0, 1, " --------------- ");
ssd1306_char_f6x8(0, 2, " B A T ");
ssd1306_char_f6x8(0, 4, " B O N A N Z A ");
ssd1306_char_f6x8(0, 5, " --------------- ");
ssd1306_char_f6x8(0, 7, " bh andh jackson "); // see comments above !
long startT = millis();
long nowT =0;
boolean sChange = 0;
while(digitalRead(0) == HIGH) {
nowT = millis();
if (nowT - startT > 2000) {
sChange = 1;
EEPROM.write(0,0);
EEPROM.write(1,0);
ssd1306_char_f6x8(16, 0, "- SYSTEM RESET -");
break;
}
if (sChange == 1) break;
}
while(digitalRead(0) == HIGH);
mute=EEPROM.read(0);
mode=EEPROM.read(1);
if (mute != 0 && mute != 1) {
mute = 0;
EEPROM.write(0,0);
}
if (mode < 0 || mode > 5) {
mode = 0;
EEPROM.write(1,0);
}
if (sChange != 1) {
delay(1500);
ssd1306_init();
ssd1306_fillscreen(0x00);
stopAnimate = 0;
score = 0;
score2 = 0;
playPong();
delay(3500);
}
system_sleep();
}
void doNumber (int x, int y, int value) {
char temp[10] = {0,0,0,0,0,0,0,0,0,0};
itoa(value,temp,10);
ssd1306_char_f6x8(x, y, temp);
}
void ssd1306_init(void){
DDRB |= (1 << SSD1306_SDA); // Set port as output
DDRB |= (1 << SSD1306_SCL); // Set port as output
ssd1306_send_command(0xAE); // display off
ssd1306_send_command(0x00); // Set Memory Addressing Mode
ssd1306_send_command(0x10); // 00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
ssd1306_send_command(0x40); // Set Page Start Address for Page Addressing Mode,0-7
ssd1306_send_command(0x81); // Set COM Output Scan Direction
ssd1306_send_command(0xCF); // ---set low column address
ssd1306_send_command(0xA1); // ---set high column address
ssd1306_send_command(0xC8); // --set start line address
ssd1306_send_command(0xA6); // --set contrast control register
ssd1306_send_command(0xA8);
ssd1306_send_command(0x3F); // --set segment re-map 0 to 127
ssd1306_send_command(0xD3); // --set normal display
ssd1306_send_command(0x00); // --set multiplex ratio(1 to 64)
ssd1306_send_command(0xD5); //
ssd1306_send_command(0x80); // 0xa4,Output follows RAM content;0xa5,Output ignores RAM content
ssd1306_send_command(0xD9); // -set display offset
ssd1306_send_command(0xF1); // -not offset
ssd1306_send_command(0xDA); // --set display clock divide ratio/oscillator frequency
ssd1306_send_command(0x12); // --set divide ratio
ssd1306_send_command(0xDB); // --set pre-charge period
ssd1306_send_command(0x40); //
ssd1306_send_command(0x20); // --set com pins hardware configuration
ssd1306_send_command(0x02);
ssd1306_send_command(0x8D); // --set vcomh
ssd1306_send_command(0x14); // 0x20,0.77xVcc
ssd1306_send_command(0xA4); // --set DC-DC enable
ssd1306_send_command(0xA6); //
ssd1306_send_command(0xAF); // --turn on oled panel
}
void ssd1306_xfer_start(void){
DIGITAL_WRITE_HIGH(SSD1306_SCL); // Set to HIGH
DIGITAL_WRITE_HIGH(SSD1306_SDA); // Set to HIGH
DIGITAL_WRITE_LOW(SSD1306_SDA); // Set to LOW
DIGITAL_WRITE_LOW(SSD1306_SCL); // Set to LOW
}
void ssd1306_xfer_stop(void){
DIGITAL_WRITE_LOW(SSD1306_SCL); // Set to LOW
DIGITAL_WRITE_LOW(SSD1306_SDA); // Set to LOW
DIGITAL_WRITE_HIGH(SSD1306_SCL); // Set to HIGH
DIGITAL_WRITE_HIGH(SSD1306_SDA); // Set to HIGH
}
void ssd1306_send_byte(uint8_t byte){
uint8_t i;
for(i=0; i<8; i++)
{
if((byte << i) & 0x80)
DIGITAL_WRITE_HIGH(SSD1306_SDA);
else
DIGITAL_WRITE_LOW(SSD1306_SDA);
DIGITAL_WRITE_HIGH(SSD1306_SCL);
DIGITAL_WRITE_LOW(SSD1306_SCL);
}
DIGITAL_WRITE_HIGH(SSD1306_SDA);
DIGITAL_WRITE_HIGH(SSD1306_SCL);
DIGITAL_WRITE_LOW(SSD1306_SCL);
}
void ssd1306_send_command(uint8_t command){
ssd1306_xfer_start();
ssd1306_send_byte(SSD1306_SA); // Slave address, SA0=0
ssd1306_send_byte(0x00); // write command
ssd1306_send_byte(command);
ssd1306_xfer_stop();
}
void ssd1306_send_data_start(void){
ssd1306_xfer_start();
ssd1306_send_byte(SSD1306_SA);
ssd1306_send_byte(0x40); //write data
}
void ssd1306_send_data_stop(void){
ssd1306_xfer_stop();
}
void ssd1306_setpos(uint8_t x, uint8_t y)
{
if (y>7) return;
ssd1306_xfer_start();
ssd1306_send_byte(SSD1306_SA); //Slave address,SA0=0
ssd1306_send_byte(0x00); //write command
ssd1306_send_byte(0xb0+y);
ssd1306_send_byte(((x&0xf0)>>4)|0x10); // |0x10
ssd1306_send_byte((x&0x0f)|0x01); // |0x01
ssd1306_xfer_stop();
}
void ssd1306_fillscreen(uint8_t fill_Data){
uint8_t m,n;
for(m=0;m<8;m++)
{
ssd1306_send_command(0xb0+m); //page0-page1
ssd1306_send_command(0x00); //low column start address
ssd1306_send_command(0x10); //high column start address
ssd1306_send_data_start();
for(n=0;n<128;n++)
{
ssd1306_send_byte(fill_Data);
}
ssd1306_send_data_stop();
}
}
void ssd1306_char_f6x8(uint8_t x, uint8_t y, const char ch[]){
uint8_t c,i,j=0;
while(ch[j] != '\0')
{
c = ch[j] - 32;
if (c >0) c = c - 12;
if (c >15) c = c - 6;
if (c>40) c=c-6;
if(x>126)
{
x=0;
y++;
}
ssd1306_setpos(x,y);
ssd1306_send_data_start();
for(i=0;i<6;i++)
{
ssd1306_send_byte(pgm_read_byte(&ssd1306xled_font6x8[c*6+i]));
}
ssd1306_send_data_stop();
x += 6;
j++;
}
}
void system_sleep() {
ssd1306_fillscreen(0x00);
ssd1306_send_command(0xAE);
cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF
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
sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON
ssd1306_send_command(0xAF);
}
void beep(int bCount,int bDelay){
if (mute) return;
for (int i = 0; i<=bCount; i++){digitalWrite(1,HIGH);for(int i2=0; i2<bDelay; i2++){__asm__("nop\n\t");}digitalWrite(1,LOW);for(int i2=0; i2<bDelay; i2++){__asm__("nop\n\t");}}
}
/* ------------------------
* Pong Code
*/
void playPong() {
ballx = 64*8;
bally = 32*4;
hdir = -8;
vdir = -4;
int actualy, actualx;
int factor = 0;
int waitCount = 0;
int lastx=64*8, lasty=32*4;
player=64;
player2=64;
lastPlayer = 64;
lastPlayer2 = 64;
score = 0; // obvious
score2 = 0; // obvious
perturbation = 0;
startGame();
while (stopAnimate == 0) {
while(1) {
waitCount++;
if(digitalRead(0)==1) {
boolean sChange = 0;
long startT = millis();
long nowT =0;
while(digitalRead(0) == HIGH) {
nowT = millis();
if (nowT - startT > 1500) {
sChange = 1;
if (mute == 0) { mute = 1; ssd1306_char_f6x8(32, 0, "-- MUTE --"); } else { mute = 0; ssd1306_char_f6x8(23, 0, "-- SOUND ON --"); }
break;
}
}
while(digitalRead(0) == HIGH);
if (sChange == 1) {
} else if (mode == 0) {
mode = 1;
ssd1306_char_f6x8(26, 0, "-- EXPERT --");
} else if (mode == 1) {
mode = 2;
pFactor = 11;
ssd1306_char_f6x8(32, 0, "-- AUTO --");
} else if (mode == 2) {
mode = 3;
pFactor = 11;
ssd1306_char_f6x8(20, 0, "- TOUGH AUTO -");
} else if (mode == 3) {
mode = 4;
pFactor = 10;
ssd1306_char_f6x8(16, 0, "- EXPERT AUTO -");
} else if (mode == 4) {
mode = 0;
ssd1306_char_f6x8(26, 0, "-- NORMAL --");
}
if (sChange == 0) delay(1000);
ssd1306_fillscreen(0x00);
EEPROM.write(0,mute);
EEPROM.write(1,mode);
}
player = ((analogRead(0)-560)/7);
if (player > 48) player = 48;
if (player <0) player = 0;
player2 = (analogRead(1) / 16);
if (mode == 2 || mode == 3 || mode == 4) {
if(waitCount >= 3) {
waitCount = 0;
perturbation = perturbation - 2 + random(0,5);
if (perturbation > pFactor) perturbation = pFactor - 2;
if (perturbation < pFactor*-1) perturbation = (pFactor*-1)+2;
}
player2 = (bally/4 -8)+perturbation;
}
if (player2 > 48) player2 = 48;
if (player2 <0) player2 = 0;
actualy = floor(bally/4);
actualx = floor(ballx/8);
// bounce off the sides of the screen
if ((actualy+vdir<63&&vdir>01) || (actualy- vdir>6&&vdir<0)){
bally+=vdir;
}else {
vdir = vdir*-1;
}
ballx+=hdir;
actualy = floor(bally/4);
actualx = floor(ballx/8);
// check it hits the left pad and deal with bounces and misses
if (actualx <= 4) {
if(actualy<player-1||actualy>player+platformWidth+1){
score2++;
ballx = 5*8;
bally = player*4;
hdir = 13;
if (vdir > 0) {
vdir = 2;
} else vdir = -2;
ssd1306_fillscreen(0x00);
doNumber(46,4,score);
doNumber(78,4,score2);
if (score2 < WINSCORE) {
for (int i = 0; i<1000; i = i+ 100){
beep(50,i);
}
for (int incr=0;incr<3;incr++) {
ssd1306_send_data_stop();
ssd1306_setpos(78,4);
ssd1306_send_data_start();
sendBlock(0);
sendBlock(0);
ssd1306_send_data_stop();
delay(350);
doNumber(78,4,score2);
delay(350);
}
startGame();
}
perturbation = 0;
break;
}else if (actualy<player+1){
vdir = -6;
hdir = 7;
}else if (actualy<player+4){
vdir = -4;
hdir = 10;
}else if (actualy<player+7){
vdir = -2;
hdir = 13;
}else if (actualy<player+9){
vdir = 0;
hdir = 14;
}else if (actualy<player+12){
vdir = 2;
hdir = 13;
}else if (actualy<player+15){
vdir = 4;
hdir = 10;
}else {
vdir = 6;
hdir = 7;
}
beep(20,600);
}
// check it hits the right pad and deal with bounces
if(actualx >= 122) {
if(actualy<player2-1||actualy>player2+platformWidth+1){
score++;
ballx = 120*8;
bally = player2*4;
hdir = -13;
if (vdir > 0) {
vdir = 2;
} else vdir = -2;
ssd1306_fillscreen(0x00);
doNumber(46,4,score);
doNumber(78,4,score2);
if (score < WINSCORE) {
for (int i = 0; i<1000; i = i+ 100){
beep(50,i);
}
for (int incr=0;incr<3;incr++) {
ssd1306_setpos(46,4);
ssd1306_send_data_start();
sendBlock(0);
sendBlock(0);
ssd1306_send_data_stop();
delay(350);
doNumber(46,4,score);
delay(350);
}
perturbation = 0;
startGame();
}
break;
}else if (actualy<player2+1){
vdir = -6;
hdir = -7;
}else if (actualy<player2+4){
vdir = -4;
hdir = -10;
}else if (actualy<player2+7){
vdir = -2;
hdir = -13;
}else if (actualy<player2+9){
vdir = 0;
hdir = -14;
}else if (actualy<player2+12){
vdir = 2;
hdir = -13;
}else if (actualy<player2+15){
vdir = 4;
hdir = -10;
}else {
vdir = 6;
hdir = -7;
}
beep(20,300);
}
if (mode == 1 || mode == 3 || mode == 4) {
factor = 8-floor((score-score2)/2); // expert modes
if (factor < 2) factor = 2;
} else {
factor = 20-floor((score-score2)/2); // normal modes
if (factor < 10) factor = 10;
}
delay(factor);
// draw ball
blankBall(floor(lastx/8),floor(lasty/4));
drawPlatform();
drawPlatform2();
drawBall(floor(ballx/8),floor(bally/4));
lastx = ballx;
lasty = bally;
doNumber(28,0,score);
doNumber(92,0,score2);
if (score == WINSCORE || score2 == WINSCORE) {
stopAnimate = 1;
break;
}
}
}
blankBall(floor(lastx/8),floor(lasty/4));
blankBall(floor(ballx/8),floor(bally/4));
if (score > score2) {
ssd1306_char_f6x8(27, 3, "P L A Y E R 1");
} else {
ssd1306_char_f6x8(27, 3, "P L A Y E R 2");
}
ssd1306_char_f6x8(27, 4, " ");
ssd1306_char_f6x8(27, 5, " W I N S ");
for (int i = 0; i<1000; i = i+ 50){
beep(50,i);
}
for (int incr=0;incr<6;incr++) {
ssd1306_setpos(28,0);
ssd1306_send_data_start();
sendBlock(0);
sendBlock(0);
ssd1306_send_data_stop();
ssd1306_setpos(92,0);
ssd1306_send_data_start();
sendBlock(0);
sendBlock(0);
ssd1306_send_data_stop();
delay(350);
doNumber(28,0,score);
doNumber(92,0,score2);
delay(350);
}
}
void drawPlatform() {
if (player != lastPlayer) {
ssd1306_setpos(0,lastPlayer/8);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(0,lastPlayer/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(0,lastPlayer/8+2);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
}
if (player%8!=0){
ssd1306_setpos(0,player/8);
ssd1306_send_data_start();
ssd1306_send_byte((B11111111)<<player%8);
ssd1306_send_data_stop();
ssd1306_setpos(0,player/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B11111111);
ssd1306_send_data_stop();
ssd1306_setpos(0,player/8+2);
ssd1306_send_data_start();
ssd1306_send_byte((B01111110)>>8-player%8);
ssd1306_send_data_stop();
} else {
ssd1306_setpos(0,player/8);
ssd1306_send_data_start();
ssd1306_send_byte(B11111111);
ssd1306_send_data_stop();
ssd1306_setpos(0,player/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B11111111);
ssd1306_send_data_stop();
}
lastPlayer = player;
}
void drawPlatform2() {
if (player2 != lastPlayer2) {
ssd1306_setpos(127,lastPlayer2/8);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(127,lastPlayer2/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(127,lastPlayer2/8+2);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
}
if (player2%8!=0){
ssd1306_setpos(127,player2/8);
ssd1306_send_data_start();
ssd1306_send_byte((B11111111)<<player2%8);
ssd1306_send_data_stop();
ssd1306_setpos(127,player2/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B11111111);
ssd1306_send_data_stop();
ssd1306_setpos(127,player2/8+2);
ssd1306_send_data_start();
ssd1306_send_byte((B01111110)>>8-player2%8);
ssd1306_send_data_stop();
} else {
ssd1306_setpos(127,player2/8);
ssd1306_send_data_start();
ssd1306_send_byte((B11111111)<<0);
ssd1306_send_data_stop();
ssd1306_setpos(127,player2/8+1);
ssd1306_send_data_start();
ssd1306_send_byte((B11111111)<<0);
ssd1306_send_data_stop();
}
lastPlayer2 = player2;
}
void sendBlock(int fill){
if (fill == 1) {
ssd1306_send_byte(B10011000);
ssd1306_send_byte(B01011100);
ssd1306_send_byte(B10110110);
ssd1306_send_byte(B01011111);
ssd1306_send_byte(B01011111);
ssd1306_send_byte(B10110110);
ssd1306_send_byte(B01011100);
ssd1306_send_byte(B10011000);
} else {
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
}
}
void blankBall(int x, int y) {
if (y%8!=0){
ssd1306_setpos(x,y/8);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(x,y/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
} else {
ssd1306_setpos(x,y/8);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
}
}
void drawBall(int x, int y) {
if (y%8!=0){
ssd1306_setpos(x,y/8);
ssd1306_send_data_start();
doDrawLS(0,y%8);
ssd1306_send_data_stop();
ssd1306_setpos(x,y/8+1);
ssd1306_send_data_start();
doDrawRS(0,8-y%8);
ssd1306_send_data_stop();
} else {
ssd1306_setpos(x,y/8);
ssd1306_send_data_start();
doDrawLS(0,0);
ssd1306_send_data_stop();
}
}
// Drawing routine for the player and fire - with right-shifts
void doDrawRS(long P1, byte P2) {
ssd1306_send_byte((B00000011 | P1)>>P2);
ssd1306_send_byte((B00000011 | P1)>>P2);
}
// Drawing routine for the player and fire - with left-shifts
void doDrawLS(long P1, byte P2) {
ssd1306_send_byte((B00000011 | P1)<<P2);
ssd1306_send_byte((B00000011 | P1)<<P2);
}
void startGame(void) {
ssd1306_fillscreen(0x00);
ssd1306_char_f6x8(16, 3, "-- GET READY --");
doNumber(60,5,3);
delay(1000);
doNumber(60,5,2);
delay(1000);
doNumber(60,5,1);
delay(1000);
ssd1306_fillscreen(0x00);
for (int i = 800; i>200; i = i - 200){
beep(30,i);
}
}
================================================
FILE: BatBonanzaAnalog/font6x8AJ.h
================================================
/*
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
*
* @file: font6x8.h
* @created: 2014-08-12
* @author: Neven Boyanov
*
* Hacked by andy jackson to allow two games (originally by webboggles.com) to
* fit onto an ATTiny85 at the same time - hence several characters are missing
* and a couple have been moved to limit the amount of software remapping required
* to map ASCII values onto locations in this array.
*
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
*
*/
// ----------------------------------------------------------------------------
#include <avr/pgmspace.h>
// ----------------------------------------------------------------------------
/* Standard ASCII 6x8 font */
static const uint8_t ssd1306xled_font6x8 [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
/*
0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
0x00, 0x62, 0x64, 0x08, 0x13, 0x23, // %
0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // &
0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // '
0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // *
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // +
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // ,
*/
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // -
0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // .
0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w in place of /
//0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // /
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // :
/*
0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // =
0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // >
0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @
*/
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B
0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C
0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E
0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F
0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G
0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I
0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J
0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K
0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L
0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P
0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R
0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S
0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T
0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W
0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X
0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
/*
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [
0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 55
0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // '
*/
0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a
0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b
0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c
0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d
0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e
0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f
0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y (in place of h)
//0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h
0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i
0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l
0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m
0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n
0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o
0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p
0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q
0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r
0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s
0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t
0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
// 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
// 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x
// 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C // y
};
// ----------------------------------------------------------------------------
================================================
FILE: BatBonanzaAnalogSinglePot/BatBonanzaAnalogSinglePot.ino
================================================
/* 2015 / 2016 /2017
* Pong clone by Andy Jackson - Twitter @andyhighnumber
* Inspired by http://webboggles.com/ and includes some code from the #AttinyArcade games on that site
* The code that does not fall under the licenses of sources listed below can be used non commercially with attribution.
*
* This code takes its inputs from one paddles - same as my analog Space Invaders Clone
* Tweet @andyhighnumber and I will direct you to the circuit.
*
* There's one button in this design (on pin 5). When the game is running, pressing and releasing the button cycles through modes, with varying degrees of difficulty.
*
* Also, from standby....
* Press and hold the button to reset all settings (good to do when you first flash the chip, since the settings are loaded from EEPROM)
*
* If you have problems uploading this sketch, this is probably due to sketch size - you need to update ld.exe in arduino\hardware\tools\avr\avr\bin
* https://github.com/TCWORLD/ATTinyCore/tree/master/PCREL%20Patch%20for%20GCC
*
* This sketch is using the screen control and font functions written by Neven Boyanov for the http://tinusaur.wordpress.com/ project
* Source code and font files available at: https://bitbucket.org/tinusaur/ssd1306xled
* **Note that this highly size-optimised version requires modified library functions (which are in this source code file)
* and a modified font header
*
* Sleep code is based on this blog post by Matthew Little:
* http://www.re-innovation.co.uk/web12/index.php/en/blog-75/306-sleep-modes-on-attiny85
*/
#include <EEPROM.h>
#include "font6x8AJ.h"
#include <avr/sleep.h>
#include <avr/interrupt.h> // needed for the additional interrupt
#define DIGITAL_WRITE_HIGH(PORT) PORTB |= (1 << PORT)
#define DIGITAL_WRITE_LOW(PORT) PORTB &= ~(1 << PORT)
// Routines to set and clear bits (used in the sleep code)
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
// Defines for OLED output
#define SSD1306XLED_H
#define SSD1306_SCL PORTB4 // SCL, Pin 4 on SSD1306 Board - for webbogles board
#define SSD1306_SDA PORTB3 // SDA, Pin 3 on SSD1306 Board - for webbogles board
#define SSD1306_SA 0x78 // Slave address
#define WINSCORE 7
// Function prototypes
void startGame(void);
void drawPlatform(void);
void drawPlatform2(void);
void sendBlock(int);
void playPong(void);
void beep(int,int);
void drawBall(int x, int y);
void blankBall(int x, int y);
void doDrawLS(long, byte);
void doDrawRS(long, byte);
void doNumber (int x, int y, int value);
void ssd1306_init(void);
void ssd1306_xfer_start(void);
void ssd1306_xfer_stop(void);
void ssd1306_send_byte(uint8_t byte);
void ssd1306_send_command(uint8_t command);
void ssd1306_send_data_start(void);
void ssd1306_send_data_stop(void);
void ssd1306_setpos(uint8_t x, uint8_t y);
void ssd1306_fillscreen(uint8_t fill_Data);
void ssd1306_char_f6x8(uint8_t x, uint8_t y, const char ch[]);
void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t bitmap[]);
int topScoreB = 0;
int player; //0 to 128-platformWidth - this is the position of the player
int player2; //0 to 128-platformWidth - this is the position of the player
int lastPlayer;
int lastPlayer2;
int platformWidth = 16;
boolean stopAnimate = 0; // this is set to 1 when a collision is detected
boolean mute = 0;
int score = 0; // score - this affects the difficulty of the game
int score2 = 0; // score - this affects the difficulty of the game
int ballx = 62*8; // coordinate of the ball
int bally = 50*4; // coordinate of the ball
int vdir = -4; // vertical direction and step distance
int hdir = -8; // horizontal direction and step distance
int mode = 2;
int perturbation = 0;
int pFactor = 12;
// Interrupt handlers
ISR(PCINT0_vect){ // PB0 pin button interrupt
}
void playerIncPong(){ // PB2 pin button interrupt
}
// Arduino stuff - setup
void setup() {
DDRB = 0b00000010; // set PB1 as output (for the speaker)
PCMSK = 0b00000001; // pin change mask: listen to portb bit 1
GIMSK |= 0b00100000; // enable PCINT interrupt
sei(); // enable all interrupts
}
// Arduino stuff - loop
void loop() {
ssd1306_init();
ssd1306_fillscreen(0x00);
// The lower case character set is seriously compromised because I've had to truncate the ASCII table
// to release space for executable code - hence lower case y and w are remapped to h and / respectively.
// There is no z in the table (or h!) as these aren't used anywhere in the text here and most of the
// symbols are also missing for the same reason (see my hacked version of font6x8.h - font6x8AJ.h for more detail)
ssd1306_char_f6x8(0, 1, " --------------- ");
ssd1306_char_f6x8(0, 2, " B A T ");
ssd1306_char_f6x8(0, 4, " B O N A N Z A ");
ssd1306_char_f6x8(0, 5, " --------------- ");
ssd1306_char_f6x8(0, 7, " bh andh jackson "); // see comments above !
long startT = millis();
long nowT =0;
boolean sChange = 0;
while(digitalRead(0) == HIGH) {
nowT = millis();
if (nowT - startT > 2000) {
sChange = 1;
EEPROM.write(0,0);
EEPROM.write(1,1);
ssd1306_char_f6x8(16, 0, "- SYSTEM RESET -");
break;
}
if (sChange == 1) break;
}
while(digitalRead(0) == HIGH);
mute=EEPROM.read(0);
mode=EEPROM.read(1);
if (mute != 0 && mute != 1) {
mute = 0;
EEPROM.write(0,0);
}
if (mode < 2 || mode > 5) {
mode = 2;
EEPROM.write(1,2);
}
if (sChange != 1) {
delay(1500);
ssd1306_init();
ssd1306_fillscreen(0x00);
stopAnimate = 0;
score = 0;
score2 = 0;
playPong();
delay(3500);
}
system_sleep();
}
void doNumber (int x, int y, int value) {
char temp[10] = {0,0,0,0,0,0,0,0,0,0};
itoa(value,temp,10);
ssd1306_char_f6x8(x, y, temp);
}
void ssd1306_init(void){
DDRB |= (1 << SSD1306_SDA); // Set port as output
DDRB |= (1 << SSD1306_SCL); // Set port as output
ssd1306_send_command(0xAE); // display off
ssd1306_send_command(0x00); // Set Memory Addressing Mode
ssd1306_send_command(0x10); // 00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
ssd1306_send_command(0x40); // Set Page Start Address for Page Addressing Mode,0-7
ssd1306_send_command(0x81); // Set COM Output Scan Direction
ssd1306_send_command(0xCF); // ---set low column address
ssd1306_send_command(0xA1); // ---set high column address
ssd1306_send_command(0xC8); // --set start line address
ssd1306_send_command(0xA6); // --set contrast control register
ssd1306_send_command(0xA8);
ssd1306_send_command(0x3F); // --set segment re-map 0 to 127
ssd1306_send_command(0xD3); // --set normal display
ssd1306_send_command(0x00); // --set multiplex ratio(1 to 64)
ssd1306_send_command(0xD5); //
ssd1306_send_command(0x80); // 0xa4,Output follows RAM content;0xa5,Output ignores RAM content
ssd1306_send_command(0xD9); // -set display offset
ssd1306_send_command(0xF1); // -not offset
ssd1306_send_command(0xDA); // --set display clock divide ratio/oscillator frequency
ssd1306_send_command(0x12); // --set divide ratio
ssd1306_send_command(0xDB); // --set pre-charge period
ssd1306_send_command(0x40); //
ssd1306_send_command(0x20); // --set com pins hardware configuration
ssd1306_send_command(0x02);
ssd1306_send_command(0x8D); // --set vcomh
ssd1306_send_command(0x14); // 0x20,0.77xVcc
ssd1306_send_command(0xA4); // --set DC-DC enable
ssd1306_send_command(0xA6); //
ssd1306_send_command(0xAF); // --turn on oled panel
}
void ssd1306_xfer_start(void){
DIGITAL_WRITE_HIGH(SSD1306_SCL); // Set to HIGH
DIGITAL_WRITE_HIGH(SSD1306_SDA); // Set to HIGH
DIGITAL_WRITE_LOW(SSD1306_SDA); // Set to LOW
DIGITAL_WRITE_LOW(SSD1306_SCL); // Set to LOW
}
void ssd1306_xfer_stop(void){
DIGITAL_WRITE_LOW(SSD1306_SCL); // Set to LOW
DIGITAL_WRITE_LOW(SSD1306_SDA); // Set to LOW
DIGITAL_WRITE_HIGH(SSD1306_SCL); // Set to HIGH
DIGITAL_WRITE_HIGH(SSD1306_SDA); // Set to HIGH
}
void ssd1306_send_byte(uint8_t byte){
uint8_t i;
for(i=0; i<8; i++)
{
if((byte << i) & 0x80)
DIGITAL_WRITE_HIGH(SSD1306_SDA);
else
DIGITAL_WRITE_LOW(SSD1306_SDA);
DIGITAL_WRITE_HIGH(SSD1306_SCL);
DIGITAL_WRITE_LOW(SSD1306_SCL);
}
DIGITAL_WRITE_HIGH(SSD1306_SDA);
DIGITAL_WRITE_HIGH(SSD1306_SCL);
DIGITAL_WRITE_LOW(SSD1306_SCL);
}
void ssd1306_send_command(uint8_t command){
ssd1306_xfer_start();
ssd1306_send_byte(SSD1306_SA); // Slave address, SA0=0
ssd1306_send_byte(0x00); // write command
ssd1306_send_byte(command);
ssd1306_xfer_stop();
}
void ssd1306_send_data_start(void){
ssd1306_xfer_start();
ssd1306_send_byte(SSD1306_SA);
ssd1306_send_byte(0x40); //write data
}
void ssd1306_send_data_stop(void){
ssd1306_xfer_stop();
}
void ssd1306_setpos(uint8_t x, uint8_t y)
{
if (y>7) return;
ssd1306_xfer_start();
ssd1306_send_byte(SSD1306_SA); //Slave address,SA0=0
ssd1306_send_byte(0x00); //write command
ssd1306_send_byte(0xb0+y);
ssd1306_send_byte(((x&0xf0)>>4)|0x10); // |0x10
ssd1306_send_byte((x&0x0f)|0x01); // |0x01
ssd1306_xfer_stop();
}
void ssd1306_fillscreen(uint8_t fill_Data){
uint8_t m,n;
for(m=0;m<8;m++)
{
ssd1306_send_command(0xb0+m); //page0-page1
ssd1306_send_command(0x00); //low column start address
ssd1306_send_command(0x10); //high column start address
ssd1306_send_data_start();
for(n=0;n<128;n++)
{
ssd1306_send_byte(fill_Data);
}
ssd1306_send_data_stop();
}
}
void ssd1306_char_f6x8(uint8_t x, uint8_t y, const char ch[]){
uint8_t c,i,j=0;
while(ch[j] != '\0')
{
c = ch[j] - 32;
if (c >0) c = c - 12;
if (c >15) c = c - 6;
if (c>40) c=c-6;
if(x>126)
{
x=0;
y++;
}
ssd1306_setpos(x,y);
ssd1306_send_data_start();
for(i=0;i<6;i++)
{
ssd1306_send_byte(pgm_read_byte(&ssd1306xled_font6x8[c*6+i]));
}
ssd1306_send_data_stop();
x += 6;
j++;
}
}
void system_sleep() {
ssd1306_fillscreen(0x00);
ssd1306_send_command(0xAE);
cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF
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
sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON
ssd1306_send_command(0xAF);
}
void beep(int bCount,int bDelay){
if (mute) return;
for (int i = 0; i<=bCount; i++){digitalWrite(1,HIGH);for(int i2=0; i2<bDelay; i2++){__asm__("nop\n\t");}digitalWrite(1,LOW);for(int i2=0; i2<bDelay; i2++){__asm__("nop\n\t");}}
}
/* ------------------------
* Pong Code
*/
void playPong() {
ballx = 64*8;
bally = 32*4;
hdir = -8;
vdir = -4;
int actualy, actualx;
int factor = 0;
int waitCount = 0;
int lastx=64*8, lasty=32*4;
player=64;
player2=64;
lastPlayer = 64;
lastPlayer2 = 64;
score = 0; // obvious
score2 = 0; // obvious
perturbation = 0;
startGame();
while (stopAnimate == 0) {
while(1) {
waitCount++;
if(digitalRead(0)==1) {
boolean sChange = 0;
long startT = millis();
long nowT =0;
while(digitalRead(0) == HIGH) {
nowT = millis();
if (nowT - startT > 1500) {
sChange = 1;
if (mute == 0) { mute = 1; ssd1306_char_f6x8(32, 0, "-- MUTE --"); } else { mute = 0; ssd1306_char_f6x8(23, 0, "-- SOUND ON --"); }
break;
}
}
while(digitalRead(0) == HIGH);
if (sChange == 1) {
} else if (mode == 2) {
mode = 3;
pFactor = 11;
ssd1306_char_f6x8(26, 0, "-- TOUGH --");
} else if (mode == 3) {
mode = 4;
pFactor = 10;
ssd1306_char_f6x8(26, 0, "-- EXPERT --");
} else if (mode == 4) {
mode = 2;
ssd1306_char_f6x8(26, 0, "-- NORMAL --");
}
if (sChange == 0) delay(1000);
ssd1306_fillscreen(0x00);
EEPROM.write(0,mute);
EEPROM.write(1,mode);
}
player = (analogRead(1) / 16);
if (player > 48) player = 48;
if (player <0) player = 0;
if(waitCount >= 3) {
waitCount = 0;
perturbation = perturbation - 2 + random(0,5);
if (perturbation > pFactor) perturbation = pFactor - 2;
if (perturbation < pFactor*-1) perturbation = (pFactor*-1)+2;
}
player2 = (bally/4 -8)+perturbation;
if (player2 > 48) player2 = 48;
if (player2 <0) player2 = 0;
actualy = floor(bally/4);
actualx = floor(ballx/8);
// bounce off the sides of the screen
if ((actualy+vdir<63&&vdir>01) || (actualy- vdir>6&&vdir<0)){
bally+=vdir;
}else {
vdir = vdir*-1;
}
ballx+=hdir;
actualy = floor(bally/4);
actualx = floor(ballx/8);
// check it hits the left pad and deal with bounces and misses
if (actualx <= 4) {
if(actualy<player-1||actualy>player+platformWidth+1){
score2++;
ballx = 5*8;
bally = player*4;
hdir = 13;
if (vdir > 0) {
vdir = 2;
} else vdir = -2;
ssd1306_fillscreen(0x00);
doNumber(46,4,score);
doNumber(78,4,score2);
if (score2 < WINSCORE) {
for (int i = 0; i<1000; i = i+ 100){
beep(50,i);
}
for (int incr=0;incr<3;incr++) {
ssd1306_send_data_stop();
ssd1306_setpos(78,4);
ssd1306_send_data_start();
sendBlock(0);
sendBlock(0);
ssd1306_send_data_stop();
delay(350);
doNumber(78,4,score2);
delay(350);
}
startGame();
}
perturbation = 0;
break;
}else if (actualy<player+1){
vdir = -6;
hdir = 7;
}else if (actualy<player+4){
vdir = -4;
hdir = 10;
}else if (actualy<player+7){
vdir = -2;
hdir = 13;
}else if (actualy<player+9){
vdir = 0;
hdir = 14;
}else if (actualy<player+12){
vdir = 2;
hdir = 13;
}else if (actualy<player+15){
vdir = 4;
hdir = 10;
}else {
vdir = 6;
hdir = 7;
}
beep(20,600);
}
// check it hits the right pad and deal with bounces
if(actualx >= 122) {
if(actualy<player2-1||actualy>player2+platformWidth+1){
score++;
ballx = 120*8;
bally = player2*4;
hdir = -13;
if (vdir > 0) {
vdir = 2;
} else vdir = -2;
ssd1306_fillscreen(0x00);
doNumber(46,4,score);
doNumber(78,4,score2);
if (score < WINSCORE) {
for (int i = 0; i<1000; i = i+ 100){
beep(50,i);
}
for (int incr=0;incr<3;incr++) {
ssd1306_setpos(46,4);
ssd1306_send_data_start();
sendBlock(0);
sendBlock(0);
ssd1306_send_data_stop();
delay(350);
doNumber(46,4,score);
delay(350);
}
perturbation = 0;
startGame();
}
break;
}else if (actualy<player2+1){
vdir = -6;
hdir = -7;
}else if (actualy<player2+4){
vdir = -4;
hdir = -10;
}else if (actualy<player2+7){
vdir = -2;
hdir = -13;
}else if (actualy<player2+9){
vdir = 0;
hdir = -14;
}else if (actualy<player2+12){
vdir = 2;
hdir = -13;
}else if (actualy<player2+15){
vdir = 4;
hdir = -10;
}else {
vdir = 6;
hdir = -7;
}
beep(20,300);
}
if (mode == 1 || mode == 3 || mode == 4) {
factor = 8-floor((score-score2)/2); // expert modes
if (factor < 2) factor = 2;
} else {
factor = 20-floor((score-score2)/2); // normal modes
if (factor < 10) factor = 10;
}
delay(factor);
// draw ball
blankBall(floor(lastx/8),floor(lasty/4));
drawPlatform();
drawPlatform2();
drawBall(floor(ballx/8),floor(bally/4));
lastx = ballx;
lasty = bally;
doNumber(28,0,score);
doNumber(92,0,score2);
if (score == WINSCORE || score2 == WINSCORE) {
stopAnimate = 1;
break;
}
}
}
blankBall(floor(lastx/8),floor(lasty/4));
blankBall(floor(ballx/8),floor(bally/4));
if (score > score2) {
ssd1306_char_f6x8(27, 3, "P L A Y E R 1");
} else {
ssd1306_char_f6x8(27, 3, "P L A Y E R 2");
}
ssd1306_char_f6x8(27, 4, " ");
ssd1306_char_f6x8(27, 5, " W I N S ");
for (int i = 0; i<1000; i = i+ 50){
beep(50,i);
}
for (int incr=0;incr<6;incr++) {
ssd1306_setpos(28,0);
ssd1306_send_data_start();
sendBlock(0);
sendBlock(0);
ssd1306_send_data_stop();
ssd1306_setpos(92,0);
ssd1306_send_data_start();
sendBlock(0);
sendBlock(0);
ssd1306_send_data_stop();
delay(350);
doNumber(28,0,score);
doNumber(92,0,score2);
delay(350);
}
}
void drawPlatform() {
if (player != lastPlayer) {
ssd1306_setpos(0,lastPlayer/8);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(0,lastPlayer/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(0,lastPlayer/8+2);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
}
if (player%8!=0){
ssd1306_setpos(0,player/8);
ssd1306_send_data_start();
ssd1306_send_byte((B11111111)<<player%8);
ssd1306_send_data_stop();
ssd1306_setpos(0,player/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B11111111);
ssd1306_send_data_stop();
ssd1306_setpos(0,player/8+2);
ssd1306_send_data_start();
ssd1306_send_byte((B01111110)>>8-player%8);
ssd1306_send_data_stop();
} else {
ssd1306_setpos(0,player/8);
ssd1306_send_data_start();
ssd1306_send_byte(B11111111);
ssd1306_send_data_stop();
ssd1306_setpos(0,player/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B11111111);
ssd1306_send_data_stop();
}
lastPlayer = player;
}
void drawPlatform2() {
if (player2 != lastPlayer2) {
ssd1306_setpos(127,lastPlayer2/8);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(127,lastPlayer2/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(127,lastPlayer2/8+2);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
}
if (player2%8!=0){
ssd1306_setpos(127,player2/8);
ssd1306_send_data_start();
ssd1306_send_byte((B11111111)<<player2%8);
ssd1306_send_data_stop();
ssd1306_setpos(127,player2/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B11111111);
ssd1306_send_data_stop();
ssd1306_setpos(127,player2/8+2);
ssd1306_send_data_start();
ssd1306_send_byte((B01111110)>>8-player2%8);
ssd1306_send_data_stop();
} else {
ssd1306_setpos(127,player2/8);
ssd1306_send_data_start();
ssd1306_send_byte((B11111111)<<0);
ssd1306_send_data_stop();
ssd1306_setpos(127,player2/8+1);
ssd1306_send_data_start();
ssd1306_send_byte((B11111111)<<0);
ssd1306_send_data_stop();
}
lastPlayer2 = player2;
}
void sendBlock(int fill){
if (fill == 1) {
ssd1306_send_byte(B10011000);
ssd1306_send_byte(B01011100);
ssd1306_send_byte(B10110110);
ssd1306_send_byte(B01011111);
ssd1306_send_byte(B01011111);
ssd1306_send_byte(B10110110);
ssd1306_send_byte(B01011100);
ssd1306_send_byte(B10011000);
} else {
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
}
}
void blankBall(int x, int y) {
if (y%8!=0){
ssd1306_setpos(x,y/8);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(x,y/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
} else {
ssd1306_setpos(x,y/8);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
}
}
void drawBall(int x, int y) {
if (y%8!=0){
ssd1306_setpos(x,y/8);
ssd1306_send_data_start();
doDrawLS(0,y%8);
ssd1306_send_data_stop();
ssd1306_setpos(x,y/8+1);
ssd1306_send_data_start();
doDrawRS(0,8-y%8);
ssd1306_send_data_stop();
} else {
ssd1306_setpos(x,y/8);
ssd1306_send_data_start();
doDrawLS(0,0);
ssd1306_send_data_stop();
}
}
// Drawing routine for the player and fire - with right-shifts
void doDrawRS(long P1, byte P2) {
ssd1306_send_byte((B00000011 | P1)>>P2);
ssd1306_send_byte((B00000011 | P1)>>P2);
}
// Drawing routine for the player and fire - with left-shifts
void doDrawLS(long P1, byte P2) {
ssd1306_send_byte((B00000011 | P1)<<P2);
ssd1306_send_byte((B00000011 | P1)<<P2);
}
void startGame(void) {
ssd1306_fillscreen(0x00);
ssd1306_char_f6x8(16, 3, "-- GET READY --");
doNumber(60,5,3);
delay(1000);
doNumber(60,5,2);
delay(1000);
doNumber(60,5,1);
delay(1000);
ssd1306_fillscreen(0x00);
for (int i = 800; i>200; i = i - 200){
beep(30,i);
}
}
================================================
FILE: BatBonanzaAnalogSinglePot/font6x8AJ.h
================================================
/*
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
*
* @file: font6x8.h
* @created: 2014-08-12
* @author: Neven Boyanov
*
* Hacked by andy jackson to allow two games (originally by webboggles.com) to
* fit onto an ATTiny85 at the same time - hence several characters are missing
* and a couple have been moved to limit the amount of software remapping required
* to map ASCII values onto locations in this array.
*
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
*
*/
// ----------------------------------------------------------------------------
#include <avr/pgmspace.h>
// ----------------------------------------------------------------------------
/* Standard ASCII 6x8 font */
static const uint8_t ssd1306xled_font6x8 [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
/*
0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
0x00, 0x62, 0x64, 0x08, 0x13, 0x23, // %
0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // &
0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // '
0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // *
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // +
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // ,
*/
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // -
0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // .
0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w in place of /
//0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // /
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // :
/*
0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // =
0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // >
0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @
*/
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B
0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C
0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E
0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F
0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G
0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I
0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J
0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K
0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L
0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P
0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R
0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S
0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T
0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W
0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X
0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
/*
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [
0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 55
0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // '
*/
0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a
0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b
0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c
0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d
0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e
0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f
0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y (in place of h)
//0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h
0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i
0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l
0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m
0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n
0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o
0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p
0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q
0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r
0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s
0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t
0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
// 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
// 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x
// 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C // y
};
// ----------------------------------------------------------------------------
================================================
FILE: BatBonanzaAttinyArcade/BatBonanzaAttinyArcade.ino
================================================
/* 2015 / 2016 /2017
* Pong game by Andy Jackson - Twitter @andyhighnumber
* Inspired by http://webboggles.com/ and includes some code from the #AttinyArcade games on that site
* The code that does not fall under the licenses of sources listed below can be used non commercially with attribution.
*
* When the game is running :
* LEFT BUTTON - Controls the player's bat
* RIGHT BUTTON - Press and relese to change mode (difficulty) - Press and hold to toggle sound
*
* Also, from standby....
* Press and hold left button to reset the system
*
* If you have problems uploading this sketch, this is probably due to sketch size - you need to update ld.exe in arduino\hardware\tools\avr\avr\bin
* https://github.com/TCWORLD/ATTinyCore/tree/master/PCREL%20Patch%20for%20GCC
*
* This sketch is using the screen control and font functions written by Neven Boyanov for the http://tinusaur.wordpress.com/ project
* Source code and font files available at: https://bitbucket.org/tinusaur/ssd1306xled
* **Note that this highly size-optimised version requires modified library functions (which are in this source code file)
* and a modified font header
*
* Sleep code is based on this blog post by Matthew Little:
* http://www.re-innovation.co.uk/web12/index.php/en/blog-75/306-sleep-modes-on-attiny85
*/
#include <EEPROM.h>
#include "font6x8AJ.h"
#include <avr/sleep.h>
#include <avr/interrupt.h> // needed for the additional interrupt
#define DIGITAL_WRITE_HIGH(PORT) PORTB |= (1 << PORT)
#define DIGITAL_WRITE_LOW(PORT) PORTB &= ~(1 << PORT)
// Routines to set and clear bits (used in the sleep code)
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
// Defines for OLED output
#define SSD1306XLED_H
#define SSD1306_SCL PORTB4 // SCL, Pin 4 on SSD1306 Board - for webbogles board
#define SSD1306_SDA PORTB3 // SDA, Pin 3 on SSD1306 Board - for webbogles board
#define SSD1306_SA 0x78 // Slave address
#define WINSCORE 7
// Function prototypes
void startGame(void);
void drawPlatform(void);
void drawPlatform2(void);
void sendBlock(int);
void playPong(void);
void beep(int,int);
void drawBall(int x, int y);
void blankBall(int x, int y);
void doDrawLS(long, byte);
void doDrawRS(long, byte);
void doNumber (int x, int y, int value);
void ssd1306_init(void);
void ssd1306_xfer_start(void);
void ssd1306_xfer_stop(void);
void ssd1306_send_byte(uint8_t byte);
void ssd1306_send_command(uint8_t command);
void ssd1306_send_data_start(void);
void ssd1306_send_data_stop(void);
void ssd1306_setpos(uint8_t x, uint8_t y);
void ssd1306_fillscreen(uint8_t fill_Data);
void ssd1306_char_f6x8(uint8_t x, uint8_t y, const char ch[]);
void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t bitmap[]);
int player; //0 to 128-platformWidth - this is the position of the player
int player2; //0 to 128-platformWidth - this is the position of the player
int lastPlayer;
int lastPlayer2;
int platformWidth = 16;
boolean stopAnimate = 0; // this is set to 1 when a collision is detected
boolean mute = 0;
boolean newHigh = 0;
int score = 0; // score - this affects the difficulty of the game
int score2 = 0; // score - this affects the difficulty of the game
int ballx = 62*8; // coordinate of the ball
int bally = 50*4; // coordinate of the ball
int vdir = -4; // vertical direction and step distance
int hdir = -8; // horizontal direction and step distance
int mode = 0;
int perturbation = 0;
int pFactor = 12;
// Interrupt handlers
ISR(PCINT0_vect){ // PB0 pin button interrupt
}
void playerIncPong(){ // PB2 pin button interrupt
}
// Arduino stuff - setup
void setup() {
DDRB = 0b00000010; // set PB1 as output (for the speaker)
PCMSK = 0b00000001; // pin change mask: listen to portb bit 1
GIMSK |= 0b00100000; // enable PCINT interrupt
sei(); // enable all interrupts
}
// Arduino stuff - loop
void loop() {
ssd1306_init();
ssd1306_fillscreen(0x00);
// The lower case character set is seriously compromised because I've had to truncate the ASCII table
// to release space for executable code - hence lower case y and w are remapped to h and / respectively.
// There is no z in the table (or h!) as these aren't used anywhere in the text here and most of the
// symbols are also missing for the same reason (see my hacked version of font6x8.h - font6x8AJ.h for more detail)
ssd1306_char_f6x8(0, 1, " --------------- ");
ssd1306_char_f6x8(0, 2, " B A T ");
ssd1306_char_f6x8(0, 4, " B O N A N Z A ");
ssd1306_char_f6x8(0, 5, " --------------- ");
ssd1306_char_f6x8(0, 7, " bh andh jackson "); // see comments above !
long startT = millis();
long nowT =0;
boolean sChange = 0;
while(digitalRead(0) == HIGH) {
nowT = millis();
if (nowT - startT > 2000) {
sChange = 1;
EEPROM.write(0,0);
EEPROM.write(1,1);
ssd1306_char_f6x8(16, 0, "- SYSTEM RESET -");
break;
}
if (sChange == 1) break;
}
while(digitalRead(0) == HIGH);
mute=EEPROM.read(0);
mode=EEPROM.read(1);
if (mute != 0 && mute != 1) {
mute = 0;
EEPROM.write(0,0);
}
if (mode != 1 && mode != 3 && mode != 4) {
mode = 1;
EEPROM.write(1,1);
}
if (sChange != 1) {
delay(1500);
ssd1306_init();
ssd1306_fillscreen(0x00);
stopAnimate = 0;
score = 0;
score2 = 0;
playPong();
delay(3500);
}
system_sleep();
}
void doNumber (int x, int y, int value) {
char temp[10] = {0,0,0,0,0,0,0,0,0,0};
itoa(value,temp,10);
ssd1306_char_f6x8(x, y, temp);
}
void ssd1306_init(void){
DDRB |= (1 << SSD1306_SDA); // Set port as output
DDRB |= (1 << SSD1306_SCL); // Set port as output
ssd1306_send_command(0xAE); // display off
ssd1306_send_command(0x00); // Set Memory Addressing Mode
ssd1306_send_command(0x10); // 00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
ssd1306_send_command(0x40); // Set Page Start Address for Page Addressing Mode,0-7
ssd1306_send_command(0x81); // Set COM Output Scan Direction
ssd1306_send_command(0xCF); // ---set low column address
ssd1306_send_command(0xA1); // ---set high column address
ssd1306_send_command(0xC8); // --set start line address
ssd1306_send_command(0xA6); // --set contrast control register
ssd1306_send_command(0xA8);
ssd1306_send_command(0x3F); // --set segment re-map 0 to 127
ssd1306_send_command(0xD3); // --set normal display
ssd1306_send_command(0x00); // --set multiplex ratio(1 to 64)
ssd1306_send_command(0xD5); //
ssd1306_send_command(0x80); // 0xa4,Output follows RAM content;0xa5,Output ignores RAM content
ssd1306_send_command(0xD9); // -set display offset
ssd1306_send_command(0xF1); // -not offset
ssd1306_send_command(0xDA); // --set display clock divide ratio/oscillator frequency
ssd1306_send_command(0x12); // --set divide ratio
ssd1306_send_command(0xDB); // --set pre-charge period
ssd1306_send_command(0x40); //
ssd1306_send_command(0x20); // --set com pins hardware configuration
ssd1306_send_command(0x02);
ssd1306_send_command(0x8D); // --set vcomh
ssd1306_send_command(0x14); // 0x20,0.77xVcc
ssd1306_send_command(0xA4); // --set DC-DC enable
ssd1306_send_command(0xA6); //
ssd1306_send_command(0xAF); // --turn on oled panel
}
void ssd1306_xfer_start(void){
DIGITAL_WRITE_HIGH(SSD1306_SCL); // Set to HIGH
DIGITAL_WRITE_HIGH(SSD1306_SDA); // Set to HIGH
DIGITAL_WRITE_LOW(SSD1306_SDA); // Set to LOW
DIGITAL_WRITE_LOW(SSD1306_SCL); // Set to LOW
}
void ssd1306_xfer_stop(void){
DIGITAL_WRITE_LOW(SSD1306_SCL); // Set to LOW
DIGITAL_WRITE_LOW(SSD1306_SDA); // Set to LOW
DIGITAL_WRITE_HIGH(SSD1306_SCL); // Set to HIGH
DIGITAL_WRITE_HIGH(SSD1306_SDA); // Set to HIGH
}
void ssd1306_send_byte(uint8_t byte){
uint8_t i;
for(i=0; i<8; i++)
{
if((byte << i) & 0x80)
DIGITAL_WRITE_HIGH(SSD1306_SDA);
else
DIGITAL_WRITE_LOW(SSD1306_SDA);
DIGITAL_WRITE_HIGH(SSD1306_SCL);
DIGITAL_WRITE_LOW(SSD1306_SCL);
}
DIGITAL_WRITE_HIGH(SSD1306_SDA);
DIGITAL_WRITE_HIGH(SSD1306_SCL);
DIGITAL_WRITE_LOW(SSD1306_SCL);
}
void ssd1306_send_command(uint8_t command){
ssd1306_xfer_start();
ssd1306_send_byte(SSD1306_SA); // Slave address, SA0=0
ssd1306_send_byte(0x00); // write command
ssd1306_send_byte(command);
ssd1306_xfer_stop();
}
void ssd1306_send_data_start(void){
ssd1306_xfer_start();
ssd1306_send_byte(SSD1306_SA);
ssd1306_send_byte(0x40); //write data
}
void ssd1306_send_data_stop(void){
ssd1306_xfer_stop();
}
void ssd1306_setpos(uint8_t x, uint8_t y)
{
if (y>7) return;
ssd1306_xfer_start();
ssd1306_send_byte(SSD1306_SA); //Slave address,SA0=0
ssd1306_send_byte(0x00); //write command
ssd1306_send_byte(0xb0+y);
ssd1306_send_byte(((x&0xf0)>>4)|0x10); // |0x10
ssd1306_send_byte((x&0x0f)|0x01); // |0x01
ssd1306_xfer_stop();
}
void ssd1306_fillscreen(uint8_t fill_Data){
uint8_t m,n;
for(m=0;m<8;m++)
{
ssd1306_send_command(0xb0+m); //page0-page1
ssd1306_send_command(0x00); //low column start address
ssd1306_send_command(0x10); //high column start address
ssd1306_send_data_start();
for(n=0;n<128;n++)
{
ssd1306_send_byte(fill_Data);
}
ssd1306_send_data_stop();
}
}
void ssd1306_char_f6x8(uint8_t x, uint8_t y, const char ch[]){
uint8_t c,i,j=0;
while(ch[j] != '\0')
{
c = ch[j] - 32;
if (c >0) c = c - 12;
if (c >15) c = c - 6;
if (c>40) c=c-6;
if(x>126)
{
x=0;
y++;
}
ssd1306_setpos(x,y);
ssd1306_send_data_start();
for(i=0;i<6;i++)
{
ssd1306_send_byte(pgm_read_byte(&ssd1306xled_font6x8[c*6+i]));
}
ssd1306_send_data_stop();
x += 6;
j++;
}
}
void system_sleep() {
ssd1306_fillscreen(0x00);
ssd1306_send_command(0xAE);
cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF
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
sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON
ssd1306_send_command(0xAF);
}
void beep(int bCount,int bDelay){
if (mute) return;
for (int i = 0; i<=bCount; i++){digitalWrite(1,HIGH);for(int i2=0; i2<bDelay; i2++){__asm__("nop\n\t");}digitalWrite(1,LOW);for(int i2=0; i2<bDelay; i2++){__asm__("nop\n\t");}}
}
/* ------------------------
* Pong Code
*/
void playPong() {
ballx = 64*8;
bally = 32*4;
hdir = -8;
vdir = -4;
int actualy, actualx;
int factor = 0;
int waitCount = 0;
int lastx=64*8, lasty=32*4;
player=64;
player2=64;
lastPlayer = 64;
lastPlayer2 = 64;
score = 0; // obvious
score2 = 0; // obvious
perturbation = 0;
startGame();
while (stopAnimate == 0) {
while(1) {
waitCount++;
if(digitalRead(2)==1) {
boolean sChange = 0;
long startT = millis();
long nowT =0;
while(digitalRead(2) == HIGH) {
nowT = millis();
if (nowT - startT > 1500) {
sChange = 1;
if (mute == 0) { mute = 1; ssd1306_char_f6x8(32, 0, "-- MUTE --"); } else { mute = 0; ssd1306_char_f6x8(23, 0, "-- SOUND ON --"); }
break;
}
}
while(digitalRead(2) == HIGH);
if (sChange == 1) {
} else if (mode == 1) {
mode = 3;
pFactor = 11;
ssd1306_char_f6x8(20, 0, "- TOUGH MODE -");
} else if (mode == 3) {
mode = 4;
pFactor = 10;
ssd1306_char_f6x8(16, 0, "- EXPERT MODE -");
} else if (mode == 4) {
mode = 1;
pFactor = 12;
ssd1306_char_f6x8(32, 0, "-- NORMAL --");
}
if (sChange == 0) delay(1000);
ssd1306_fillscreen(0x00);
EEPROM.write(0,mute);
EEPROM.write(1,mode);
}
if (digitalRead(0) == 1) {
player-= 3;
}
player+=1;
if (player > 48) player = 48;
if (player <0) player = 0;
if (mode == 1 || mode == 3 || mode == 4) {
if(waitCount >= 3) {
waitCount = 0;
perturbation = perturbation - 2 + random(0,5);
if (perturbation > pFactor) perturbation = pFactor - 2;
if (perturbation < pFactor*-1) perturbation = (pFactor*-1)+2;
}
player2 = (bally/4 -8)+perturbation;
}
if (player2 > 48) player2 = 48;
if (player2 <0) player2 = 0;
actualy = floor(bally/4);
actualx = floor(ballx/8);
// bounce off the sides of the screen
if ((actualy+vdir<63&&vdir>01) || (actualy- vdir>6&&vdir<0)){
bally+=vdir;
}else {
vdir = vdir*-1;
}
ballx+=hdir;
actualy = floor(bally/4);
actualx = floor(ballx/8);
// check it hits the left pad and deal with bounces and misses
if (actualx <= 4) {
if(actualy<player-1||actualy>player+platformWidth+1){
score2++;
ballx = 5*8;
bally = player*4;
hdir = 13;
if (vdir > 0) {
vdir = 2;
} else vdir = -2;
ssd1306_fillscreen(0x00);
doNumber(46,4,score);
doNumber(78,4,score2);
if (score2 < WINSCORE) {
for (int i = 0; i<1000; i = i+ 100){
beep(50,i);
}
for (int incr=0;incr<3;incr++) {
ssd1306_send_data_stop();
ssd1306_setpos(78,4);
ssd1306_send_data_start();
sendBlock(0);
sendBlock(0);
ssd1306_send_data_stop();
delay(350);
doNumber(78,4,score2);
delay(350);
}
startGame();
}
perturbation = 0;
break;
}else if (actualy<player+1){
vdir = -6;
hdir = 7;
}else if (actualy<player+4){
vdir = -4;
hdir = 10;
}else if (actualy<player+7){
vdir = -2;
hdir = 13;
}else if (actualy<player+9){
vdir = 0;
hdir = 14;
}else if (actualy<player+12){
vdir = 2;
hdir = 13;
}else if (actualy<player+15){
vdir = 4;
hdir = 10;
}else {
vdir = 6;
hdir = 7;
}
beep(20,600);
}
// check it hits the right pad and deal with bounces
if(actualx >= 122) {
if(actualy<player2-1||actualy>player2+platformWidth+1){
score++;
ballx = 120*8;
bally = player2*4;
hdir = -13;
if (vdir > 0) {
vdir = 2;
} else vdir = -2;
ssd1306_fillscreen(0x00);
doNumber(46,4,score);
doNumber(78,4,score2);
if (score < WINSCORE) {
for (int i = 0; i<1000; i = i+ 100){
beep(50,i);
}
for (int incr=0;incr<3;incr++) {
ssd1306_setpos(46,4);
ssd1306_send_data_start();
sendBlock(0);
sendBlock(0);
ssd1306_send_data_stop();
delay(350);
doNumber(46,4,score);
delay(350);
}
perturbation = 0;
startGame();
}
break;
}else if (actualy<player2+1){
vdir = -6;
hdir = -7;
}else if (actualy<player2+4){
vdir = -4;
hdir = -10;
}else if (actualy<player2+7){
vdir = -2;
hdir = -13;
}else if (actualy<player2+9){
vdir = 0;
hdir = -14;
}else if (actualy<player2+12){
vdir = 2;
hdir = -13;
}else if (actualy<player2+15){
vdir = 4;
hdir = -10;
}else {
vdir = 6;
hdir = -7;
}
beep(20,300);
}
if (mode == 2 || mode == 3 || mode == 4) {
factor = 8-floor((score-score2)/2); // expert modes
if (factor < 2) factor = 2;
} else {
factor = 20-floor((score-score2)/2); // normal modes
if (factor < 10) factor = 10;
}
delay(factor);
// draw ball
blankBall(floor(lastx/8),floor(lasty/4));
drawPlatform();
drawPlatform2();
drawBall(floor(ballx/8),floor(bally/4));
lastx = ballx;
lasty = bally;
doNumber(28,0,score);
doNumber(92,0,score2);
if (score == WINSCORE || score2 == WINSCORE) {
stopAnimate = 1;
break;
}
}
}
blankBall(floor(lastx/8),floor(lasty/4));
blankBall(floor(ballx/8),floor(bally/4));
if (score > score2) {
ssd1306_char_f6x8(27, 3, "P L A Y E R 1");
} else {
ssd1306_char_f6x8(27, 3, "P L A Y E R 2");
}
ssd1306_char_f6x8(27, 4, " ");
ssd1306_char_f6x8(27, 5, " W I N S ");
for (int i = 0; i<1000; i = i+ 50){
beep(50,i);
}
for (int incr=0;incr<6;incr++) {
ssd1306_setpos(28,0);
ssd1306_send_data_start();
sendBlock(0);
sendBlock(0);
ssd1306_send_data_stop();
ssd1306_setpos(92,0);
ssd1306_send_data_start();
sendBlock(0);
sendBlock(0);
ssd1306_send_data_stop();
delay(350);
doNumber(28,0,score);
doNumber(92,0,score2);
delay(350);
}
}
void drawPlatform() {
if (player != lastPlayer) {
ssd1306_setpos(0,lastPlayer/8);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(0,lastPlayer/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(0,lastPlayer/8+2);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
}
if (player%8!=0){
ssd1306_setpos(0,player/8);
ssd1306_send_data_start();
ssd1306_send_byte((B11111111)<<player%8);
ssd1306_send_data_stop();
ssd1306_setpos(0,player/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B11111111);
ssd1306_send_data_stop();
ssd1306_setpos(0,player/8+2);
ssd1306_send_data_start();
ssd1306_send_byte((B01111110)>>8-player%8);
ssd1306_send_data_stop();
} else {
ssd1306_setpos(0,player/8);
ssd1306_send_data_start();
ssd1306_send_byte(B11111111);
ssd1306_send_data_stop();
ssd1306_setpos(0,player/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B11111111);
ssd1306_send_data_stop();
}
lastPlayer = player;
}
void drawPlatform2() {
if (player2 != lastPlayer2) {
ssd1306_setpos(127,lastPlayer2/8);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(127,lastPlayer2/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(127,lastPlayer2/8+2);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
}
if (player2%8!=0){
ssd1306_setpos(127,player2/8);
ssd1306_send_data_start();
ssd1306_send_byte((B11111111)<<player2%8);
ssd1306_send_data_stop();
ssd1306_setpos(127,player2/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B11111111);
ssd1306_send_data_stop();
ssd1306_setpos(127,player2/8+2);
ssd1306_send_data_start();
ssd1306_send_byte((B01111110)>>8-player2%8);
ssd1306_send_data_stop();
} else {
ssd1306_setpos(127,player2/8);
ssd1306_send_data_start();
ssd1306_send_byte((B11111111)<<0);
ssd1306_send_data_stop();
ssd1306_setpos(127,player2/8+1);
ssd1306_send_data_start();
ssd1306_send_byte((B11111111)<<0);
ssd1306_send_data_stop();
}
lastPlayer2 = player2;
}
void sendBlock(int fill){
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
}
void blankBall(int x, int y) {
if (y%8!=0){
ssd1306_setpos(x,y/8);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
ssd1306_setpos(x,y/8+1);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
} else {
ssd1306_setpos(x,y/8);
ssd1306_send_data_start();
ssd1306_send_byte(B00000000);
ssd1306_send_byte(B00000000);
ssd1306_send_data_stop();
}
}
void drawBall(int x, int y) {
if (y%8!=0){
ssd1306_setpos(x,y/8);
ssd1306_send_data_start();
doDrawLS(0,y%8);
ssd1306_send_data_stop();
ssd1306_setpos(x,y/8+1);
ssd1306_send_data_start();
doDrawRS(0,8-y%8);
ssd1306_send_data_stop();
} else {
ssd1306_setpos(x,y/8);
ssd1306_send_data_start();
doDrawLS(0,0);
ssd1306_send_data_stop();
}
}
void doDrawRS(long P1, byte P2) {
ssd1306_send_byte((B00000011 | P1)>>P2);
ssd1306_send_byte((B00000011 | P1)>>P2);
}
void doDrawLS(long P1, byte P2) {
ssd1306_send_byte((B00000011 | P1)<<P2);
ssd1306_send_byte((B00000011 | P1)<<P2);
}
void startGame(void) {
ssd1306_fillscreen(0x00);
ssd1306_char_f6x8(16, 3, "-- GET READY --");
doNumber(60,5,3);
delay(1000);
doNumber(60,5,2);
delay(1000);
doNumber(60,5,1);
delay(1000);
ssd1306_fillscreen(0x00);
for (int i = 800; i>200; i = i - 200){
beep(30,i);
}
}
================================================
FILE: BatBonanzaAttinyArcade/font6x8AJ.h
================================================
/*
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
*
* @file: font6x8.h
* @created: 2014-08-12
* @author: Neven Boyanov
*
* Hacked by andy jackson to allow two games (originally by webboggles.com) to
* fit onto an ATTiny85 at the same time - hence several characters are missing
* and a couple have been moved to limit the amount of software remapping required
* to map ASCII values onto locations in this array.
*
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
*
*/
// ----------------------------------------------------------------------------
#include <avr/pgmspace.h>
// ----------------------------------------------------------------------------
/* Standard ASCII 6x8 font */
static const uint8_t ssd1306xled_font6x8 [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
/*
0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
0x00, 0x62, 0x64, 0x08, 0x13, 0x23, // %
0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // &
0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // '
0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // *
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // +
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // ,
*/
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // -
0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // .
0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w in place of /
//0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // /
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // :
/*
0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // =
0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // >
0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @
*/
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B
0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C
0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E
0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F
0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G
0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I
0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J
0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K
0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L
0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P
0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R
0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S
0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T
0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W
0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X
0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
/*
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [
0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 55
0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // '
*/
0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a
0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b
0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c
0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d
0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e
0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f
0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y (in place of h)
//0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h
0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i
0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l
0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m
0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n
0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o
0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p
0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q
0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r
0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s
0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t
0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
// 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
// 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x
// 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C // y
};
// ----------------------------------------------------------------------------
================================================
FILE: Frogger_Attiny_Arcade/Frogger_Attiny_Arcade.ino
================================================
/* 2015 / 2016 / 2017
* Frogger game by Andy Jackson - Twitter @andyhighnumber
*
* Special thanks to @senkunmusahi, who created the artwork bitmaps in the game using https://www.riyas.org/2013/12/online-led-matrix-font-generator-with.html
*
* Inspired by http://webboggles.com/ and includes some code from the #AttinyArcade games on that site
* The code that does not fall under the licenses of sources listed below can be used non commercially with attribution.
* This software is supplied without warranty of any kind.
*
* Controls:
* On the standard AttinyArcade:
* LEFT and RIGHT buttons move the frog across
* BOTH BOTTONS TOGETHER move the frog forwards
*
* HIGHLY RECOMMENDED:
* On custom hardware (see schematic in folder where you found this file) there is an additional button to move frog forward
*
* Also, from standby....
* Press and hold left button to turn sound on and off
* Press and hold left button with the right button held to reset high score
*
* This sketch is using the screen control and font functions written by Neven Boyanov for the http://tinusaur.wordpress.com/ project
* Source code and font files available at: https://bitbucket.org/tinusaur/ssd1306xled
* **Note that this highly size-optimised version requires modified library functions (which are in this source code file)
* and a modified font header
*
* Sleep code is based on this blog post by Matthew Little:
* http://www.re-innovation.co.uk/web12/index.php/en/blog-75/306-sleep-modes-on-attiny85
*/
#include <EEPROM.h>
#include "font6x8AJ2.h"
#include <avr/pgmspace.h>
#include <avr/sleep.h>
#include <avr/interrupt.h> // needed for the additional interrupt
// Uncomment this #define to make the logs smaller (/thinner)
//#define SMALLLOGS
// Make click delay an even number - it gets halved and then used in an integer comparison
#define CLICKDELAY 120
// The basline speed - higher number is slower
#define MOVEBASE 1000
#define DIGITAL_WRITE_HIGH(PORT) PORTB |= (1 << PORT)
#define DIGITAL_WRITE_LOW(PORT) PORTB &= ~(1 << PORT)
// Routines to set and clear bits (used in the sleep code)
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
// Defines for OLED output
#define SSD1306XLED_H
#define SSD1306_SCL PORTB4 // SCL, Pin 4 on SSD1306 Board - for webbogles board
#define SSD1306_SDA PORTB3 // SDA, Pin 3 on SSD1306 Board - for webbogles board
#define SSD1306_SA 0x78 // Slave address
// Function prototypes
// Drawing functions - adapted from those at https://bitbucket.org/tinusaur/ssd1306xled
void ssd1306_init(void);
void ssd1306_xfer_start(void);
void ssd1306_xfer_stop(void);
void ssd1306_send_byte(uint8_t byte);
void ssd1306_send_command(uint8_t command);
void ssd1306_send_data_start(void);
void ssd1306_send_data_stop(void);
void ssd1306_setpos(uint8_t x, uint8_t y);
void ssd1306_fillscreen(uint8_t fill_Data);
void ssd1306_char_f6x8(uint8_t x, uint8_t y, const char ch[]);
void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t bitmap[]);
// Custom draw functions - allow for extra functionality like inverse display
void sendBlock(byte, bool);
void sendByte(byte, bool);
// Other generic functions for games (both originated in code from webboggles.com and the sleep code is by Matthew Little - see above)
void beep(int,int);
void system_sleep(void);
void doNumber (int,int,int);
// Game functions
void playFrogger(void);
void levelUp(int);
void moveBlocks(void);
void initScreen(void);
void drawDocks(void);
void drawLives(void);
void displayTitle(void);
void resetDock(byte);
void checkCollision(void);
// Global variables - yes I know all these global vars is a lazy way to code but it makes it easier to prevent stack overflows when you're working with 512 bytes!
// Most of these are initialised in the main game function (playFrogger())
int watchDog; // Counts drawing cycles so I can shut the game down if there's inactivity - battery saver!
boolean stopAnimate; // this is set to 1 when a collision is detected
int lives; // Lives in the game - this can go negative to end the game, which is why it's a signed variable
bool frogDocks[5]; // Tracks which frog docks are full (at the top of the screen)
bool flipFlop; // Used in routines that flip-flop between two states (left and right)
bool flipFlopShift; // Same as previous one
byte frogColumn; // Column location of frog (there are 16 altogether)
byte frogRow; // Row locaiton of frog (there are 8, but 0 is the frog docks at the top and 7 is the start row)
byte frogLeftLimit; // Left limit of frog travel on start row (changes as digits in score increases)
byte frogRightLimit; // Right limit of frog travel on start row (changes as lives decrease as there's then more space)
byte level; // Level - starts at 1
byte blockShiftL; // Number of pixels to shift the left-going rows by
byte blockShiftR; // Number of pixels to shift the right-going rows by
int interimStep; // Used as timer for incremental movements
int moveDelay; // How long to wait until the next movement of logs etc - changes as levels increase to make the game go faster
int dockedFrogs; // How many frogs are in the docks at the top
unsigned long clickBase; // Timer for debounce
boolean clickLock; // For debounce routine
int score; // Obvious I hope
int topScore; // High score
boolean newHigh; // Is there a new high score?
boolean mute = 0; // Mute the speaker
byte grid[6][16]; // Grid for items like logs, crocs, cars and lorries
byte frogMode; // Represents the frog direction
bool moveForward=0; // Captures when the 'forward' button is pressed
bool moveLeft=0; // Captures when the 'left' button is pressed
bool moveRight=0; // Captures when the 'right' button is pressed
// Bitmaps created by @senkunmusahi using https://www.riyas.org/2013/12/online-led-matrix-font-generator-with.html
static const byte bitmaps[15][8] PROGMEM = {
// Frogs
{0x83, 0xDC, 0x7A, 0x3F, 0x3F, 0x7A, 0xDC, 0x83},
{0x99, 0xBD, 0xDB, 0x7E, 0x7E, 0x3C, 0xE7, 0x81},
{0x81, 0xE7, 0x3C, 0x7E, 0x7E, 0xDB, 0xBD, 0x99},
#ifdef SMALLLOGS
// Small logs
{0x1C, 0x22, 0x41, 0x55, 0x55, 0x51, 0x43, 0x61},
{0x69, 0x6B, 0x43, 0x61, 0x45, 0x45, 0x61, 0x65},
{0x45, 0x55, 0x41, 0x5D, 0x63, 0x5D, 0x22, 0x1C},
#else
// Bigger logs
{0x3C, 0x7E, 0xD7, 0xB5, 0xAD, 0xBF, 0xFF, 0xED},
{0xAD, 0xAD, 0xFF, 0xB7, 0xF5, 0xBF, 0xB7, 0xAD},
{0xED, 0xBD, 0xC3, 0xBD, 0xA5, 0xBD, 0x42, 0x3C},
#endif
// Trucks
{0x00, 0x7F, 0x41, 0x55, 0x55, 0x55, 0x55, 0x55},
{0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55},
{0x41, 0x7F, 0x22, 0x7F, 0x7F, 0x63, 0x22, 0x1C},
// Crocs
{0x41, 0x63, 0x46, 0x6E, 0x7C, 0x7E, 0x7A, 0x3E},
{0xBC, 0xFE, 0x7E, 0x3E, 0xBE, 0xBE, 0xFC, 0x7C},
{0x78, 0x38, 0x38, 0x38, 0x70, 0x60, 0x60, 0x40},
// Cars
{0x00, 0x1C, 0x22, 0x63, 0x7F, 0x7F, 0x22, 0x22},
{0x22, 0x3E, 0x3E, 0x7F, 0x63, 0x63, 0x22, 0x1C},
{0x22, 0x3E, 0x3E, 0x7F, 0x63, 0x63, 0x22, 0x1C}
};
// Opening artwork created by @senkunmusahi using https://www.riyas.org/2013/12/online-led-matrix-font-generator-with.html
static const byte titleBmp[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xF0, 0x7C, 0x06, 0x73, 0x59, 0x43,
0x06, 0x3C, 0x38, 0x30, 0x30, 0x38, 0x3E, 0x26, 0x7B, 0x59, 0x43, 0x06, 0x7C, 0xF0, 0xC0, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xFF,
0xCF, 0x01, 0x00, 0x00, 0x30, 0x60, 0xE0, 0xC0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0,
0xC0, 0x60, 0x30, 0x00, 0x00, 0x00, 0x01, 0xCF, 0xFE, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7C, 0xFE, 0x86, 0x0E, 0x0E, 0x1C, 0x18, 0x31, 0x7F, 0xFE, 0xFC, 0x1C, 0x18, 0x38, 0x38, 0x38,
0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x18, 0x1C, 0xFC, 0xFE, 0x7F,
0x39, 0x18, 0x1C, 0x0E, 0x0E, 0xC6, 0xFE, 0x3C, 0x00, 0x01, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xC0,
0xC0, 0x80, 0x03, 0x07, 0xFC, 0xF8, 0x00, 0x00, 0xF0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xE0, 0xF0,
0x00, 0x00, 0xF8, 0xFC, 0x0F, 0x03, 0x80, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x03, 0x01, 0x00,
0x04, 0x06, 0x0F, 0x0F, 0x06, 0x06, 0x03, 0x03, 0x03, 0x63, 0x73, 0x33, 0x3B, 0xFF, 0xFF, 0x7F,
0x3F, 0x38, 0xF0, 0xC0, 0x00, 0xF0, 0xF8, 0x3F, 0x7F, 0xFF, 0xFF, 0x3B, 0x33, 0x63, 0x63, 0x03,
0x03, 0x03, 0x06, 0x06, 0x0F, 0x0F, 0x06, 0x00,
};
// Interrupt handlers
ISR(PCINT0_vect){ // PB0 pin button interrupt
if (clickLock == 0) {
moveLeft = 1;
clickLock = 1;
clickBase = millis();
}
}
void playerIncFrogger(){ // PB2 pin button interrupt
if (clickLock == 0) {
moveRight = 1;
clickLock = 1;
clickBase = millis();
}
}
void displayTitle(void) {
int incr = 0;
for(int lxn = 2; lxn < 7; lxn++) {
ssd1306_setpos(85,lxn);
ssd1306_send_data_start();
for(int lxn2 = 0; lxn2 < 40; lxn2++) {
ssd1306_send_byte(pgm_read_byte(&titleBmp[incr]));
incr++;
}
ssd1306_send_data_stop();
}
}
// Arduino stuff - setup
void setup() {
DDRB = 0b00000010; // set PB1 as output (for the speaker)
PCMSK = 0b00000001; // pin change mask: listen to portb bit 1
GIMSK |= 0b00100000; // enable PCINT interrupt
sei(); // enable all interrupts
}
// Arduino stuff - loop
void loop() {
ssd1306_init();
ssd1306_fillscreen(0x00);
// The lower case character set is seriously compromised because I've had to truncate the ASCII table
// to release space for executable code.
// There is no z in the table as this isn't used anywhere in the text here and most of the
// symbols are also missing for the same reason (see my hacked version of font6x8.h - font6x8AJ.h for more detail)
ssd1306_char_f6x8(0, 2, "F R O G G E R");
ssd1306_char_f6x8(0, 4, "andy jackson"); // see comments above !
ssd1306_setpos(0,1);
for (int incr = 0; incr < 80; incr++) {
ssd1306_send_data_start();
ssd1306_send_byte(B00111000);
ssd1306_send_data_stop();
}
ssd1306_setpos(0,3);
for (int incr = 0; incr < 80; incr++) {
ssd1306_send_data_start();
ssd1306_send_byte(B00011100);
ssd1306_send_data_stop();
}
displayTitle();
ssd1306_char_f6x8(0, 6, "inspired by");
ssd1306_char_f6x8(0, 7, "webboggles.com");
delay(1500);
ssd1306_char_f6x8(0, 6, "artwork by ");
ssd1306_char_f6x8(0, 7, "zsenkunmusashi"); // see comments above - f has been replaced by @ in the ASCII table
long startT = millis();
long nowT =0;
boolean sChange = 0;
while(digitalRead(0) == HIGH) {
nowT = millis();
if (nowT - startT > 2000) {
sChange = 1;
if (digitalRead(2) == HIGH) {
EEPROM.write(0,0);
EEPROM.write(1,0);
ssd1306_char_f6x8(8, 0, "-HIGH SCORE RESET-");
} else if (mute == 0) { mute = 1; ssd1306_char_f6x8(32, 0, "-- MUTE --"); } else { mute = 0; ssd1306_char_f6x8(31, 0, "- SOUND ON -"); }
break;
}
if (sChange == 1) break;
}
while(digitalRead(0) == HIGH);
if (sChange == 0) {
delay(2000);
ssd1306_init();
ssd1306_fillscreen(0x00);
playFrogger();
topScore = EEPROM.read(0);
topScore = topScore << 8;
topScore = topScore | EEPROM.read(1);
newHigh = 0;
if (score > topScore) {
topScore = score;
EEPROM.write(1,score & 0xFF);
EEPROM.write(0,(score>>8) & 0xFF);
newHigh = 1;
}
ssd1306_fillscreen(0x00);
ssd1306_char_f6x8(11, 1, "----------------");
ssd1306_char_f6x8(11, 2, "G A M E O V E R");
ssd1306_char_f6x8(11, 3, "----------------");
ssd1306_char_f6x8(37, 5, "SCORE:");
doNumber(75, 5, score);
if (!newHigh) {
ssd1306_char_f6x8(21, 7, "HIGH SCORE:");
doNumber(88, 7, topScore);
}
delay(1000);
if (newHigh) {
ssd1306_fillscreen(0x00);
ssd1306_char_f6x8(10, 1, "----------------");
ssd1306_char_f6x8(10, 3, " NEW HIGH SCORE ");
ssd1306_char_f6x8(10, 7, "----------------");
doNumber(50,5,topScore);
for (int i = 700; i>200; i = i - 50){
beep(30,i);
}
delay(1200);
}
}
system_sleep();
}
void doNumber (int x, int y, int value) {
char temp[10] = {0,0,0,0,0,0,0,0,0,0};
itoa(value,temp,10);
ssd1306_char_f6x8(x, y, temp);
}
void ssd1306_init(void){
DDRB |= (1 << SSD1306_SDA); // Set port as output
DDRB |= (1 << SSD1306_SCL); // Set port as output
ssd1306_send_command(0xAE); // display off
ssd1306_send_command(0x00); // Set Memory Addressing Mode
ssd1306_send_command(0x10); // 00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
ssd1306_send_command(0x40); // Set Page Start Address for Page Addressing Mode,0-7
ssd1306_send_command(0x81); // Set COM Output Scan Direction
ssd1306_send_command(0xCF); // ---set low rowumn address
ssd1306_send_command(0xA1); // ---set high rowumn address
ssd1306_send_command(0xC8); // --set start line address
ssd1306_send_command(0xA6); // --set contrast control register
ssd1306_send_command(0xA8);
ssd1306_send_command(0x3F); // --set segment re-map 0 to 127
ssd1306_send_command(0xD3); // --set normal display
ssd1306_send_command(0x00); // --set multiplex ratio(1 to 64)
ssd1306_send_command(0xD5); //
ssd1306_send_command(0x80); // 0xa4,Output follows RAM content;0xa5,Output ignores RAM content
ssd1306_send_command(0xD9); // -set display offset
ssd1306_send_command(0xF1); // -not offset
ssd1306_send_command(0xDA); // --set display clock divide ratio/oscillator frequency
ssd1306_send_command(0x12); // --set divide ratio
ssd1306_send_command(0xDB); // --set pre-charge period
ssd1306_send_command(0x40); //
ssd1306_send_command(0x20); // --set com pins hardware configuration
ssd1306_send_command(0x02);
ssd1306_send_command(0x8D); // --set vcomh
ssd1306_send_command(0x14); // 0x20,0.77xVcc
ssd1306_send_command(0xA4); // --set DC-DC enable
ssd1306_send_command(0xA6); //
ssd1306_send_command(0xAF); // --turn on oled panel
}
void ssd1306_xfer_start(void){
DIGITAL_WRITE_HIGH(SSD1306_SCL); // Set to HIGH
DIGITAL_WRITE_HIGH(SSD1306_SDA); // Set to HIGH
DIGITAL_WRITE_LOW(SSD1306_SDA); // Set to LOW
DIGITAL_WRITE_LOW(SSD1306_SCL); // Set to LOW
}
void ssd1306_xfer_stop(void){
DIGITAL_WRITE_LOW(SSD1306_SCL); // Set to LOW
DIGITAL_WRITE_LOW(SSD1306_SDA); // Set to LOW
DIGITAL_WRITE_HIGH(SSD1306_SCL); // Set to HIGH
DIGITAL_WRITE_HIGH(SSD1306_SDA); // Set to HIGH
}
void ssd1306_send_byte(uint8_t byte){
uint8_t i;
for(i=0; i<8; i++)
{
if((byte << i) & 0x80)
DIGITAL_WRITE_HIGH(SSD1306_SDA);
else
DIGITAL_WRITE_LOW(SSD1306_SDA);
DIGITAL_WRITE_HIGH(SSD1306_SCL);
DIGITAL_WRITE_LOW(SSD1306_SCL);
}
DIGITAL_WRITE_HIGH(SSD1306_SDA);
DIGITAL_WRITE_HIGH(SSD1306_SCL);
DIGITAL_WRITE_LOW(SSD1306_SCL);
}
void ssd1306_send_command(uint8_t command){
ssd1306_xfer_start();
ssd1306_send_byte(SSD1306_SA); // Slave address, SA0=0
ssd1306_send_byte(0x00); // write command
ssd1306_send_byte(command);
ssd1306_xfer_stop();
}
void ssd1306_send_data_start(void){
ssd1306_xfer_start();
ssd1306_send_byte(SSD1306_SA);
ssd1306_send_byte(0x40); //write data
}
void ssd1306_send_data_stop(void){
ssd1306_xfer_stop();
}
void ssd1306_setpos(uint8_t x, uint8_t y)
{
if (y>7) return;
ssd1306_xfer_start();
ssd1306_send_byte(SSD1306_SA); //Slave address,SA0=0
ssd1306_send_byte(0x00); //write command
ssd1306_send_byte(0xb0+y);
ssd1306_send_byte(((x&0xf0)>>4)|0x10); // |0x10
ssd1306_send_byte((x&0x0f)|0x01); // |0x01
ssd1306_xfer_stop();
}
void ssd1306_fillscreen(uint8_t fill_Data){
uint8_t m,n;
for(m=0;m<8;m++)
{
ssd1306_send_command(0xb0+m); //page0-page1
ssd1306_send_command(0x00); //low rowumn start address
ssd1306_send_command(0x10); //high rowumn start address
ssd1306_send_data_start();
for(n=0;n<128;n++)
{
ssd1306_send_byte(fill_Data);
}
ssd1306_send_data_stop();
}
}
void ssd1306_char_f6x8(uint8_t x, uint8_t y, const char ch[]){
uint8_t c,i,j=0;
while(ch[j] != '\0')
{
c = ch[j] - 32;
if (c >0) c = c - 12;
if (c >15) c = c - 6;
if (c>40) c=c-9;
if(x>126)
{
x=0;
y++;
}
ssd1306_setpos(x,y);
ssd1306_send_data_start();
for(i=0;i<6;i++)
{
ssd1306_send_byte(pgm_read_byte(&ssd1306xled_font6x8[c*6+i]));
}
ssd1306_send_data_stop();
x += 6;
j++;
}
}
void system_sleep(void) {
ssd1306_fillscreen(0x00);
ssd1306_send_command(0xAE);
cbi(ADCSRA,ADEN); // switch analog to digital converter off
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
sbi(ADCSRA,ADEN); // switch analog to digital converter on
ssd1306_send_command(0xAF);
}
void beep(int bCount,int bDelay){
if (mute) return;
for (int i = 0; i<=bCount; i++){digitalWrite(1,HIGH);for(int i2=0; i2<bDelay; i2++){__asm__("nop\n\t");}digitalWrite(1,LOW);for(int i2=0; i2<bDelay; i2++){__asm__("nop\n\t");}}
}
/* ------------------------
* Frogger main game code
*/
void playFrogger(){
stopAnimate = 0;
score = 0;
moveDelay = MOVEBASE;
level = 1;
frogColumn = 8;
frogRow = 7;
clickLock = 0;
frogMode = 1;
interimStep =0;
blockShiftL = 0;
blockShiftR = 0;
flipFlop = 1;
flipFlopShift = 1;
dockedFrogs = 0;
lives = 2;
frogRightLimit = 12;
watchDog = 1; // we use this to see if there's been movement - it's only ever zero when the frog has just moved!
attachInterrupt(0,playerIncFrogger,CHANGE);
initScreen();
resetDock(0);
drawFrog(frogMode,0);
drawGameScreen(frogMode);
drawLives();
drawDocks();
doNumber(0,7,score);
while (lives >= 0) {
interimStep++;
if (watchDog >= 500) lives = -1; // Stop the game if nothing's happening - maybe triggered in someone's pocket so this is to save battery!
// Calculate left limit of frog movement so it doesn't hit the score
frogLeftLimit = 1;
if ((score / 10) % 10 != 0) frogLeftLimit++;
if ((score / 100) % 10 != 0) frogLeftLimit++;
if ((score / 1000) % 10 != 0) frogLeftLimit++;
// Move stuff along if it's time to
if (interimStep > moveDelay/8) {
watchDog++;
blockShiftL++;
if (flipFlopShift == 1) flipFlopShift = 0; else flipFlopShift = 1;
if (flipFlopShift == 1) blockShiftR++;
if (blockShiftL == 7) {
moveBlocks();
blockShiftL = 0;
}
if (blockShiftR == 7) {
blockShiftR = 0;
}
interimStep = 0;
checkCollision();
if (stopAnimate == 0) {
drawGameScreen(frogMode);
drawFrog(frogMode,0);
}
}
// Handle input from 'jump' button (the other two buttons are captured in the interrupt routines)
if (analogRead(0) < 940 && clickLock == 0) {
moveForward = 1;
watchDog = 0; // reset the watchdog so the game doesn't end!
clickLock = 1;
clickBase = millis();
}
// Handle moving left
if(moveLeft == 1 && millis() > clickBase + CLICKDELAY/2) {
watchDog = 0; // reset the watchdog so the game doesn't end!
moveLeft = 0;
if (digitalRead(2) == HIGH) moveForward = 1; else {
drawFrog(0,0); // delete the frog
// move the frog, checking it isn't jumping off the edge of the screen
if ((frogRow == 7 && frogColumn > frogLeftLimit) || (frogRow < 7 && frogColumn > 0)) {
frogColumn --;
} else if (frogRow < 7) stopAnimate = 1;
frogMode = 2; // pointing left
}
}
// Handle moving right
if(moveRight == 1 && millis() > clickBase + CLICKDELAY/2){
watchDog = 0; // reset the watchdog so the game doesn't end!
moveRight = 0;
if (digitalRead(0) == HIGH) moveForward = 1; else {
drawFrog(0,0); // delete the frog
// move the frog, checking it isn't jumping off the edge of the screen
if ((frogRow == 7 && frogColumn < frogRightLimit) || (frogRow < 7 && frogColumn < 14)) {
frogColumn ++;
} else if (frogRow < 7) stopAnimate = 1;
frogMode = 3; // pointing right
}
}
// Handle 'move forward' button press
if (moveForward == 1) {
moveForward = 0;
score+= level; // increment the score for every move
doNumber(0,7,score); // display new score
drawFrog(0,0); // delete the frog
if (frogRow > 1) {
frogRow--;
// Correct for the skew in frog position created by the blockShift scrolling parameter
if (frogRow == 3 && blockShiftL < 4) frogColumn--;
if (frogRow == 2 && blockShiftR + blockShiftL < 5) frogColumn++;
if (frogRow == 1 && blockShiftR + blockShiftL < 5) frogColumn--;
} else {
// frog is at the docks!
if (blockShiftL < 4 && frogColumn <15) frogColumn++; // account for skew due to block shifting
byte dockPos = (byte)floor(frogColumn/3);
if (frogDocks[dockPos] == 0 ) {
dockedFrogs++;
frogDocks[dockPos] = 1; // assign this dock as filled
frogRow = 7; // reposition the frog at the start
frogColumn = 8;
for (int i = 1000; i>200; i = i - 100){ // make sound
beep(10,i);
drawDocks(); // redraw the docks
}
} else stopAnimate = 1;
}
frogMode = 1; // mode 1 = forwards position
// check if all docks are full - if so, then level up!
if (dockedFrogs >= 5) {
level++;
levelUp(level);
if (moveDelay > 99) moveDelay -=100; // make the game speed up
initScreen(); // reinitalise the position of game items
resetDock(0); // reinitliase the dock
dockedFrogs = 0;
drawDocks(); // display the (now empty) docks
drawLives(); // display the lives
doNumber(0,7,score); // display the score
}
}
// The frog has moved
if (watchDog == 0 && stopAnimate == 0) {
watchDog = 1; // set to something other than zero so this routine doesn't run again
// redraw the frog
drawFrog(frogMode,0);
// redraw the screen
drawGameScreen(frogMode);
// make jump sound
beep(30,400);
beep(30,300);
beep(30,200);
}
checkCollision();
if (clickLock == 1 && millis() > clickBase + CLICKDELAY && digitalRead(2)==0 && digitalRead(0)==0 && analogRead(0) > 940) clickLock = 0; // normal debounce
// check to see if the frog has been killed
if (stopAnimate != 0) {
// redraw the screen
drawGameScreen(frogMode);
// animation for frog death
drawFrog(0,1);
for (int i = 0; i<250; i = i+ 50){
beep(50,i);
}
drawFrog(frogMode,1);
for (int i = 250; i<500; i = i+ 50){
beep(50,i);
}
drawFrog(0,1);
for (int i = 500; i<750; i = i+ 50){
beep(50,i);
}
drawFrog(frogMode,1);
for (int i = 750; i<1000; i = i+ 50){
beep(50,i);
}
delay(600);
lives--; // increment the score for every move
frogRightLimit++; // there's one less frog drawn on right so you can move a bit further across (if you really want to!)
stopAnimate = 0; // reset parameter
drawLives(); // display number of lives left
frogColumn = 8; // reinitalise frog location
frogRow = 7;
}
} // Big while loop (main game loop) goes until lives is negative
}
void checkCollision(void) {
if (frogRow > 0 && frogRow < 4 && grid[frogRow-1][frogColumn] == 0) stopAnimate = 1; // the frog has fallen in the river
if (frogRow > 0 && frogRow < 4 && grid[frogRow-1][frogColumn] > 9) stopAnimate = 1; // the frog has stepped on a croc
if ((frogRow < 7 && frogRow > 3) && (grid[frogRow-1][frogColumn] != 0 || grid[frogRow-1][frogColumn-1] != 0)) stopAnimate = 1; // the frog has been hit by a vehicle
}
// Initialise all the moving objects on the game screen
void initScreen(void) {
int initCounter[6] = {3,2,4,2,2,3}; // the length of the objects on each row - doesn't change
int gapCounter[6] = {-2,-3,-4,-4,-3,-5}; // the gaps between objects - change with levels to make it harder as you go thru the game
int counter[6]; // used to hold the gap data
byte stepMode = 0; // which component of the object are we drawing (they all have three - a start a middle and an end)
byte stepShift = 0; // offset to shift up to the different objects in the array
byte crocStartColumn = 0; // column at which to stop drawing crocs - is zero at start hence no crocs!
// Adjust difficulty by changing gaps between objects according to level
if (level == 1) {
gapCounter[5] = -14; // easiset setting, for start of game
}
if (level < 3) {
gapCounter[4] = -6; // make it easier for levels less than 3 by increasing the gap in the cars on this row
}
if (level < 4) {
gapCounter[3] = -7;
}
if (level > 4) {
for (byte incr = 1; incr < 3; incr++) {
gapCounter[incr]--; // increase the gaps between the logs for levels over 4
}
}
if (level > 7) { // set smaller gaps between cars for levels over 7
gapCounter[3] = -4;
gapCounter[4] = -2;
gapCounter[5] = -3;
}
if (level > 2) crocStartColumn = 5; // one croc appears at level 3 and above
if (level > 6) crocStartColumn = 9; // two croc appear at level 7 and above
// Initialise the counters
for (byte incr = 0; incr < 6;incr++) counter[incr] = initCounter[incr];
// Initialise array with zeros
for (byte col = 0; col < 16; col++) {
for (byte row = 0; row < 6; row++) {
grid[row][col] = 0;
}
}
stepMode = 0;
// Initialise array with obstacles
for (byte row = 0; row < 6; row++) {
for (byte col = 0; col < 15; col++) {
if (counter[row] > 0) {
if (14-row > counter[row]) {
if (counter[row] == 1) if (stepMode == 1) stepMode = 2; // the next space is blank and we are drawing the middle - draw the end!
if (row > 2) stepShift = 3; else stepShift = 0; // shift up to the trucks in the array
if (row == 4) stepShift = 9; // shift up to the cars in the array - also theres no middle
if (row > 0) {
grid[row][col] = 4+stepMode+stepShift; // if you are on any row but the first - draw whatever is appropriate from the bitmaps
} else if (col >= crocStartColumn) {
grid[row][col] = 4+stepMode+stepShift; // if you're on row zero (top row of logs) and you are above where crocs should be drawm, draw logs ...
} else grid[row][col] = 10+stepMode; // .. otherwise draw crocs
if (stepMode == 0) stepMode = 1; // we've drawn the left side now switch to central sections
if (stepMode == 2) stepMode = 0; // we've drawn the end, now reset
}
}
counter[row]--; // decrement the counter
if (counter[row] <= gapCounter[row]) {
counter[row] = initCounter[row]; // if we have gone negative enough to account for the gaps - reset the counter and start again
}
}
}
}
// Display the frog
void drawFrog(byte mode, bool frogDead) {
if (frogRow > 6 || frogRow < 1 || frogDead == 1) { // don't draw the frog when it's on the road or on logs - because they are moving, that's handled in the main drawing routine below- exception is when you are animating frog death
if (frogRow == 1 || frogRow == 3) { // these allow for the blocks being shifted when animating the frog death on rows with logs
ssd1306_setpos(frogColumn*8 + 7 - blockShiftL,frogRow);
} else if (frogRow == 2) {
ssd1306_setpos(frogColumn*8 + blockShiftR,frogRow);
} else {
ssd1306_setpos(frogColumn*8,frogRow);
}
ssd1306_send_data_start();
sendBlock(mode,0); // draw the frog - mode is direction
ssd1306_send_data_stop();
}
}
// Display the frog and all the moving items on the screen
void drawGameScreen(byte mode) {
bool inverse = 0;
// Draw objects going left
for (byte row = 0; row < 6; row+=2) {
if (row >=0 && row < 3) inverse = 1; else inverse = 0; // draw everything (except the frog) in inverse video on the river rows (0,1,2)
ssd1306_setpos(0,row+1); // +1 because row 0 here is actually row 1 on the screen
ssd1306_send_data_start();
for (byte incr = 0; incr < 7-blockShiftL; incr++) if (grid[row][15] == 0) { // cover the tiny bit to the far left of the screen up to wherever the main blocks will be drawn (depends on how far they are shifted)
sendByte(0,inverse); // draw an empty 8-bit line if there's nothing wrapping around
} else {
sendByte(pgm_read_byte(&bitmaps[grid[row][15]-1][1+blockShiftL+incr]), inverse); // pick the correct bit of whatever is wrapping from the right of the screen
}
for (byte col = 0; col < 15; col++) {
if (frogRow == row+1 && frogColumn == col && frogRow < 4 && frogRow > 0) {
sendBlock(mode,0); // if we are in a location with the frog, and it's on the logs, draw it - never invert it (hence zero as second parameter here)
} else if (stopAnimate == 0 && frogRow == row+1 && frogColumn == col + 1 && frogRow > 3 && frogRow < 7) { // frog is amongst the cars and needs drawing
for (byte incr = 0; incr < blockShiftL; incr++) sendByte(0,0); // draw the blank space up to the frog
sendBlock(mode,0); // draw frog
for (byte incr = 0; incr < 7-blockShiftL; incr++) sendByte(0,0); // draw the blank space after the frog
col++; // we've now drawn two columns so increment
} else {
sendBlock(grid[row][col],inverse); // draw the correct object for this space - it's not a frog ;)
}
}
// fill in the bit to the right of the main blocks
for (byte incr = 0; incr < blockShiftL; incr++) if (grid[row][15] == 0) sendByte(0,inverse); else sendByte(pgm_read_byte(&bitmaps[grid[row][15]-1][incr]),inverse);
ssd1306_send_data_stop();
}
if (frogColumn == 0) drawFrog(mode,1); // this covers the exceptional case where the frog is in the far left colum, in which case the normal routine can't draw it when it's on the road
// Draw objects going right - see comments above, works in basically the same way
for (byte row = 1; row < 6; row+=2) {
if (row > 0 && row < 3) inverse = 1; else inverse = 0;
ssd1306_setpos(0,row+1);
ssd1306_send_data_start();
for (byte incr = 0; incr < blockShiftR; incr++) if (grid[row][15] == 0) sendByte(0, inverse); else sendByte(pgm_read_byte(&bitmaps[grid[row][15]-1][incr+(8-blockShiftR)]),inverse);
for (byte col = 0; col < 15; col++) {
if (frogRow == row+1 && frogColumn == col && frogRow < 4 && frogRow > 0) {
sendBlock(mode,0);
} else if (stopAnimate == 0 && frogRow == row+1 && frogColumn == col + 1 && frogRow > 3 && frogRow < 7) {
for (byte incr = 0; incr < 7-blockShiftR; incr++) sendByte(0,0);
sendBlock(mode,0); // draw frog
for (byte incr = 0; incr < blockShiftR; incr++) sendByte(0,0);
col++;
} else {
sendBlock(grid[row][col],inverse);
}
}
for (byte incr = 0; incr < 7-blockShiftR; incr++) if (grid[row][15] == 0) sendByte(0,inverse); else sendByte(pgm_read_byte(&bitmaps[grid[row][15]-1][incr]),inverse);
ssd1306_send_data_stop();
}
if (frogColumn == 0) drawFrog(mode,1);
}
// Send one byte to the screen
void sendByte(byte fill, bool inverse) {
if (inverse == 0) ssd1306_send_byte(fill); else ssd1306_send_byte(~fill);
}
// Send one block of 8 bytes to the screen - inverse means inverse video, for the river section
void sendBlock(byte fill, bool inverse){
for (int incr = 0; incr < 8; incr++) {
if (fill > 0) {
if (inverse == 0) ssd1306_send_byte(pgm_read_byte(&bitmaps[fill-1][incr])); else ssd1306_send_byte(~pgm_read_byte(&bitmaps[fill-1][incr]));
} else if (inverse ==0) ssd1306_send_byte(0); else ssd1306_send_byte(0xFF);
}
}
// Draw the frog lives (in the right hand corner)
void drawLives(void) {
byte tempRow = frogColumn;
byte tempCol = frogRow;
frogRow = 7;
for (int incr = 2; incr > 0; incr--) {
frogColumn = 15-incr;
drawFrog(0,1);
}
for (int incr = lives; incr > 0; incr--) {
frogColumn = 15-incr;
drawFrog(1,1);
}
frogRow = tempCol;
frogColumn = tempRow;
}
// Draw the docks for the frog to land in at top of screen
void drawDocks(void) {
byte drawPos = 3;
for (byte incr = 0; incr < 5; incr++) {
ssd1306_setpos(drawPos,0);
ssd1306_send_data_start();
ssd1306_send_byte(B11111111);
ssd1306_send_byte(B00000001);
ssd1306_send_byte(B00000001);
if (frogDocks[incr] == 1) sendBlock(1,0); else for(byte lxn = 0; lxn < 8; lxn++) ssd1306_send_byte(B00000001);
ssd1306_send_byte(B00000001);
ssd1306_send_byte(B00000001);
ssd1306_send_byte(B11111111);
ssd1306_send_data_stop();
drawPos+= 24;
}
}
// Set all the frog docks to a single value
void resetDock(byte value) { for (byte incr = 0; incr < 5;incr++) frogDocks[incr] = value; }
// Handle what happens at the end of a level
void levelUp(int number) {
// Flash the frog docks
delay(200);
for (byte incr = 0; incr < 5; incr ++) {
resetDock(0);
drawDocks();
for (int i = 800; i>200; i = i - 200){
beep(20,i);
}
resetDock(1);
drawDocks();
for (int i = 800; i>200; i = i - 200){
beep(20,i);
}
}
delay(500);
ssd1306_fillscreen(0x00);
ssd1306_char_f6x8(35, 1, "---------");
ssd1306_char_f6x8(35, 3, " LEVEL ");
ssd1306_char_f6x8(35, 5, "---------");
doNumber(77,3,number);
delay(1500);
ssd1306_fillscreen(0x00);
}
// Move all the items on the game screen (wrapping at the ends) and check for frog dropping off the end of the screen
void moveBlocks(void) {
int direct = 0;
if (flipFlop == 1) flipFlop = 0; else flipFlop = 1;
for (byte row = 0; row < 6; row++) {
// Move the frog along and check to see whether it's gone off the screen, in which case it dies
if (frogRow < 4 && frogRow > 0) {
if (frogRow == row + 1) {
if (direct == 1 && flipFlop == 1) {
if (frogColumn >= 14) stopAnimate = 1; else frogColumn++;
} else if (direct == 0) {
if (frogColumn < 1) stopAnimate = 1; else frogColumn--;
}
}
}
if (direct == 0) { // move left
byte temp = grid[row][0];
for (byte col = 0; col < 15; col++) {
grid[row][col] = grid[row][col+1];
}
grid[row][15] = temp; // wrap around
direct = 1;
} else { // move right
if (flipFlop == 1) {
byte temp = grid[row][15];
for (byte col = 15; col > 0; col--) {
grid[row][col] = grid[row][col-1];
}
grid[row][0] = temp; // wrap around
}
direct = 0;
}
}
}
================================================
FILE: Frogger_Attiny_Arcade/font6x8AJ2.h
================================================
/*
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
*
* @file: font6x8.h
* @created: 2014-08-12
* @author: Neven Boyanov
*
* Hacked by andy jackson to allow two games (originally by webboggles.com) to
* fit onto an ATTiny85 at the same time - hence several characters are missing
* and a couple have been moved to limit the amount of software remapping required
* to map ASCII values onto locations in this array.
*
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
*
*/
// ----------------------------------------------------------------------------
#include <avr/pgmspace.h>
// ----------------------------------------------------------------------------
/* Standard ASCII 6x8 font */
static const uint8_t ssd1306xled_font6x8 [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
/*
0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
0x00, 0x62, 0x64, 0x08, 0x13, 0x23, // %
0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // &
0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // '
0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // *
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // +
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // ,
*/
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // -
0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // .
0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w in place of /
//0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // /
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // :
/*
0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // =
0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // >
0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @
*/
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B
0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C
0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E
0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F
0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G
0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I
0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J
0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K
0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L
0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P
0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R
0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S
0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T
0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W
/*
0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X
0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [
0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 55
0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // '
*/
0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a
0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b
0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c
0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d
0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e
0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f
0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h
0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i
0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l
0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m
0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n
0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o
0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p
0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q
0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r
0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s
0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t
0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x
0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E // @ in place of z
};
// ----------------------------------------------------------------------------
================================================
FILE: Frogger_MAKERbuino/Frogger_MAKERbuino.ino
================================================
/* 2018
*
* Frogger for MakerBuino and GameBuino by Andy Jackson - Twitter @andyhighnumber
*
* You need to install the 'Classic' GameBuino libraries in your Arduino IDE, like this:
* http://legacy.gamebuino.com/wiki/index.php?title=Getting_started#Install_the_Gamebuino_Library_.28Automatic.29
*
* Everything you need to build and run this game is contained in this file and the font
* header (font6x8AJ3.h)
*
* This is a port of a Frogger clone written for the AttinyArcade, which is why some of
* the display routines look a bit weird. More info here:
* https://github.com/andyhighnumber/Attiny-Arduino-Games
*
* 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 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.
*
*/
//imports the SPI library (needed to communicate with Gamebuino's screen)
#include <SPI.h>
//imports the Gamebuino library
#include <Gamebuino.h>
//creates a Gamebuino object named gb
Gamebuino gb;
#include <EEPROM.h>
#include "font6x8AJ4.h"
// Uncomment this #define to make the logs smaller (/thinner)
//#define SMALLLOGS
// Make click delay an even number - it gets halved and then used in an integer comparison
#define CLICKDELAY 120
// The basline speed - higher number is slower
#define MOVEBASE 1000
#define DIGITAL_WRITE_HIGH(PORT) PORTB |= (1 << PORT)
#define DIGITAL_WRITE_LOW(PORT) PORTB &= ~(1 << PORT)
// Routines to set and clear bits (used in the sleep code)
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
// Defines for OLED output
#define lcdDisplayXLED_H
#define lcdDisplay_SCL PORTB4 // SCL, Pin 4 on lcdDisplay Board - for webbogles board
#define lcdDisplay_SDA PORTB3 // SDA, Pin 3 on lcdDisplay Board - for webbogles board
#define lcdDisplay_SA 0x78 // Slave address
// Function prototypes
// Custom draw functions - allow for extra functionality like inverse display
void sendBlock(byte, bool);
void sendByte(byte, bool);
// Other generic functions for games (both originated in code from webboggles.com and the sleep code is by Matthew Little - see above)
void beep(int,int);
void system_sleep(void);
void doNumber (int,int,int);
// Game functions
void playFrogger(void);
void levelUp(int);
void moveBlocks(void);
void initScreen(void);
void drawDocks(void);
void drawLives(void);
void displayTitle(void);
void resetDock(byte);
void checkCollision(void);
// Global variables - yes I know all these global vars is a lazy way to code but it makes it easier to prevent stack overflows when you're working with 512 bytes!
// Most of these are initialised in the main game function (playFrogger())
int watchDog; // Counts drawing cycles so I can shut the game down if there's inactivity - battery saver!
boolean stopAnimate; // this is set to 1 when a collision is detected
int lives; // Lives in the game - this can go negative to end the game, which is why it's a signed variable
bool frogDocks[5]; // Tracks which frog docks are full (at the top of the screen)
bool flipFlop; // Used in routines that flip-flop between two states (left and right)
bool flipFlopShift; // Same as previous one
byte frogColumn; // Column location of frog (there are 16 altogether)
byte frogRow; // Row locaiton of frog (there are 8, but 0 is the frog docks at the top and 7 is the start row)
byte frogLeftLimit; // Left limit of frog travel on start row (changes as digits in score increases)
byte frogRightLimit; // Right limit of frog travel on start row (changes as lives decrease as there's then more space)
byte level; // Level - starts at 1
byte blockShiftL; // Number of pixels to shift the left-going rows by
byte blockShiftR; // Number of pixels to shift the right-going rows by
int interimStep; // Used as timer for incremental movements
int moveDelay; // How long to wait until the next movement of logs etc - changes as levels increase to make the game go faster
int dockedFrogs; // How many frogs are in the docks at the top
unsigned long clickBase; // Timer for debounce
boolean clickLock; // For debounce routine
int score; // Obvious I hope
int topScore; // High score
boolean newHigh; // Is there a new high score?
boolean mute = 0; // Mute the speaker
byte grid[6][16]; // Grid for items like logs, crocs, cars and lorries
byte frogMode; // Represents the frog direction
bool moveForward=0; // Captures when the 'forward' button is pressed
bool moveLeft=0; // Captures when the 'left' button is pressed
bool moveRight=0; // Captures when the 'right' button is pressed
bool moveBack=0; // Captures when the 'right' button is pressed
int screenLeft = 0; // Current left position of the displayed screen
int screenTop = 0; // Current top of the displayed screen
byte currentX = 0; // Current X positon to draw
byte currentY = 0; // Current Y positon to draw
// Bitmaps created by @senkunmusahi using https://www.riyas.org/2013/12/online-led-matrix-font-generator-with.html
static const byte bitmaps[16][8] PROGMEM = {
// Frogs
{0x83, 0xDC, 0x7A, 0x3F, 0x3F, 0x7A, 0xDC, 0x83},
{0x99, 0xBD, 0xDB, 0x7E, 0x7E, 0x3C, 0xE7, 0x81},
{0x81, 0xE7, 0x3C, 0x7E, 0x7E, 0xDB, 0xBD, 0x99},
{0xC1, 0x3B, 0x5E, 0xFC, 0xFC, 0x5E, 0x3B, 0xC1},
#ifdef SMALLLOGS
// Small logs
{0x1C, 0x22, 0x41, 0x55, 0x55, 0x51, 0x43, 0x61},
{0x69, 0x6B, 0x43, 0x61, 0x45, 0x45, 0x61, 0x65},
{0x45, 0x55, 0x41, 0x5D, 0x63, 0x5D, 0x22, 0x1C},
#else
// Bigger logs
{0x3C, 0x7E, 0xD7, 0xB5, 0xAD, 0xBF, 0xFF, 0xED},
{0xAD, 0xAD, 0xFF, 0xB7, 0xF5, 0xBF, 0xB7, 0xAD},
{0xED, 0xBD, 0xC3, 0xBD, 0xA5, 0xBD, 0x42, 0x3C},
#endif
// Trucks
{0x00, 0x7F, 0x41, 0x55, 0x55, 0x55, 0x55, 0x55},
{0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55},
{0x41, 0x7F, 0x22, 0x7F, 0x7F, 0x63, 0x22, 0x1C},
// Crocs
{0x41, 0x63, 0x46, 0x6E, 0x7C, 0x7E, 0x7A, 0x3E},
{0xBC, 0xFE, 0x7E, 0x3E, 0xBE, 0xBE, 0xFC, 0x7C},
{0x78, 0x38, 0x38, 0x38, 0x70, 0x60, 0x60, 0x40},
// Cars
{0x00, 0x1C, 0x22, 0x63, 0x7F, 0x7F, 0x22, 0x22},
{0x22, 0x3E, 0x3E, 0x7F, 0x63, 0x63, 0x22, 0x1C},
{0x22, 0x3E, 0x3E, 0x7F, 0x63, 0x63, 0x22, 0x1C}
};
// Opening artwork created by @senkunmusahi using https://www.riyas.org/2013/12/online-led-matrix-font-generator-with.html
static const byte titleBmp[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xF0, 0x7C, 0x06, 0x73, 0x59, 0x43,
0x06, 0x3C, 0x38, 0x30, 0x30, 0x38, 0x3E, 0x26, 0x7B, 0x59, 0x43, 0x06, 0x7C, 0xF0, 0xC0, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xFF,
0xCF, 0x01, 0x00, 0x00, 0x30, 0x60, 0xE0, 0xC0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0,
0xC0, 0x60, 0x30, 0x00, 0x00, 0x00, 0x01, 0xCF, 0xFE, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7C, 0xFE, 0x86, 0x0E, 0x0E, 0x1C, 0x18, 0x31, 0x7F, 0xFE, 0xFC, 0x1C, 0x18, 0x38, 0x38, 0x38,
0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x18, 0x1C, 0xFC, 0xFE, 0x7F,
0x39, 0x18, 0x1C, 0x0E, 0x0E, 0xC6, 0xFE, 0x3C, 0x00, 0x01, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xC0,
0xC0, 0x80, 0x03, 0x07, 0xFC, 0xF8, 0x00, 0x00, 0xF0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xE0, 0xF0,
0x00, 0x00, 0xF8, 0xFC, 0x0F, 0x03, 0x80, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x03, 0x01, 0x00,
0x04, 0x06, 0x0F, 0x0F, 0x06, 0x06, 0x03, 0x03, 0x03, 0x63, 0x73, 0x33, 0x3B, 0xFF, 0xFF, 0x7F,
0x3F, 0x38, 0xF0, 0xC0, 0x00, 0xF0, 0xF8, 0x3F, 0x7F, 0xFF, 0xFF, 0x3B, 0x33, 0x63, 0x63, 0x03,
0x03, 0x03, 0x06, 0x06, 0x0F, 0x0F, 0x06, 0x00
};
// Opening artwork created by @senkunmusahi using https://www.riyas.org/2013/12/online-led-matrix-font-generator-with.html
const byte PROGMEM openScreen[] = {
57,35,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0f,0xe0,0x00,0x00,0x00,0x00,
0x00,0x00,0x07,0xfc,0x00,0x00,0x00,0x00,
0x00,0x00,0x03,0xff,0xe0,0x00,0x00,0x00,
0x00,0x00,0xff,0xff,0xf8,0x00,0x00,0x00,
0x00,0x00,0x7f,0xff,0xfc,0x00,0x00,0x00,
0x00,0x00,0x1f,0xff,0xe0,0x00,0x00,0x00,
0x00,0x80,0x07,0xff,0xfc,0x20,0x00,0x00,
0x00,0xe0,0x0f,0xff,0xfc,0x30,0x00,0x00,
0x00,0xf0,0x00,0x7f,0xfe,0x30,0x00,0x00,
0x00,0x78,0x00,0x7f,0xbf,0x78,0x00,0x00,
0x00,0x0b,0xf0,0xff,0x7f,0x78,0x00,0x00,
0x00,0x3b,0xff,0xfe,0xff,0x78,0x00,0x00,
0x00,0xff,0xff,0xfd,0xff,0xfc,0x00,0x00,
0x00,0x0e,0x8f,0xfb,0xff,0xfc,0x00,0x00,
0x00,0x09,0x87,0xf7,0xff,0xfe,0x00,0x00,
0x00,0x7a,0x37,0xff,0xff,0xfe,0x00,0x00,
0x00,0x62,0x37,0xff,0xff,0xff,0x00,0x00,
0x00,0xc2,0x07,0xff,0xff,0xff,0x00,0x00,
0x00,0x02,0x07,0xff,0xff,0xff,0x80,0x00,
0x00,0x02,0x0f,0xff,0xfb,0xff,0xc0,0x00,
0x00,0x01,0x0f,0x0f,0xf1,0xff,0xc0,0x00,
0x00,0x00,0x9e,0x07,0xe0,0xff,0xe0,0x00,
0x00,0x00,0x7c,0x63,0xe0,0xff,0xe0,0x00,
0x00,0x00,0x78,0x63,0xf0,0xde,0xf0,0x00,
0x00,0x00,0x78,0x01,0xf0,0xde,0x30,0x00,
0x00,0x00,0x7c,0x01,0x78,0x8e,0x10,0x00,
0x00,0x00,0x3e,0x02,0x38,0x0e,0x00,0x00,
0x00,0x00,0x02,0x02,0x7e,0x06,0x00,0x00,
0x00,0x00,0x03,0x0c,0x7f,0x02,0x00,0x00,
0x00,0x00,0x00,0xf0,0xc9,0x02,0x00,0x00,
0x00,0x00,0x00,0x01,0xcd,0x80,0x00,0x00
};
// Display functions - a legacy from the AttinyArcade version - could be replaced with GameBuino function calls if you wish
void lcdDisplay_send_byte(uint8_t byte);
void lcdDisplay_setpos(uint8_t x, uint8_t y);
void lcdDisplay_fillscreen(uint8_t fill_Data);
void lcdDisplay_char_f6x8(uint8_t x, uint8_t y, const char ch[]);
// Other generic functions for games (both originated in code from webboggles.com)
void doNumber (int, int, int);
void beep(int,int);
void displayTitle(void) {
int incr = 0;
for(int lxn = 0; lxn < 5; lxn++) {
lcdDisplay_setpos(84,lxn);
for(int lxn2 = 0; lxn2 < 40; lxn2++) {
lcdDisplay_send_byte(pgm_read_byte(&titleBmp[incr]));
incr++;
}
}
}
void beep(int bCount,int bDelay){
if (mute) return;
for (int i = 0; i<=bCount; i++){
digitalWrite(3,HIGH);
for(int i2=0; i2<bDelay; i2++){
__asm__("nop\n\t"); // 62.5ns delay @ 16MHz
}
digitalWrite(3,LOW);
for(int i2=0; i2<bDelay; i2++) {
__asm__("nop\n\t"); // 62.5ns delay @ 16Mhz
}
}
}
// Arduino stuff - setup
void setup() {
// initialize the Gamebuino object
gb.begin();
//display the main menu:
//gb.titleScreen(F("FROGGER"),openScreen);
gb.titleScreen(openScreen);
}
void displayOpenScreen(int incr) {
lcdDisplay_fillscreen(1);
if (incr < 99) screenLeft = incr;
lcdDisplay_char_f6x8(0, 1, "F R O G G E R");
lcdDisplay_char_f6x8(0, 3, "andy jackson");
lcdDisplay_char_f6x8(64, 5, "Press A...");
lcdDisplay_setpos(0, 0);
for (int incr2 = 0; incr2 < 76; incr2++) {
lcdDisplay_send_byte(B00111000);
}
lcdDisplay_setpos(0, 2);
for (int incr2 = 0; incr2 < 76; incr2++) {
lcdDisplay_send_byte(B00011100);
}
displayTitle();
}
// Arduino stuff - loop
void loop() {
lcdDisplay_fillscreen(1);
int sChange = 0;
screenLeft = 0;
screenTop = 0;
if (gb.buttons.pressed(BTN_B) == true) {
sChange = 1;
EEPROM.write(0,0);
EEPROM.write(1,0);
lcdDisplay_char_f6x8(0, 0, "--------------");
lcdDisplay_char_f6x8(0, 1, "HI SCORE RESET");
lcdDisplay_char_f6x8(0, 3, "--------------");
while(!gb.update());
delay(2000);
}
if (sChange == 0) {
lcdDisplay_fillscreen(1);
playFrogger();
screenLeft = 0;
screenTop = 0;
topScore = EEPROM.read(0);
topScore = topScore << 8;
topScore = topScore | EEPROM.read(1);
newHigh = 0;
if (score > topScore) {
topScore = score;
EEPROM.write(1, score & 0xFF);
EEPROM.write(0, (score >> 8) & 0xFF);
newHigh = 1;
}
screenLeft = 0;
lcdDisplay_fillscreen(0x00);
lcdDisplay_char_f6x8(0, 0, "------------");
lcdDisplay_char_f6x8(0, 1, "GAME OVER");
lcdDisplay_char_f6x8(0, 3, "------------");
showScore();
while(!gb.update());
delay(2500);
lcdDisplay_fillscreen(0x00);
lcdDisplay_char_f6x8(0, 0, "---------------");
lcdDisplay_char_f6x8(0, 3, "---------------");
doNumber(24, 2, topScore);
if (!newHigh) {
lcdDisplay_char_f6x8(0, 1, "HIGH SCORE:");
} else {
lcdDisplay_char_f6x8(0, 1, "NEW HIGH:");
for (int i = 700; i>200; i = i - 50){
beep(30,i);
}
}
while(!gb.update());
delay(2500);
}
lcdDisplay_fillscreen(1);
gb.display.update();
while(gb.buttons.pressed(BTN_A) == true) { while(!gb.update()); delay(5);}
gb.sound.playNote(63,1,0);
while(!gb.update());
screenLeft = 0;
for (int incr = 0; incr < 46 ; incr+=3) {
displayOpenScreen(incr);
gb.display.update();
if (incr == 0) delay(1700);
}
while(gb.buttons.pressed(BTN_A) == false && gb.buttons.pressed(BTN_B) == false ) {
displayOpenScreen(100);
while(!gb.update());
}
}
void doNumber (int x, int y, int value) {
char temp[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
itoa(value, temp, 10);
lcdDisplay_char_f6x8(x, y, temp);
}
void showScore(void) {
lcdDisplay_char_f6x8(0, 2, "SCORE:");
doNumber(44, 2, score);
}
void lcdDisplay_send_byte(uint8_t input) {
uint8_t *disp;
disp = gb.display.getBuffer();
if ( (currentX >= screenLeft) && (currentX < screenLeft + 84) && (currentY >= screenTop) && (currentY <= screenTop + 5)) {
*(disp + currentX - screenLeft + ((currentY - screenTop) * 84)) = input;
}
currentX++;
}
void lcdDisplay_setpos(uint8_t x, uint8_t y)
{
currentX = x;
currentY = y;
}
void lcdDisplay_fillscreen(uint8_t fill_Data) {
gb.display.setColor(WHITE, BLACK);
for (int i = 0; i < 64; i++) {
for (int j = 0; j < 128; j++) {
gb.display.drawPixel(j, i);
}
}
}
void lcdDisplay_char_f6x8(uint8_t x, uint8_t y, const char ch[]) {
uint8_t c, i, j = 0;
while (ch[j] != '\0')
{
c = ch[j] - 32;
if (c > 0) c = c - 12;
if (c > 15) c = c - 6;
if (c > 40) c = c - 9;
if (x > 126)
{
x = 0;
y++;
}
lcdDisplay_setpos(x, y);
for (i = 0; i < 6; i++)
{
lcdDisplay_send_byte(pgm_read_byte(&lcdDisplayxled_font6x8[c * 6 + i]));
}
x += 6;
j++;
}
}
/* ------------------------
* Frogger main game code
*/
void playFrogger(){
stopAnimate = 0;
score = 0;
moveDelay = MOVEBASE;
level = 1;
frogColumn = 8;
frogRow = 7;
clickLock = 0;
frogMode = 1;
interimStep =0;
blockShiftL = 0;
blockShiftR = 0;
flipFlop = 1;
flipFlopShift = 1;
dockedFrogs = 0;
lives = 2;
frogRightLimit = 12;
watchDog = 1; // we use this to see if there's been movement - it's only ever zero when the frog has just moved!
initScreen();
resetDock(0);
drawFrog(frogMode,0);
drawLives();
doNumber(0,7,score);
drawGameScreen(frogMode);
drawDocks();
screenLeft = 0;
screenTop = 0;
while(!gb.update());
while (lives >= 0) {
drawFrog(frogMode,0);
drawLives();
doNumber(0,7,score);
drawGameScreen(frogMode);
drawDocks();
if (frogColumn*8 < screenLeft + 40) screenLeft--;
if (frogColumn*8 > screenLeft + 50) screenLeft++;
if (frogColumn*8 < screenLeft + 15) screenLeft--;
if (frogColumn*8 > screenLeft + 60) screenLeft++;
/*
if (frogRow == 1 || frogRow == 3) {
screenLeft = frogColumn*8 - 30 - blockShiftL;
} else if (frogRow == 2) {
screenLeft = frogColumn*8 - 30 + blockShiftR;
} else {
screenLeft = frogColumn*8 - 30;
}
*/
screenTop = frogRow - 3;
if (screenLeft < 0) screenLeft = 0;
if (screenTop < 0) screenTop = 0;
if (screenLeft > 43) screenLeft = 43;
if (screenTop > 2) screenTop = 2;
while(!gb.update());
interimStep++;
if (watchDog >= 500) lives = -1; // Stop the game if nothing's happening - maybe triggered in someone's pocket so this is to save battery!
// Calculate left limit of frog movement so it doesn't hit the score
frogLeftLimit = 1;
if ((score / 10) % 10 != 0) frogLeftLimit++;
if ((score / 100) % 10 != 0) frogLeftLimit++;
if ((score / 1000) % 10 != 0) frogLeftLimit++;
// Move stuff along if it's time to
//if (interimStep > moveDelay/8) {
watchDog++;
blockShiftL++;
if (flipFlopShift == 1) flipFlopShift = 0; else flipFlopShift = 1;
if (flipFlopShift == 1) blockShiftR++;
if (blockShiftL == 7) {
moveBlocks();
blockShiftL = 0;
}
if (blockShiftR == 7) {
blockShiftR = 0;
}
interimStep = 0;
checkCollision();
/*
if (stopAnimate == 0) {
drawGameScreen(frogMode);
drawFrog(frogMode,0);
}
*/
//}
// Handle input
if (gb.buttons.pressed(BTN_UP) == true && clickLock == 0) {
moveForward = 1;
watchDog = 0; // reset the watchdog so the game doesn't end!
clickLock = 1;
clickBase = millis();
}
if (gb.buttons.pressed(BTN_DOWN) == true && clickLock == 0) {
moveBack = 1;
watchDog = 0; // reset the watchdog so the game doesn't end!
clickLock = 1;
clickBase = millis();
}
if (gb.buttons.pressed(BTN_LEFT) == true && clickLock == 0) {
moveLeft = 1;
watchDog = 0; // reset the watchdog so the game doesn't end!
clickLock = 1;
//clickBase = millis();
}
if (gb.buttons.pressed(BTN_RIGHT) == true && clickLock == 0) {
moveRight = 1;
watchDog = 0; // reset the watchdog so the game doesn't end!
clickLock = 1;
//clickBase = millis();
}
// Handle moving left
// if(moveLeft == 1 && millis() > clickBase + CLICKDELAY/2) {
if(moveLeft == 1) {
watchDog = 0; // reset the watchdog so the game doesn't end!
moveLeft = 0;
drawFrog(0,0); // delete the frog
// move the frog, checking it isn't jumping off the edge of the screen
if ((frogRow == 7 && frogColumn > frogLeftLimit) || (frogRow < 7 && frogColumn > 0)) {
frogColumn --;
} else if (frogRow < 7) stopAnimate = 1;
frogMode = 2; // pointing left
}
// Handle moving right
// if(moveRight == 1 && millis() > clickBase + CLICKDELAY/2){
if(moveRight == 1){
watchDog = 0; // reset the watchdog so the game doesn't end!
moveRight = 0;
drawFrog(0,0); // delete the frog
// move the frog, checking it isn't jumping off the edge of the screen
if ((frogRow == 7 && frogColumn < frogRightLimit) || (frogRow < 7 && frogColumn < 14)) {
frogColumn ++;
} else if (frogRow < 7) stopAnimate = 1;
frogMode = 3; // pointing right
}
// Handle 'move back' button press
if (moveBack == 1) {
moveBack = 0;
if (frogRow < 7) score-= level; // decrement the score for every move back
if (frogRow < 7) {
// Correct for the skew in frog position created by the blockShift scrolling parameter
if (frogRow == 3 && blockShiftL < 4) frogColumn++;
if (frogRow == 2 && blockShiftR + blockShiftL < 5) frogColumn--;
if (frogRow == 1 && blockShiftR + blockShiftL < 5) frogColumn++;
frogRow++;
frogMode = 4; // mode 1 = forwards position
}
}
// Handle 'move forward' button press
if (moveForward == 1) {
moveForward = 0;
score+= level; // increment the score for every move
doNumber(0,7,score); // display new score
drawFrog(0,0); // delete the frog
if (frogRow > 1) {
frogRow--;
// Correct for the skew in frog position created by the blockShift scrolling parameter
if (frogRow == 3 && blockShiftL < 4) frogColumn--;
if (frogRow == 2 && blockShiftR + blockShiftL < 5) frogColumn++;
if (frogRow == 1 && blockShiftR + blockShiftL < 5) frogColumn--;
} else {
// frog is at the docks!
if (blockShiftL < 4 && frogColumn <15) frogColumn++; // account for skew due to block shifting
byte dockPos = (byte)floor(frogColumn/3);
if (frogDocks[dockPos] == 0 ) {
dockedFrogs++;
frogDocks[dockPos] = 1; // assign this dock as filled
frogRow = 7; // reposition the frog at the start
frogColumn = 8;
drawFrog(frogMode,0);
drawLives();
doNumber(0,7,score);
drawGameScreen(frogMode);
drawDocks();
while(!gb.update());
for (int i = 1000; i>200; i = i - 100){ // make sound
beep(10,i);
}
delay(600);
} else stopAnimate = 1;
}
frogMode = 1; // mode 1 = forwards position
// check if all docks are full - if so, then level up!
if (dockedFrogs >= 5) {
level++;
levelUp(level);
if (moveDelay > 99) moveDelay -=100; // make the game speed up
initScreen(); // reinitalise the position of game items
resetDock(0); // reinitliase the dock
dockedFrogs = 0;
drawDocks(); // display the (now empty) docks
drawLives(); // display the lives
doNumber(0,7,score); // display the score
}
}
// The frog has moved
if (watchDog == 0 && stopAnimate == 0) {
watchDog = 1; // set to something other than zero so this routine doesn't run again
// redraw the screen
drawGameScreen(frogMode);
// redraw the frog
drawFrog(frogMode,0);
// make jump sound
beep(30,400);
beep(30,300);
beep(30,200);
}
checkCollision();
//if (clickLock == 1 && millis() > clickBase + CLICKDELAY && digitalRead(2)==0 && digitalRead(0)==0 && analogRead(0) > 940) clickLock = 0; // normal debounce
clickLock = 0; // No Debounce
// check to see if the frog has been killed
if (stopAnimate != 0) {
// redraw the screen
drawGameScreen(frogMode);
// animation for frog death
drawGameScreen(frogMode);
drawDocks();
drawFrog(0,1);
while(!gb.update());
for (int i = 0; i<250; i = i+ 50){
beep(50,i);
}
drawGameScreen(frogMode);
drawDocks();
drawFrog(frogMode,1);
for (int i = 250; i<500; i = i+ 50){
beep(50,i);
}
drawGameScreen(frogMode);
drawDocks();
drawFrog(0,1);
while(!gb.update());
for (int i = 500; i<750; i = i+ 50){
beep(50,i);
}
drawGameScreen(frogMode);
drawDocks();
drawFrog(frogMode,1);
for (int i = 750; i<1000; i = i+ 50){
beep(50,i);
}
while(!gb.update());
delay(600);
lives--; // increment the score for every move
//frogRightLimit++; // there's one less frog drawn on right so you can move a bit further across (if you really want to!)
stopAnimate = 0; // reset parameter
drawLives(); // display number of lives left
frogColumn = 8; // reinitalise frog location
frogRow = 7;
while(!gb.update());
}
} // Big while loop (main game loop) goes until lives is negative
}
void checkCollision(void) {
if (frogRow > 0 && frogRow < 4 && grid[frogRow-1][frogColumn] == 0) stopAnimate = 1; // the frog has fallen in the river
if (frogRow > 0 && frogRow < 4 && grid[frogRow-1][frogColumn] > 9) stopAnimate = 1; // the frog has stepped on a croc
if ((frogRow < 7 && frogRow > 3) && (grid[frogRow-1][frogColumn] != 0 || grid[frogRow-1][frogColumn-1] != 0)) stopAnimate = 1; // the frog has been hit by a vehicle
}
// Initialise all the moving objects on the game screen
void initScreen(void) {
int initCounter[6] = {3,2,4,2,2,3}; // the length of the objects on each row - doesn't change
int gapCounter[6] = {-2,-3,-4,-4,-3,-5}; // the gaps between objects - change with levels to make it harder as you go thru the game
int counter[6]; // used to hold the gap data
byte stepMode = 0; // which component of the object are we drawing (they all have three - a start a middle and an end)
byte stepShift = 0; // offset to shift up to the different objects in the array
byte crocStartColumn = 0; // column at which to stop drawing crocs - is zero at start hence no crocs!
// Adjust difficulty by changing gaps between objects according to level
if (level == 1) {
gapCounter[5] = -14; // easiset setting, for start of game
}
if (level < 3) {
gapCounter[4] = -6; // make it easier for levels less than 3 by increasing the gap in the cars on this row
}
if (level < 4) {
gapCounter[3] = -7;
}
if (level > 4) {
for (byte incr = 1; incr < 3; incr++) {
gapCounter[incr]--; // increase the gaps between the logs for levels over 4
}
}
if (level > 7) { // set smaller gaps between cars for levels over 7
gapCounter[3] = -4;
gapCounter[4] = -2;
gapCounter[5] = -3;
}
if (level > 2) crocStartColumn = 5; // one croc appears at level 3 and above
if (level > 6) crocStartColumn = 9; // two croc appear at level 7 and above
// Initialise the counters
for (byte incr = 0; incr < 6;incr++) counter[incr] = initCounter[incr];
// Initialise array with zeros
for (byte col = 0; col < 16; col++) {
for (byte row = 0; row < 6; row++) {
grid[row][col] = 0;
}
}
stepMode = 0;
// Initialise array with obstacles
for (byte row = 0; row < 6; row++) {
for (byte col = 0; col < 15; col++) {
if (counter[row] > 0) {
if (14-row > counter[row]) {
if (counter[row] == 1) if (stepMode == 1) stepMode = 2; // the next space is blank and we are drawing the middle - draw the end!
if (row > 2) stepShift = 3; else stepShift = 0; // shift up to the trucks in the array
if (row == 4) stepShift = 9; // shift up to the cars in the array - also theres no middle
if (row > 0) {
grid[row][col] = 5+stepMode+stepShift; // if you are on any row but the first - draw whatever is appropriate from the bitmaps
} else if (col >= crocStartColumn) {
grid[row][col] = 5+stepMode+stepShift; // if you're on row zero (top row of logs) and you are above where crocs should be drawm, draw logs ...
} else grid[row][col] = 11+stepMode; // .. otherwise draw crocs
if (stepMode == 0) stepMode = 1; // we've drawn the left side now switch to central sections
if (stepMode == 2) stepMode = 0; // we've drawn the end, now reset
}
}
counter[row]--; // decrement the counter
if (counter[row] <= gapCounter[row]) {
counter[row] = initCounter[row]; // if we have gone negative enough to account for the gaps - reset the counter and start again
}
}
}
}
// Display the frog
void drawFrog(byte mode, bool frogDead) {
if (frogRow > 6 || frogRow < 1 || frogDead == 1) { // don't draw the frog when it's on the road or on logs - because they are moving, that's handled in the main drawing routine below- exception is when you are animating frog death
if (frogRow == 1 || frogRow == 3) { // these allow for the blocks being shifted when animating the frog death on rows with logs
lcdDisplay_setpos(frogColumn*8 + 7 - blockShiftL,frogRow);
} else if (frogRow == 2) {
lcdDisplay_setpos(frogColumn*8 + blockShiftR,frogRow);
} else {
lcdDisplay_setpos(frogColumn*8,frogRow);
}
sendBlock(mode,0); // draw the frog - mode is direction
}
}
// Display the frog and all the moving items on the screen
void drawGameScreen(byte mode) {
bool inverse = 0;
// Draw objects going left
for (byte row = 0; row < 6; row+=2) {
if (row >=0 && row < 3) inverse = 1; else inverse = 0; // draw everything (except the frog) in inverse video on the river rows (0,1,2)
lcdDisplay_setpos(0,row+1); // +1 because row 0 here is actually row 1 on the screen
for (byte incr = 0; incr < 7-blockShiftL; incr++) if (grid[row][15] == 0) { // cover the tiny bit to the far left of the screen up to wherever the main blocks will be drawn (depends on how far they are shifted)
sendByte(0,inverse); // draw an empty 8-bit line if there's nothing wrapping around
} else {
sendByte(pgm_read_byte(&bitmaps[grid[row][15]-1][1+blockShiftL+incr]), inverse); // pick the correct bit of whatever is wrapping from the right of the screen
}
for (byte col = 0; col < 15; col++) {
if (frogRow == row+1 && frogColumn == col && frogRow < 4 && frogRow > 0) {
sendBlock(mode,0); // if we are in a location with the frog, and it's on the logs, draw it - never invert it (hence zero as second parameter here)
} else if (stopAnimate == 0 && frogRow == row+1 && frogColumn == col + 1 && frogRow > 3 && frogRow < 7) { // frog is amongst the cars and needs drawing
for (byte incr = 0; incr < blockShiftL; incr++) sendByte(0,0); // draw the blank space up to the frog
sendBlock(mode,0); // draw frog
for (byte incr = 0; incr < 7-blockShiftL; incr++) sendByte(0,0); // draw the blank space after the frog
col++; // we've now drawn two columns so increment
} else {
sendBlock(grid[row][col],inverse); // draw the correct object for this space - it's not a frog ;)
}
}
// fill in the bit to the right of the main blocks
for (byte incr = 0; incr < blockShiftL; incr++) if (grid[row][15] == 0) sendByte(0,inverse); else sendByte(pgm_read_byte(&bitmaps[grid[row][15]-1][incr]),inverse);
}
if (frogColumn == 0) drawFrog(mode,1); // this covers the exceptional case where the frog is in the far left colum, in which case the normal routine can't draw it when it's on the road
// Draw objects going right - see comments above, works in basically the same way
for (byte row = 1; row < 6; row+=2) {
if (row > 0 && row < 3) inverse = 1; else inverse = 0;
lcdDisplay_setpos(0,row+1);
for (byte incr = 0; incr < blockShiftR; incr++) if (grid[row][15] == 0) sendByte(0, inverse); else sendByte(pgm_read_byte(&bitmaps[grid[row][15]-1][incr+(8-blockShiftR)]),inverse);
for (byte col = 0; col < 15; col++) {
if (frogRow == row+1 && frogColumn == col && frogRow < 4 && frogRow > 0) {
sendBlock(mode,0);
} else if (stopAnimate == 0 && frogRow == row+1 && frogColumn == col + 1 && frogRow > 3 && frogRow < 7) {
for (byte incr = 0; incr < 7-blockShiftR; incr++) sendByte(0,0);
sendBlock(mode,0); // draw frog
for (byte incr = 0; incr < blockShiftR; incr++) sendByte(0,0);
col++;
} else {
sendBlock(grid[row][col],inverse);
}
}
for (byte incr = 0; incr < 7-blockShiftR; incr++) if (grid[row][15] == 0) sendByte(0,inverse); else sendByte(pgm_read_byte(&bitmaps[grid[row][15]-1][incr]),inverse);
}
if (frogColumn == 0) drawFrog(mode,1);
}
// Send one byte to the screen
void sendByte(byte fill, bool inverse) {
if (inverse == 0) lcdDisplay_send_byte(fill); else lcdDisplay_send_byte(~fill);
}
// Send one block of 8 bytes to the screen - inverse means inverse video, for the river section
void sendBlock(byte fill, bool inverse){
for (int incr = 0; incr < 8; incr++) {
if (fill > 0) {
if (inverse == 0) lcdDisplay_send_byte(pgm_read_byte(&bitmaps[fill-1][incr])); else lcdDisplay_send_byte(~pgm_read_byte(&bitmaps[fill-1][incr]));
} else if (inverse ==0) lcdDisplay_send_byte(0); else lcdDisplay_send_byte(0xFF);
}
}
// Draw the frog lives (in the right hand corner)
void drawLives(void) {
byte tempRow = frogColumn;
byte tempCol = frogRow;
frogRow = 7;
for (int incr = 2; incr > 0; incr--) {
frogColumn = 15-incr;
drawFrog(0,1);
}
for (int incr = lives; incr > 0; incr--) {
frogColumn = 15-incr;
drawFrog(1,1);
}
frogRow = tempCol;
frogColumn = tempRow;
}
// Draw the docks for the frog to land in at top of screen
void drawDocks(void) {
byte drawPos = 3;
for (byte incr = 0; incr < 5; incr++) {
lcdDisplay_setpos(drawPos,0);
lcdDisplay_send_byte(B11111111);
lcdDisplay_send_byte(B00000001);
lcdDisplay_send_byte(B00000001);
if (frogDocks[incr] == 1) sendBlock(1,0); else for(byte lxn = 0; lxn < 8; lxn++) lcdDisplay_send_byte(B00000001);
lcdDisplay_send_byte(B00000001);
lcdDisplay_send_byte(B00000001);
lcdDisplay_send_byte(B11111111);
drawPos+= 24;
}
}
// Set all the frog docks to a single value
void resetDock(byte value) { for (byte incr = 0; incr < 5;incr++) frogDocks[incr] = value; }
// Handle what happens at the end of a level
void levelUp(int number) {
// Flash the frog docks
screenLeft = 0;
screenTop = 0;
delay(200);
for (byte incr = 0; incr < 5; incr ++) {
resetDock(0);
drawDocks();
drawGameScreen(frogMode);
while(!gb.update());
for (int i = 800; i>200; i = i - 200){
beep(20,i);
}
resetDock(1);
drawDocks();
drawGameScreen(frogMode);
while(!gb.update());
for (int i = 800; i>200; i = i - 200){
beep(20,i);
}
}
delay(500);
lcdDisplay_fillscreen(0x00);
lcdDisplay_char_f6x8(14, 1, "---------");
lcdDisplay_char_f6x8(14, 2, " LEVEL ");
lcdDisplay_char_f6x8(14, 4, "---------");
doNumber(32, 3, level);
while(!gb.update());
delay(1500);
lcdDisplay_fillscreen(0x00);
while(!gb.update());
}
// Move all the items on the game screen (wrapping at the ends) and check for frog dropping off the end of the screen
void moveBlocks(void) {
int direct = 0;
if (flipFlop == 1) flipFlop = 0; else flipFlop = 1;
for (byte row = 0; row < 6; row++) {
// Move the frog along and check to see whether it's gone off the screen, in which case it dies
if (frogRow < 4 && frogRow > 0) {
if (frogRow == row + 1) {
if (direct == 1 && flipFlop == 1) {
if (frogColumn >= 14) stopAnimate = 1; else frogColumn++;
} else if (direct == 0) {
if (frogColumn < 1) stopAnimate = 1; else frogColumn--;
}
}
}
if (direct == 0) { // move left
byte temp = grid[row][0];
for (byte col = 0; col < 15; col++) {
grid[row][col] = grid[row][col+1];
}
grid[row][15] = temp; // wrap around
direct = 1;
} else { // move right
if (flipFlop == 1) {
byte temp = grid[row][15];
for (byte col = 15; col > 0; col--) {
grid[row][col] = grid[row][col-1];
}
grid[row][0] = temp; // wrap around
}
direct = 0;
}
}
}
================================================
FILE: Frogger_MAKERbuino/HEX and INF/FROGGER.HEX
================================================
:100000000C94C1030C94E9030C94E9030C94E903E8
:100010000C94E9030C94E9030C94E9030C94E903B0
:100020000C94E9030C94E9030C94E9030C944A063C
:100030000C94E9030C94E9030C94E9030C94E90390
:100040000C94F5050C94E9030C94E9030C94E90372
:100050000C94E9030C94E9030C94E9030C94E90370
:100060000C94E9030C94E9030101FF030101F70378
:100070006C00680000000000240027002A00000037
:100080000000250028002B000500893008023802F6
:100090004978681400000500380168010000175312
:1000A00044001613780016131400151020001520B4
:1000B0001000540A03E181867F3E186D830F0F0EF6
:1000C0000183866033186DC3198F1803C38E6033A4
:1000D000186DE330CF1803C39E603630CDE360CF98
:1000E0003006C79E7E3E30CDB360CF300CC6F66082
:1000F0003330D9B660CF33CFCCF66061B0DB1E6051
:10010000CF30D86CE6C061B0DB1E618F19986CC629
:10011000C063B19B0E330F0FB078C6FF7E1F1B0666
:100120001E0F003923000000000000000000000046
:100130000000000000000070000000000000003E11
:10014000000000000000000FE000000000000007B9
:10015000FC00000000000003FFE00000000000FFC2
:10016000FFF800000000007FFFFC00000000001FFF
:10017000FFE0000000008007FFFC20000000E00F0F
:10018000FFFC30000000F0007FFE3000000078002F
:100190007FBF780000000BF0FF7F780000003BFF7E
:1001A000FEFF78000000FFFFFDFFFC0000000E8F47
:1001B000FBFFFC0000000987F7FFFE0000007A3714
:1001C000FFFFFE0000006237FFFFFF000000C207D4
:1001D000FFFFFF0000000207FFFFFF800000020F8B
:1001E000FFFBFFC00000010F0FF1FFC00000009EE9
:1001F00007E0FFE00000007C63E0FFE00000007823
:1002000063F0DEF00000007801F0DE300000007CDA
:1002100001788E100000003E02380E00000000023F
:10022000027E0600000000030C7F020000000000B8
:10023000F0C902000000000001CD800000000000B5
:10024000000000000080C0F07C06735943063C3873
:100250003030383E267B5943067CF0C080000000D9
:10026000000000000000000000000078FFCF010047
:10027000003060E0C080808080808080C0C06030BE
:1002800000000001CFFE780000000000007CFE8628
:100290000E0E1C18317FFEFC1C18383838393939DD
:1002A0003939393938383838181CFCFE7F39181C70
:1002B0000E0EC6FE3C0001070E1C3870C0C0800345
:1002C00007FCF80000F0C0C0C0C0C0E0F00000F8BB
:1002D000FC0F0380C0E070381C0E03010004060F01
:1002E0000F06060303036373333BFFFF7F3F38F0C2
:1002F000C000F0F83F7FFFFF3B3363630303030657
:10030000060F0F06000000000000000000080808AB
:1003100000000060600000002010080402003E5150
:1003200049453E0000427F4000004261514946007D
:100330002141454B31001814127F100027454545D7
:1003400039003C4A4949300001710905030036492A
:1003500049493600064949291E000036360000008A
:100360007C1211127C007F49494936003E414141CF
:1003700022007F4141221C007F49494941007F09F9
:10038000090901003E4149497A007F0808087F00B9
:1003900000417F4100002040413F01007F081422BE
:1003A00041007F40404040007F020C027F007F04FC
:1003B00008107F003E4141413E007F0909090600C7
:1003C0003E4151215E007F091929460046494949AD
:1003D000310001017F0101003F4040403F001F20EC
:1003E00040201F003F4038403F00205454547800C4
:1003F0007F4844443800384444442000384444484A
:100400007F00385454541800087E0901020018A4D3
:10041000A4A47C007F080404780000447D40000010
:100420004080847D00007F102844000000417F4010
:1004300000007C04180478007C0804047800384428
:1004400044443800FC242424180018242418FC00F8
:100450007C0804040800485454542000043F4440DD
:1004600020003C4040207C001C2040201C003C40E0
:1004700030403C004428102844001CA0A0A07C83ED
:10048000DC7A3F3F7ADC8399BDDB7E7E3CE781816D
:10049000E73C7E7EDBBD99C13B5EFCFC5E3BC13C24
:1004A0007ED7B5ADBFFFEDADADFFB7F5BFB7ADEDD5
:1004B000BDC3BDA5BD423C007F4155555555555561
:1004C00055555555555555417F227F7F63221C4117
:1004D00063466E7C7E7A3EBCFE7E3EBEBEFC7C7871
:1004E00038383870606040001C22637F7F222222EF
:1004F0003E3E7F6363221C223E3E7F6363221C4597
:100500000068010000F6E8DBCFC3B8AEA49B928A76
:10051000827B746E68625C57524E4945413E3A3761
:1005200034312E2C29272523210A0A153A49676ED2
:100530006F7265006D560A0A504C45415345205470
:1005400055524E204F464620004C4F5720424154B2
:100550005445525921200003053F213F1208120A39
:10056000100A0E1C0E0C1E0C141A14161F161E1345
:100570001E1E1B1E1E1F1E3F213F3A2F3A173D17FE
:100580003F213F181F02040A041F0E04040E1F0A15
:100590001F0A0E0E1F04110E2E252E2F2A2E26297D
:1005A00029021F02081F08150E04040E150E15154A
:1005B0001B151B040604040C0400000000170003B4
:1005C00000031F0A1F16371A1904130A153A0003ED
:1005D00000000E11110E000A040A040E040030007F
:1005E0000404040010001804031F111F121F101D23
:1005F000151711151F07041F17151D1F151D0101C4
:100600001F1F151F17151F000A00003200040A11D2
:100610000A0A0A110A040115020E11171E051E1FEF
:10062000150A0E110A1F110E1F15111F05010E11BB
:100630001D1F041F111F1108100F1F041B1F101076
:100640001F061F1E040F0E110E1F09060E112E1F6E
:10065000051A121509011F011F101F0F180F1F0C7B
:100660001F1B041B031C03191513001F110304187F
:10067000111F000201022020200001020C121E1F87
:10068000120C0C12120C121F0C1A14041E05242A30
:100690001E1F021C141D1020201D1F0814111F10E6
:1006A0001E041E1E021C0C120C3E0A040C123E1EDE
:1006B000040214160A020F120E101E0E100E1E084F
:1006C0001E120C1226281E322A26041E21001F008C
:1006D000211E040102013F213F172B152010204C41
:1006E0004F4144455200172B16201314000A4E6F39
:1006F0002053442063617264206F720A6E6F204C35
:100700004F414445522E4845580A0A153A457869E2
:1007100074001D20466C617368696E670A20206C46
:100720006F616465722E2E2E0A0A444F4E275420A4
:100730005455524E204F4646210000000000230031
:100740002600290004040404040404040202020232
:100750000202030303030303010204081020408084
:100760000102040810200102040810200000000803
:100770000002010000030407000000000000000068
:10078000AA1F11241FBECFEFD8E0DEBFCDBF11E0FE
:10079000A0E0B1E0ECE5F4E402C005900D92A03ACF
:1007A000B107D9F724E0A0EAB1E001C01D92A53C51
:1007B000B207E1F713E0C1ECD3E004C02197FE01DA
:1007C0000E942122C03CD107C9F70E94BB150C949E
:1007D0002C220C940000CF92DF92EF92FF920F93A5
:1007E0001F93CF93DF936C017A018B01C0E0D0E0BF
:1007F000CE15DF0589F0D8016D918D01D601ED91FF
:10080000FC910190F081E02DC6010995892B11F42E
:100810007E0102C02196ECCFC701DF91CF911F91DD
:100820000F91FF90EF90DF90CF90089590912E025E
:10083000292F30E0E0910F02F09110022E173F07B0
:1008400024F1AF014D5A5F4F42175307F4F0409126
:100850002D0250E060910D0270910E02461757076D
:10086000A4F0DB011596A417B5077CF02E1B3F0BF7
:10087000461B570B64E5649FF001659FF00D112442
:10088000E20FF31FE55CFD4F80839F5F90932E0284
:100890000895EF92FF920F931F93CF93DF93F82E5B
:1008A000E62E88E0F89E80011124C8E0D0E0FF2009
:1008B00061F0F801EC1BFD0BE158FB4FE11002C0A9
:1008C000849108C08491809505C0E11002C080E049
:1008D00001C08FEF0E941604219749F7DF91CF9155
:1008E0001F910F91FF90EF900895611180950C94E6
:1008F0001604089580E090E008950E942722833036
:1009000081F028F4813099F08230A1F00895873089
:10091000A9F08830B9F08430D1F4809180008F7DC7
:1009200003C0809180008F7780938000089584B504
:100930008F7702C084B58F7D84BD08958091B0000B
:100940008F7703C08091B0008F7D8093B0000895B1
:100950001F93CF93DF93282F30E0F901E459F84F2C
:100960008491F901E85AF84FD491F901EC5BF84F02
:10097000C491CC23C9F0162F81110E947F04EC2F63
:10098000F0E0EE0FFF1FE258FF4FA591B4918FB733
:10099000F894111105C09C91ED2FE095E92302C058
:1009A000EC91ED2BEC938FBFDF91CF911F910895C8
:1009B000CF93DF9390E0FC01E85AF84F2491FC01BB
:1009C000EC5BF84F8491882361F190E0880F991FC8
:1009D000FC01EC58FF4FC591D491FC01E258FF4F48
:1009E000A591B491611109C09FB7F89488812095B1
:1009F00082238883EC912E230BC0623061F49FB771
:100A0000F8943881822F809583238883EC912E2B54
:100A10002C939FBF06C08FB7F894E8812E2B2883B4
:100A20008FBFDF91CF9108951F93CF93DF93182F3E
:100A3000EB0161E00E94D804209711F460E004C04B
:100A4000CF3FD10539F461E0812FDF91CF911F9124
:100A50000C94A804E12FF0E0E459F84FE491E3305E
:100A6000F9F048F4E130B9F0E230A1F584B58062E4
:100A700084BDC8BD34C0E730E9F0E83019F1E43096
:100A800049F580918000806280938000D0938B0034
:100A9000C0938A0024C084B5806884BDC7BD1FC0D0
:100AA00080918000806880938000D0938900C093FB
:100AB000880015C08091B00080688093B000C0931A
:100AC000B3000DC08091B00080628093B000C093ED
:100AD000B40005C0C038D1050CF0B5CFAFCFDF9161
:100AE000CF911F9108958E3008F08E5087708064EA
:100AF00080937C0080917A00806480937A0080915A
:100B00007A0086FDFCCF809178002091790090E0FA
:100B1000922B08953FB7F894809135029091360258
:100B2000A0913702B091380226B5A89B05C02F3F8F
:100B300019F00196A11DB11D3FBFBA2FA92F982F03
:100B40008827820F911DA11DB11DBC01CD0142E07E
:100B5000660F771F881F991F4A95D1F708958F92C6
:100B60009F92AF92BF92CF92DF92EF92FF926B0172
:100B70007C010E948A054B015C01C114D104E1048F
:100B8000F104F1F00E948A05DC01CB018819990972
:100B9000AA09BB09883E9340A105B10570F321E085
:100BA000C21AD108E108F10888EE880E83E0981E89
:100BB000A11CB11CC114D104E104F10419F7DDCF6B
:100BC000FF90EF90DF90CF90BF90AF909F908F906D
:100BD00008952FB7F894609131027091320280919C
:100BE0003302909134022FBF08951F920F920FB6D7
:100BF0000F9211242F933F938F939F93AF93BF93A3
:100C00008091310290913202A0913302B09134026E
:100C10003091300223E0230F2D3720F40196A11DDF
:100C2000B11D05C026E8230F0296A11DB11D20931A
:100C300030028093310290933202A0933302B0933A
:100C400034028091350290913602A0913702B09122
:100C500038020196A11DB11D809335029093360292
:100C6000A0933702B0933802BF91AF919F918F91BB
:100C70003F912F910F900FBE0F901F90189580916C
:100C80003B04882319F080913D0401C080E08093EB
:100C9000B40008951F920F920FB60F9211242F9354
:100CA0003F934F935F936F937F938F939F93AF93F4
:100CB000BF93EF93FF9360913C04662321F18091F1
:100CC0002F028F5F80932F02909139028917D8F0FD
:100CD00090913B0481E0892780933B0410922F027E
:100CE00080913A02882369F08091000193E4899F02
:100CF000802D1124895B809300010E94ED21909347
:100D00003D040E943F06FF91EF91BF91AF919F91EB
:100D10008F917F916F915F914F913F912F910F90A4
:100D20000FBE0F901F9018951F93CF93DF93EC0188
:100D3000162FF89460E08F850E94A8048889181601
:100D40001CF460E00E94A8041EBD00000DB407FE64
:100D5000FDCF8EB5888918161CF461E00E94A804A6
:100D60007894DF91CF911F910895EF92FF921F9396
:100D7000CF93DF93EC018C858F5F8C878BE3E82E1C
:100D800082E0F82E10E0612F6064CE010E9494068C
:100D900060E8CE010E94940661E08F850E94A8045D
:100DA000888918161CF460E00E94A80480E090E096
:100DB000F701E80FF91F20812EBD00000DB407FEDA
:100DC000FDCF2EB501968435910591F788891816C7
:100DD0001CF461E00E94A8041F5F84E5E80EF11C8A
:100DE000163089F660E4CE01DF91CF911F91FF901C
:100DF000EF900C9494060F931F93CF93DF9300E032
:100E000012E0C3E0C0932E0210922D028FEF0E94D9
:100E1000160481E00E94160481E00E941604F80185
:100E200081918F01882329F060E081E00E944904CC
:100E300006C0D8E081E00E941604D150D9F781E0C5
:100E40000E94160481E00E9416048FEF0E9416048F
:100E5000C85ECB37B9F6DF91CF911F910F910895FE
:100E6000909109022FEF290F263080F4662321F19B
:100E7000913011F0933051F420910A02220F220F89
:100E8000220F30910802231B295F0FC020910A0214
:100E9000923041F43091070248E0249F300D112434
:100EA000232F03C0220F220F220F20932E02909394
:100EB0002D0260E00C9449040895FF920F931F9354
:100EC000CF93DF9310910A020091090287E080938B
:100ED00009028DE080930A0261E080E00E94300701
:100EE0008EE080930A0261E080E00E943007C091AA
:100EF0000502D09106028FE0F82E1C161D0654F450
:100F00008F2D8C1B80930A0261E081E00E943007E4
:100F10002197F3CF0093090210930A02DF91CF913A
:100F20001F910F91FF9008954F925F926F927F9261
:100F30008F929F92AF92BF92CF92DF92EF92FF92E9
:100F40000F931F93CF93DF93182FAFEACA2EA1E020
:100F5000DA2EC1E0D0E0B7E0AB2EB12C9C2F01E03F
:100F60008C2F8150833008F000E010922E02909375
:100F70002D02F12C2F2D30E0E0910802F0E0C501A8
:100F80008E1B9F0B28173907A4F4D6018C91882358
:100F900059F03196E20FF31FB8E08B9FE00DF11D81
:100FA0001124E958FB4F8491602F0E947504F3943B
:100FB000E1CF712C7E01E1E0EE1AF1084701F4E087
:100FC000880C991CFA95E1F760910902262F30E010
:100FD0002C173D0769F460900A02671009C08FEF73
:100FE000860F833028F460E0812F0E94490441C0BD
:100FF00040910C02872D90E0411131C02C173D0724
:1010000071F520910A0230E0AC014F5F5F4F241769
:10101000350729F56450633010F5612C8091080282
:10102000681628F480E00E9416046394F7CF60E00D
:10103000812F0E944904612C862D90E020910802A6
:10104000A501421B5109841795072CF480E00E94EA
:1010500016046394F1CF66246394670C0AC0880D6C
:10106000991DFC01E056FE4F602F80810E944904CB
:10107000672C77247394760C5EE0571508F0A4CFA4
:10108000912CC701E4E0880F991FEA95E1F7DC0194
:10109000A155BE4F7D01809108029816C0F4D7017A
:1010A000EC91E11103C0602F80E00DC0F0E03197BA
:1010B00073E0EE0FFF1F7A95E1F7E90DF11DE1589E
:1010C000FB4F8491602F0E9475049394E4CF229685
:1010D000B0E2CB0ED11CC730D10509F03FCF8091D3
:1010E0000A02811104C061E0812F0E9430074FEB9A
:1010F000C42E41E0D42EC2E0D0E058E0452E512C61
:1011000067E0A62EB12C9C2F01E08C2F82508230FC
:1011100008F000E010922E0290932D02F12C8091A5
:101120000702F816C8F4F6019081911103C0602FF0
:1011300080E00EC0F201E81BF109EF0DF11D28E07F
:10114000929FE00DF11D1124E958FB4F8491602F0F
:101150000E947504F394E3CF712C7E0131E0E31A11
:10116000F108470134E0880C991C3A95E1F7609149
:101170000902262F30E02C173D0769F460900A021F
:10118000671009C08FEF860F833028F460E0812F4D
:101190000E94490441C040910C02872D90E041110A
:1011A00031C02C173D0771F520910A0230E0AC01E7
:1011B0004F5F5F4F2417350729F56450633010F5F2
:1011C000612C862D90E020910702A501421B510958
:1011D000841795072CF480E00E9416046394F1CFE5
:1011E00060E0812F0E944904612C809107026816FB
:1011F00028F480E00E9416046394F7CF6624639479
:10120000670C0AC0880D991DFC01E056FE4F602F47
:1012100080810E944904672C77247394760C5EE0E9
:10122000571508F0A4CF912CC70124E0880F991F0F
:101230002A95E1F7DC01A155BE4F7D01E92DF0E0D3
:10124000809107029501281B3109E217F3078CF4FE
:10125000D7018C91882341F0B8E08B9FE00DF11D00
:101260001124E958FB4F8491602F0E9475049394D8
:10127000E5CF229630E2C30ED11CC830D10509F06B
:1012800042CF80910A02811114C061E0812FDF9169
:10129000CF911F910F91FF90EF90DF90CF90BF9073
:1012A000AF909F908F907F906F905F904F900C9435
:1012B0003007DF91CF911F910F91FF90EF90DF905A
:1012C000CF90BF90AF909F908F907F906F905F90E6
:1012D0004F9008952F923F924F925F926F927F921C
:1012E0008F929F92AF92BF92CF92DF92EF92FF9236
:1012F0000F931F93CF93DF93CDB7DEB7A6970FB6AB
:10130000F894DEBF0FBECDBF8CE0E1E0F1E0DE017E
:10131000599601900D928A95E1F78CE0EDE0F1E0AD
:10132000DE011D9601900D928A95E1F780910B02E6
:10133000813029F422EF3FEF388F2F8B02C08330AA
:1013400028F42AEF3FEF3E8B2D8B02C0833041F40F
:1013500029EF3FEF3C8B2B8B8330F0F4512C23C0D3
:101360008430F9F02F85388921503109388B2F8747
:1013700029893A89215031093A8B298B883060F0CC
:101380002CEF3FEF3C8B2B8B2EEF3FEF3E8B2D8BCB
:101390002DEF3FEF388F2F8B873018F0B9E05B2EA1
:1013A00002C0A5E05A2EDE015996CE0101969EA3F9
:1013B0008DA3AE014B5D5F4F9C01CD01FC0161919E
:1013C0007191CF01F901619371939F018417950782
:1013D000A9F760EA71E0AB0120E030E0FA01119278
:1013E000AF01C90180569E4FFC01108A10A210AABD
:1013F0008C01005C1F4FF8011082805B9F4FFC0145
:1014000010822F5F3F4F2031310541F77E01FDE013
:10141000EF0EF11C20E030E010E0FEE0AF2EB12C2A
:10142000EDA1FEA180819181F701C190D1907F0152
:1014300040E050E04501821A930A422E1816190620
:1014400084F5881599056CF58130910519F41130F2
:1014500009F412E01B01240E351E2330310528F05B
:10146000F4E04F1639F003E001C000E0211531052A
:1014700029F402C009E002C0451540F0E5E07E2EE7
:10148000710E672C600EF101608204C00BE0010F49
:10149000F1010083112321F0123019F410E001C092
:1014A00011E00197C816D9061CF08D919C911197F7
:1014B0004F5F5F4F4F30510509F6EDA1FEA18193BB
:1014C0009193FEA3EDA32F5F3F4F1296605F7F4F76
:1014D0002630310509F0A4CFA6960FB6F894DEBFEA
:1014E0000FBECDBFDF91CF911F910F91FF90EF9075
:1014F000DF90CF90BF90AF909F908F907F906F9034
:101500005F904F903F902F900895809109029FEF38
:10151000980F9330A0F490910A02E82FF0E03197F1
:1015200034E0EE0FFF1F3A95E1F7E90FF11DE056A9
:10153000FE4F9081911129C091E090930C029CEF95
:10154000980F933028F590E09C012150310980914B
:101550000A02E82FF0E0C90124E0880F991F2A95BC
:10156000E1F7DC01AE0FBF1FA056BE4F2C91211139
:1015700008C08E0F9F1FFC01E156FE4F808188231B
:1015800039F081E080930C0208959A30A8F6D7CF05
:101590000895AF92BF92CF92DF92EF92FF920F9396
:1015A0001F93CF93DF931F92CDB7DEB7182F7A0129
:1015B00000E0F701E00FF11D8081882381F1803286
:1015C00061F194ED980F903130F09EEC980F9932C4
:1015D00010F095EC980F1F3710F06F5F10E010932C
:1015E0002E0260932D0286E0989F50011124C12C99
:1015F000D12CF601EA0DFB1DEB5FFC4F8491698352
:101600000E9416048FEFC81AD80A698186E0C816AE
:10161000D10479F71A5F0F5FCCCF90E0DCCF0F9049
:10162000DF91CF911F910F91FF90EF90DF90CF90BE
:10163000BF90AF900895EF92FF920F931F93CF93B7
:10164000DF93CDB7DEB72A970FB6F894DEBF0FBE93
:10165000CDBFF82EE62ECA018E010F5F1F4F2AE084
:10166000F80111922A95E9F74AE0B8010E94B51FE6
:10167000A8016E2D8F2D0E94C90A2A960FB6F894E4
:10168000DEBF0FBECDBFDF91CF911F910F91FF90B5
:10169000EF900895EF92FF920F931F93CF93DF93F4
:1016A0007C018B01C0E0D0E0EC16FD06E4F061E0C7
:1016B00083E00E94A80420E030E02017310724F4E2
:1016C00000002F5F3F4FF9CF60E083E00E94A80445
:1016D00020E030E02017310724F400002F5F3F4F57
:1016E000F9CF2196E1CFDF91CF911F910F91FF901C
:1016F000EF900895FC01643508F053C0403308F0C2
:1017000050C090A1742F759575957595262F062E4E
:10171000000C330B542F57709230A1F4F901E55CA3
:10172000FD4F84E57802E00DF11D1124808190E0E9
:10173000052E02C0959587950A94E2F78095982F1B
:1017400091700AC0933041F484858170462740959A
:101750004170841303C014C0911112C084E5780253
:10176000200D311D1124F901E55CFD4F81E090E071
:1017700001C0880F5A95EAF780959081892310C09F
:1017800084E57802200D311D1124F901E55CFD4F3F
:1017900081E090E001C0880F5A95EAF79081892B8B
:1017A00080830895BF92CF92DF92EF92FF920F93C2
:1017B0001F93CF93DF931F92CDB7DEB77C01D62E58
:1017C000C42E002E000C110B040F111D47FD1A959D
:1017D0004C2D0C2C000C550B401751077CF4B12CF0
:1017E000B21654F46B2D6D0D4C2DC70129830E9448
:1017F0007A0BB3942981F4CFC394EACF0F90DF9191
:10180000CF911F910F91FF90EF90DF90CF90BF90FD
:1018100008956F927F928F929F92AF92BF92CF92D4
:10182000DF92EF92FF920F931F93CF93DF93EC0120
:101830006A3019F42D819885A1C06D3009F4A4C0D7
:101840001885BA84D98488A083E58D150CF47FC0EF
:101850008FE28B150CF47BC08C8190E00197189F70
:101860009001199F300D1124C9018D0D911DD7FCD8
:101870009A95181619060CF06AC08D81819FC001D7
:1018800011248B0D911DB7FC9A95181619060CF0B2
:101890005EC09D2CCD2CE62EF12CEC2DED190E2EDC
:1018A000000CFF0B8C8190E0E817F9070CF04EC09C
:1018B0000197E817F90779F0E89E9001E99E300D4D
:1018C000F89E300D1124E20FF31F8E8D9F8DE80FCF
:1018D000F91F749001C0712C6B2CAB2C2A2D2B1985
:1018E000022E000C330B8D8190E0281739075CF530
:1018F00070FE10C0113031F44A2D6C2DCE010E94C3
:101900007A0B1DC0012F212F462D692DCE010E947B
:10191000D20B15C089A198A1891789F088A311302D
:1019200031F44A2D6C2DCE010E947A0B07C0012F95
:10193000212F462D692DCE010E94D20B88A27694CC
:10194000A394610ECBCFC394910EA7CF88A2288514
:101950003C818985329F800D112489879F8199233D
:1019600099F0082E000C990B44E550E0239F401994
:1019700051091124481759073CF49D818A85299FF4
:10198000800D11248A87198681E090E0DF91CF9144
:101990001F910F91FF90EF90DF90CF90BF90AF908D
:1019A0009F908F907F906F900895CF93DF931092C8
:1019B000AC0481E08093AD04D0E0C0E04D2F6C2FEB
:1019C0008CE894E00E947A0BCF5FC038B9F7DF5FF4
:1019D000D03499F7DF91CF910895EF92FF920F9352
:1019E0001F93CF93DF938C0181E00E94D50C0336C7
:1019F000110524F41093100200930F024FE651E0FA
:101A000061E080E00E94C90A4DE751E063E080E0B8
:101A10000E94C90A4AE851E065E080E40E94C90AD0
:101A200010922E0210922D020CE410E088E30E9426
:101A3000160401501109D1F710922E0282E0809312
:101A40002D020CE410E08CE10E94160401501109F3
:101A5000D1F7C0E0E12CF12CD4E5D0932E02C09355
:101A60002D0200E010E0F801EE0DFF1DE35CFD4FDC
:101A700084910E9416040F5F1F4F0832110599F7D9
:101A800088E2E80EF11CCF5FC53039F7DF91CF91C6
:101A90001F910F91FF90EF9008954F925F926F9278
:101AA0007F928F929F92AF92BF92CF92DF92EF92EE
:101AB000FF920F931F93CF93DF9300D000D01F921C
:101AC000CDB7DEB7C090BE04D090BF04E090C00494
:101AD000F090C1040E94E905C61AD70AE80AF90A7B
:101AE0008091BD0490E0A0E0B0E04091B904509135
:101AF000BA046091BB047091BC048C159D05AE05C1
:101B0000BF0530F4411551056105710509F03CC36D
:101B1000452B462B472B09F035C380915504815046
:101B20008E3FC0F5809154048130C9F580916804DE
:101B30008F5F6091690487FD09C0082E000C990B26
:101B400070E06F5F7F4F0E94F921682F60936804F7
:101B500086EE96E09093C3048093C20488E4809359
:101B6000C40480E00E94C9128FEF94E09093710446
:101B700080937004109276041092750481E0809333
:101B8000640489E08093790410927C0410927E04AE
:101B9000109280048091550481508E3F70F48091A2
:101BA0005304813009F095C389ED96E09093C30406
:101BB0008093C20488E48093C40480E00E949C1354
:101BC00080916404882309F4ABC08091780481116A
:101BD000A7C08091700490917104E0917504F09118
:101BE0007604EE0FFF1FE80FF91F45915491411540
:101BF0005105F1F420917404222331F010927604FF
:101C000010927504FC0112C0109264048091630468
:101C1000882341F080E00E949C13E0917504F091CC
:101C200076042DC080E00E94B4127AC04591549190
:101C30009A01369527953695279540FF51C0CA01E0
:101C400016E0969587951A95E1F78F71952F9695E1
:101C50009695969590512F70223071F1F8F42111DC
:101C600017C08B3008F08AE080937904E091750406
:101C7000F09176043196F0937604E0937504EE0FBC
:101C8000FF1F8091700490917104E80FF91FCECF6F
:101C9000213061F760E00E940614E8CF2330B1F0F4
:101CA000243021F720916704829F802D1124809396
:101CB000800490938104DACF20916704829F802D65
:101CC000112480937C0490937D04D0CF20916704ED
:101CD000829F802D112480937E0490937F04C6CF31
:101CE0002F732093770480916704859F802D1124A2
:101CF00080937804109288041092870410928604CE
:101D000081E080937A0480933B0410927B0480915D
:101D100075049091760401969093760480937504EF
:101D200080917A04882309F4EEC0809178048111AF
:101D300003C00E94B412E7C0815080937804809160
:101D40008804811146C020918604309187042F5F5A
:101D50003F4FC901880F991FE0918204F0918304DD
:101D6000E80FF91F65917491862F8770809389041D
:101D7000AB01E3E056954795EA95E1F7CA019695E0
:101D80008795972F9695969590938A048F73909147
:101D90006704899F802D11248093880441704093AB
:101DA0003A0230938704209386048091840490E063
:101DB0002817390770F020918504222339F0821BFF
:101DC0009109909387048093860403C080E00E9469
:101DD000B4128091880481508093880480917B04A0
:101DE00021E0280F20937B044091770430918A04EE
:101DF000340F80916F04380F3093650460917E0436
:101E0000662371F070E0822F022E000C990B0E9465
:101E1000F92180917F04869F300D11243093650451
:101E20008091650490E0849664E270E00E94F9215C
:101E300080936504309179043093660460917C044A
:101E4000662381F0062E000C770B822F022E000CE9
:101E5000990B0E94F92180917D04869F300D1124F9
:101E600030936604609180046623A1F0822F220FD4
:101E7000990B70E00E94F921CB0162E070E00E94B2
:101E8000F9212091810490916604289F900D1124DE
:101E900090936604809166044F3341F08A300CF0D1
:101EA00089E087FD80E08093660402C0109266049A
:101EB000F894E0916504F0E0EB5FFA4FE491E09371
:101EC00039023091660420918B0432039001112471
:101ED000409189044203C001439F900D112400905A
:101EE000680402C0880F991F0A94E2F797FF02C0A6
:101EF00081589F4F880F892F881F990B80933C042E
:101F000080933D0478948091C404882309F48DC0A3
:101F10008C3020F49CE0E92EE81A01C0E12CFF246B
:101F2000F394F09294041092AC041092AD043091AA
:101F300091044DE2D42E1D2D131B1E0D03E0030F43
:101F40002EE4412F63E08CE894E03D830E94D20BA5
:101F50003D810CEF030F1D5F202F41E0612F80E5D5
:101F60000E94D714202F42E0612F83E00E94D714F3
:101F7000F092AC04F092AD040091910413E0100FC4
:101F8000D01ADE0C23E04D2D622F8CE894E02D83D7
:101F90000E947A0B2D812F5F2135A9F71D0DFF249B
:101FA000FA94F10E23E04F2D622F8CE894E02D83FC
:101FB0000E947A0B2D812F5F2135A9F7035033E062
:101FC000D30E402F6D2D80E00E94BF14402F6D2D49
:101FD00083E50E94BF1441E06D2D83E00E9441140F
:101FE00042E06D2D80E50E944114145044E0612FC1
:101FF00080E50E94411448E0612F83E00E94411473
:1020000084E08093950480919104E81A8E2D815D7F
:10201000809396048091C2049091C3040E9434136B
:102020008091C40481508093C40480915A0490919B
:102030005B04892B09F47CC011E01093AC0410926E
:10204000AD049091900485E5891B809395041092CE
:10205000960480915704813009F44DC030F090917E
:102060005604853008F05FC05AC080E00E94C91253
:1020700010939404E7E5F5E0E491EF5FE0939004BA
:10208000E8E5F5E0E491EF5FE093910489E595E000
:102090009093AB048093AA0410925B0410925A04AC
:1020A0001092920418EA0E944D0D8823E1F389E40E
:1020B00095E00E943413609158047091590480E0B7
:1020C00090E04AE00E94321584E395E00E943413C8
:1020D000612F62956F7070E080E090E04AE00E94AE
:1020E000321589E295E00E943413809153048130C7
:1020F00009F0F5C01DC08091AF049091B004A0918B
:10210000B104B091B2048F709927AA27BB27089712
:10211000A105B10510F487E009C088E707C099233D
:1021200039F08B5F03C0992319F08FE20E94731579
:102130008CE894E00E94B5068091920481110EC053
:1021400088EF91E0EBE3F2E0DF019C011D9221506A
:102150003040E1F710929504109296040E948A058F
:102160006093B9047093BA048093BB049093BC0449
:102170002091B5043091B604621B730B7093B404C4
:102180006093B30480E0C5C00E94E9052091BD04BE
:10219000DC01CB01820F911DA11DB11D8093BE04F6
:1021A0009093BF04A093C004B093C1048091AF0486
:1021B0009091B004A091B104B091B2040196A11D18
:1021C000B11D8093AF049093B004A093B104B09379
:1021D000B2041092B9041092BA041092BB04109287
:1021E000BC040E948A056093B5047093B604809382
:1021F000B7049093B80480913F04909140042FE07D
:10220000289F8001299F100D112485E10E947305EC
:10221000800F911F24E0969587952A95E1F790937A
:10222000400480933F0420913E04222309F44BC0D4
:1022300060914204262F30E040E050E029833A8349
:102240004B835C83C0904304D12CE12CF12C409152
:102250004604509147044A01A12CB12C209144041A
:10226000309145042901612C712C8217930728F0C5
:102270009C014817590708F49A01C901A0E0B0E091
:102280009C01AD01241935094609570969817A81F4
:102290008B819C816C197D098E099F090E94DD212B
:1022A000A501940124193509460957090E94002007
:1022B000C20ED31EE41EF51EC09241046C2D70E0C8
:1022C00085E00E9414050E94E0120E947E1581E0C4
:1022D00020C0893209F071CC0E9463136ECC11507A
:1022E00009F0E1CE60E070E085E00E94140583B75C
:1022F000817F846083BF83B7816083BF83B7816040
:1023000083BF889583B78E7F83BF83B78E7F83BF5C
:10231000CACE0F900F900F900F900F90DF91CF913A
:102320001F910F91FF90EF90DF90CF90BF90AF90F3
:102330009F908F907F906F905F904F9008958F92B5
:102340009F92AF92BF92CF92DF92EF92FF920F9344
:102350001F93CF93DF93FB0124913196C490F090AB
:10236000AC04022E000C330B121613060CF0D7C06F
:1023700080330CF0D4C0482F082E000C550BFA0106
:10238000EC0DF11DC7FCFA951E161F060CF0C7C018
:102390006E5F7F4FD901179693E0B595A7959A95F3
:1023A000E1F787FF0BC0C80EA49FC001A59F900D49
:1023B000B49F900D1124681B790B80E04C2D0C2CE0
:1023C000000C550B480F511D87FD5A95413351059F
:1023D0001CF090E3C92EC81A2535310514F024E508
:1023E00030E0109198041827982F977031E001C0C1
:1023F000330F9A95EAF7859585958595F4E58F02D3
:10240000C0011124855C9D4F00E00C2C000CDD0800
:10241000BB24B394402F50E04C155D050CF07FC0F9
:10242000FB01E490F1E0FF1218C0FB01EC0140E871
:10243000542F5E2119F05881532B588350E0559545
:1024400047954115510519F43196E49040E82196DD
:102450005C2F581B521760F359C0F1101AC0A32EFD
:10246000A094FB01EC0140E8542F5E2119F0588143
:102470005A21588350E0559547954115510519F457
:102480003196E49040E821965C2F581B521760F378
:102490003DC043E0F41223C0932E9094FB01EC0165
:1024A00040E8A82E8C2E881A542F5E2141F08126F8
:1024B000588180FE02C0532B01C05921588350E03F
:1024C000559547954115510519F43196E49040E82A
:1024D00021965C2F5A19521728F31B2517C0FB01B0
:1024E000EC0140E8542F5E2119F05881532758839E
:1024F00050E0559547954115510519F43196E490F2
:1025000040E821965C2F581B521760F3330F19F4E3
:102510008C5A9F4F31E00F5F6A0F7B1F7BCFDF919B
:10252000CF911F910F91FF90EF90DF90CF90BF90D0
:10253000AF909F908F900895BC01009791F0FC019F
:1025400001900020E9F73197AF01481B590BE0914A
:102550008C04F0918D040280F381E02D8CE894E0EE
:10256000099480E090E00895811112C010927A04DD
:1025700010927804109287041092860410927B04C3
:1025800010923D0410923C0410923B040C943F06C0
:102590000895811114C010927A0410927804109258
:1025A00087041092860410927B0410923D041092CE
:1025B0003C0410923B040E943F061092640408956C
:1025C000CF92DF92EF92FF920F931F93CF93DF93FF
:1025D000C8E4D4E00FE414E0FF24FA9497E0E92E75
:1025E000E00E62E088810E94D804288130E0F90181
:1025F000E459F84F8491F901E85AF84FC490F90171
:10260000EC5BF84FD490DD2071F081110E947F04C3
:10261000ED2DF0E0EE0FFF1FE65CF84FA591B491B1
:10262000EC91EC21B1F4F80180818F5F808360E050
:1026300088810E94D80421960F5F1F4FE012D1CFEE
:10264000DF91CF911F910F91FF90EF90DF90CF908E
:102650000895F8018081882371F3F8018F3F11F408
:102660001082E5CFF082E3CF0F931F93CF93DF93D8
:102670008C01C0E0D0E0F801EC0FFD1F64916623EF
:1026800071F0E0918C04F0918D040190F081E02DC7
:102690008CE894E00995892B11F02196ECCFCE01BE
:1026A000DF91CF911F910F910895CF93DF930E94F7
:1026B0003413EC0185E991E00E949C128C0F9D1F60
:1026C000DF91CF91089588EF91E0EBE3F2E0DF0135
:1026D0009C011D9221503040E1F710929504109218
:1026E000960482E197E00E9434138CE894E00E9403
:1026F000B5068CB583608CBD8DB58E7F8DBD88E9A8
:1027000091E0EEEFFFE30995109292048DEE96E0D2
:102710000E9455138CE894E00E94B5060E94E012D6
:1027200080915304813039F062E370E080E090E002
:102730000E94AF05F3CF0895AF92BF92CF92DF9280
:10274000EF92FF920F931F93CF93DF93C82ED12C5C
:10275000E601C25CDB4F9DA1992309F44CC07E01C8
:102760009FEFE91AF90AF70195A1911144C09EA5BE
:102770008601000F111F025C1B4FF80134A525A52F
:10278000E32FF22FE90FF11DE90FF11D259134918F
:102790002F3FFFEF3F0711F41DA22DC039ABF6010B
:1027A000EE0FFF1FE85BFB4F3327220F331F05A0FF
:1027B000F6A1E02DE20FF31FA590B490811117C090
:1027C0000E94C912F801B3AAA2AAF601EE0FFF1FD8
:1027D000E05BFB4F16A215A281E0F70185A389E01B
:1027E0008BAF1EAEFE017B9615A2329615A22996DE
:1027F0008DA18F5F8DA3DF91CF911F910F91FF90DE
:10280000EF90DF90CF90BF90AF90089570E0DB0124
:10281000AA0FBB1FA25CBB4FD4962C91D497D59620
:102820009C91D597E22FF92FE80FF11DE80FF11DCC
:10283000259134915F9696963C932E939597F90146
:102840008591949190916704989F802D1124625CEA
:102850007B4FFB01B19685A3F901A591B4914B2F54
:1028600050E0E82FF0E04E175F0720F4F9012591C2
:102870003491832FFB01B296899F802D112485A36B
:102880000895AF92BF92CF92DF92EF92FF920F9393
:102890001F93CF93DF93182F062FC1E0D3E08AEF69
:1028A000D82E9EEFE92E842F8470C82E842F82703C
:1028B000B82E842F8870A82E4170F42E8C2F880F8C
:1028C0008F5FE80ECC2081F04D2F400F6C2F610FF1
:1028D0008CE894E00E947A0B4C2F400F6D2F610F13
:1028E0008CE894E00E947A0BBB2081F0402F4D1BB6
:1028F0006C2F610F8CE894E00E947A0B402F4C1BE8
:102900006D2F610F8CE894E00E947A0BAA2081F071
:102910004C2F400F612F6D1B8CE894E00E947A0BC6
:102920004D2F400F612F6C1B8CE894E00E947A0BB6
:10293000FF2081F0402F4C1B612F6D1B8CE894E031
:102940000E947A0B402F4D1B612F6C1B8CE894E08A
:102950000E947A0BCD1744F4E7FC04C0D150D39405
:10296000D394ED0CCF5FAACFDF91CF911F910F9140
:10297000FF90EF90DF90CF90BF90AF9008950F93AE
:102980001F93CF93DF93182F062FD42FC0E0CD17BE
:102990004CF44C2F400F612F8CE894E00E947A0B8E
:1029A000CF5FF5CFDF91CF911F910F9108959F9247
:1029B000AF92BF92CF92DF92EF92FF920F931F934D
:1029C000CF93DF93F82EE62EB22E03E0020FD0E075
:1029D000C3E08AEFC82E1EEF842F8170982EAA24A0
:1029E000A394A20E4270D42EDF5F802F8B19180F94
:1029F000992081F04C2F440F4A0D6E2D6C1B8D2FAA
:102A00008F0D0E94BF14402F6E2D6D1B8C2F8F0DCC
:102A10000E94BF14DD2081F04C2F440F4A0D6E2D13
:102A20006C1B8F2D8D1B0E94BF14402F6E2D6D1BB4
:102A30008F2D8C1B0E94BF14DC1744F417FD04C0BB
:102A4000C150C394C3941C0D0E5FCECFDF91CF91C4
:102A50001F910F91FF90EF90DF90CF90BF90AF90BC
:102A60009F9008958F929F92AF92BF920F931F9362
:102A7000CF93DF93CDB7DEB7A1970FB6F894DEBF43
:102A80000FBECDBF19A2423008F44AE08E010F5D9F
:102A90001F4F842E912CA12CB12CA50194010E94D2
:102AA0002A20E62FB901CA0101501109EA3014F4B5
:102AB000E05D01C0E95CD801EC93232B242B252B8E
:102AC00061F7C8010E949C12A1960FB6F894DEBF70
:102AD0000FBECDBFDF91CF911F910F91BF90AF90EF
:102AE0009F908F900895E0918C04F0918D04019057
:102AF000F081E02D682F8CE894E0099480915A04CD
:102B000090915B04892BB1F1809162048F7169F51A
:102B100084E10E947305BC01990F880B990B0E94F8
:102B20008C2026EE3FE34EEC50E40E9448210E94A8
:102B30005B209B017093590460935804672B91F0BC
:102B400084E080935704EAE5F4E080E041915191FC
:102B50002417350718F48093570408958F5F843045
:102B6000A9F703C08FEF80935704809162048F5FB1
:102B7000809362040895CF93DF9300D000D000D0FB
:102B8000CDB7DEB7789484B5826084BD84B58160AA
:102B900084BD85B5826085BD85B5816085BD809128
:102BA0006E00816080936E001092810080918100A0
:102BB0008260809381008091810081608093810098
:102BC000809180008160809380008091B10084605A
:102BD0008093B1008091B00081608093B0008091BB
:102BE0007A00846080937A0080917A00826080937A
:102BF0007A0080917A00816080937A0080917A00D7
:102C0000806880937A001092C10082E38093BD04B3
:102C100081E090E0A0E0B0E08093B9049093BA0422
:102C2000A093BB04B093BC048FEF8093AE04E0E8A4
:102C3000F7E7259134912130304C09F049C0E6E99D
:102C4000F7E7E491E0939704E7E9F7E7E491E0938D
:102C50004204E8E9F7E7E491E0934304E9E9F7E7A0
:102C6000859194919093450480934404EBE9F7E7B0
:102C700085919491909347048093460487E08093D4
:102C80006904EEE9F7E7E491E0936804EFE9F7E718
:102C9000E491E093AE04E0EAF7E785919491909394
:102CA0005B0480935A04E2EAF7E78591949190934C
:102CB0005D0480935C04E4EAF7E785919491909336
:102CC0005F0480935E04E6EAF7E7859194912CC057
:102CD0009CE390939704109242048093430480E213
:102CE00093E0909345048093440484ED93E09093A3
:102CF00047048093460487E08093690480936804C6
:102D00008CEA9DE090935B0480935A048EED9DE0E5
:102D100090935D0480935C0484E79EE090935F044D
:102D200080935E048CE39FE0909361048093600441
:102D300011E010933E046FEF70E085E00E941405EF
:102D400088E08093480489E08093490487E0809379
:102D50004A0486E080934B0404E000934C0482E034
:102D600080934D0481E180934E040E94E0128CE335
:102D70009FE0909359048093580400935704109354
:102D800062048BE080939A048DE08093990480E143
:102D900080939B048EE080939D048FE080939C043D
:102DA000109394041093AC041092AD041093930408
:102DB000E7E5F5E0E491EF5FE0939004E8E5F5E006
:102DC000E491EF5FE093910489E595E09093AB0483
:102DD0008093AA041FB7F89480911102811127C033
:102DE000EEE4F7E08491E2E6F7E09491E82FF0E07A
:102DF000EE0FFF1FEC58FF4FA591B491EC91E92322
:102E000021F461E08AE00E94A80461E08AE00E9467
:102E1000D8048CB580618CBD8CB580648CBD61E0BC
:102E20008DE00E94D80461E08BE00E94D80480917C
:102E300011028F5F809311021FBF8CB58F7D8CBDF7
:102E40008CB58C7F81608CBD8DB581608DBD8CB55E
:102E50008C608CBD61E080919A040E94D80461E08E
:102E6000809199040E94D80461E080919B040E94A3
:102E7000D80480919D0418161CF461E00E94D804C7
:102E800080919C0418161CF461E00E94D804809183
:102E90009D04181674F460E00E94A8046AE070E0D3
:102EA00080E090E00E94AF0561E080919D040E9467
:102EB000A80480919904082E000C990BFC01EC5B8E
:102EC000F84FE491F0E0EE0FFF1FE258FF4F25911D
:102ED00034913093A1042093A004FC01E85AF84FE8
:102EE000E491E093A70480919A04082E000C990BBA
:102EF000FC01EC5BF84FE491F0E0EE0FFF1FE258AD
:102F0000FF4F2591349130939F0420939E04FC0140
:102F1000E85AF84FE491E093A60480919C04082EAF
:102F2000000C990BFC01EC5BF84FE491F0E0EE0F24
:102F3000FF1FE258FF4F259134913093A304209353
:102F4000A204FC01E85AF84FE491E093A8048091B0
:102F50009B04082E000C990BFC01EC5BF84FE491EC
:102F6000F0E0EE0FFF1FE258FF4F259134913093B0
:102F7000A5042093A404FC01E85AF84FE491E093DF
:102F8000A90461E28CE894E00E94940664E18CE874
:102F900094E00E9494068091970487FF03C08FE716
:102FA000809397046091970460688CE894E00E9495
:102FB000940660E28CE894E00E9494066CE08CE851
:102FC00094E00E9494068CE894E00E94B50611E01B
:102FD0001093670484E080938B0480E790E09093E3
:102FE00073048093720460E080E00E94061461E044
:102FF00070E083E00E9414058091B100887F8160B9
:103000008093B100F8941092800010928100109289
:1030100085001092840088E191E09093890080936C
:103020008800809181008860809381008091810078
:1030300081608093810080916F00826080936F0037
:1030400078940E947E1580915404813019F4109276
:1030500068041CC0809157048823C9F380E00E9453
:10306000C91288E890E090937104809370041092E4
:103070007604109275041093640489E080937904B7
:1030800010927C0410927E04109280048091AE0411
:10309000882309F458C181E080939404109293042A
:1030A00010929204109256048093AC048093AD0465
:1030B00072E2672E71E0772EECE0FE2E0FEF14E047
:1030C000EE24E394F9E0DF2E0E944D0D8823E1F316
:1030D000F3018491882319F0C090910401C0C12CA0
:1030E00062EB70E080E00E949F1163E271E08CE08F
:1030F0008C0D0E949F1110929504F092960482E22A
:1031000091E00E94341380919004982F990F890FB9
:1031100081958D5A8093950480919104982F990FF1
:10312000890F8195835D809396048091AF0484FF1D
:1031300003C08EEA90E002C08AEA90E00E94551334
:1031400080919004982F990F890F81958D5A8093C3
:103150009504809196048F5F809396048091680413
:10316000882319F086EA90E002C082EA90E00E948B
:10317000551380919004982F990F890F81958D5A3E
:1031800080939504809196048F5F809396048EE9D6
:1031900090E00E94551380915404813039F580915C
:1031A00068048F5F6091690487FD09C0082E000CD8
:1031B000990B70E06F5F7F4F0E94F921682F609339
:1031C000680480E00E94C912109371040093700497
:1031D0001092760410927504E0926404D0927904FF
:1031E00010927C0410927E0410928004809153040B
:1031F0008130B9F08091AE04482F50E060E070E07B
:103200008090AF049090B004A090B104B090B2044C
:1032100084169506A606B70608F483C68F3F09F400
:1032200080C68FEF8093AE0480E00E94C91280E0D8
:103230000E94C91286E990E0909371048093700413
:10324000109276041092750481E08093640499E0F2
:103250009093790410927C0410927E041092800462
:103260008093560470C060E080E090E00E94F21FFE
:1032700060E081E090E00E94F21F4BE351E060E0EB
:1032800080E00E94C90A40E651E061E080E00E94CF
:10329000C90A4BE351E063E080E00E94C90A0E9442
:1032A0004D0D8823E1F360ED77E080E090E00E942F
:1032B000AF0581E00E94D50C8CE894E00E94B50631
:1032C00080915304813009F421C68FE38093770401
:1032D0008091670480937804109288041092870488
:1032E0001092860481E080937A0480933B041092CC
:1032F0007B040E944D0D8823E1F31092100210927E
:103300000F0200E010E0C8010E94ED0C8CE894E090
:103310000E94B5060115110531F464EA76E080E0FB
:1033200090E00E94AF050D5F1F4F0033110559F764
:1033300080915304813009F0FFC580E090E0892B33
:1033400011F00E94000081E00E94D50C1092100242
:1033500010920F0210920E0210920D0280915404EE
:10336000813009F480CF81E00E94D50C10920C02CC
:10337000109229021092280288EE93E0909327027F
:103380008093260281E080930B0298E090930A02DA
:1033900097E09093090210922502809324021092E4
:1033A00023021092220210920802109207028093C8
:1033B00021028093200210921F0210921E0282E0CE
:1033C00090E090930602809305028CE080931D02AA
:1033D00081E090E090931C0280
gitextract_6g324x5n/
├── BatBonanzaAnalog/
│ ├── BatBonanzaAnalog.ino
│ └── font6x8AJ.h
├── BatBonanzaAnalogSinglePot/
│ ├── BatBonanzaAnalogSinglePot.ino
│ └── font6x8AJ.h
├── BatBonanzaAttinyArcade/
│ ├── BatBonanzaAttinyArcade.ino
│ └── font6x8AJ.h
├── Frogger_Attiny_Arcade/
│ ├── Frogger_Attiny_Arcade.ino
│ └── font6x8AJ2.h
├── Frogger_MAKERbuino/
│ ├── Bitmaps/
│ │ └── InfEncoder.jar
│ ├── Frogger_MAKERbuino.ino
│ ├── HEX and INF/
│ │ ├── FROGGER.HEX
│ │ └── FROGGER.INF
│ └── font6x8AJ4.h
├── MorseAttinyArcade/
│ ├── MorseAttinyArcade.ino
│ └── font6x8AJ.h
├── PAK-MAN_MAKERbuino/
│ ├── HEX and INF/
│ │ ├── PAKMAN.HEX
│ │ └── PAKMAN.INF
│ ├── PAK-MAN_MAKERbuino.ino
│ └── font6x8AJ4.h
├── Pacman_Attiny_Arcade/
│ ├── Pacman_Attiny_Arcade.ino
│ └── font6x8AJ3.h
├── README.md
├── SpaceAttackAttiny/
│ ├── SpaceAttackAttiny.ino
│ └── font6x8AJ.h
├── Space_Attack_Analog/
│ ├── Space_Attack_Analog.ino
│ └── font6x8AJ.h
├── Tetris_Attiny_Arcade/
│ ├── Tetris_Attiny_Arcade.ino
│ └── font8x8AJ.h
├── Tetris_Multi_Button/
│ ├── Tetris_Multi_Button.ino
│ └── font8x8AJ.h
├── UFO_Breakout_Arduino/
│ ├── UFO_Breakout_Arduino.ino
│ └── font6x8AJ.h
├── UFO_Stacker_Attiny/
│ ├── UFO_Stacker_Attiny.ino
│ └── font6x8AJ.h
└── WrenRollercoasterAttinyArcade/
├── WrenRollercoasterAttinyArcade.ino
└── font6x8AJ.h
Condensed preview — 36 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (638K chars).
[
{
"path": "BatBonanzaAnalog/BatBonanzaAnalog.ino",
"chars": 22985,
"preview": "/* 2015 / 2016 /2017\n * Pong clone by Andy Jackson - Twitter @andyhighnumber\n * Inspired by http://webboggles.com/ and i"
},
{
"path": "BatBonanzaAnalog/font6x8AJ.h",
"chars": 4925,
"preview": "/*\n * SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays\n *\n * @file: font6x8.h\n * @creat"
},
{
"path": "BatBonanzaAnalogSinglePot/BatBonanzaAnalogSinglePot.ino",
"chars": 22239,
"preview": "/* 2015 / 2016 /2017\n * Pong clone by Andy Jackson - Twitter @andyhighnumber\n * Inspired by http://webboggles.com/ and i"
},
{
"path": "BatBonanzaAnalogSinglePot/font6x8AJ.h",
"chars": 4925,
"preview": "/*\n * SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays\n *\n * @file: font6x8.h\n * @creat"
},
{
"path": "BatBonanzaAttinyArcade/BatBonanzaAttinyArcade.ino",
"chars": 21734,
"preview": "/* 2015 / 2016 /2017\n * Pong game by Andy Jackson - Twitter @andyhighnumber\n * Inspired by http://webboggles.com/ and in"
},
{
"path": "BatBonanzaAttinyArcade/font6x8AJ.h",
"chars": 4925,
"preview": "/*\n * SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays\n *\n * @file: font6x8.h\n * @creat"
},
{
"path": "Frogger_Attiny_Arcade/Frogger_Attiny_Arcade.ino",
"chars": 36663,
"preview": "/* 2015 / 2016 / 2017\n * Frogger game by Andy Jackson - Twitter @andyhighnumber\n * \n * Special thanks to @senkunmusa"
},
{
"path": "Frogger_Attiny_Arcade/font6x8AJ2.h",
"chars": 4914,
"preview": "/*\n * SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays\n *\n * @file: font6x8.h\n * @creat"
},
{
"path": "Frogger_MAKERbuino/Frogger_MAKERbuino.ino",
"chars": 37886,
"preview": "/* 2018\r\n * \r\n * Frogger for MakerBuino and GameBuino by Andy Jackson - Twitter @andyhighnumber\r\n * \r\n * You need "
},
{
"path": "Frogger_MAKERbuino/HEX and INF/FROGGER.HEX",
"chars": 49685,
"preview": ":100000000C94C1030C94E9030C94E9030C94E903E8\r\n:100010000C94E9030C94E9030C94E9030C94E903B0\r\n:100020000C94E9030C94E9030C94E"
},
{
"path": "Frogger_MAKERbuino/font6x8AJ4.h",
"chars": 4819,
"preview": "/*\n * Font file - originally from SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays\n *\n "
},
{
"path": "MorseAttinyArcade/MorseAttinyArcade.ino",
"chars": 21939,
"preview": "/* 2015 / 2016 / 2017\n * Morse decoder for Attiny85 and the #AttinyArcade by Andy Jackson (M0RCL) - Twitter @andyhighn"
},
{
"path": "MorseAttinyArcade/font6x8AJ.h",
"chars": 4873,
"preview": "/*\n * SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays\n *\n * @file: font6x8.h\n * @creat"
},
{
"path": "PAK-MAN_MAKERbuino/HEX and INF/PAKMAN.HEX",
"chars": 50123,
"preview": ":100000000C947F050C94A7050C94A7050C94A705E8\r\n:100010000C94A7050C94A7050C94A7050C94A705B0\r\n:100020000C94A7050C94A7050C94A"
},
{
"path": "PAK-MAN_MAKERbuino/PAK-MAN_MAKERbuino.ino",
"chars": 33737,
"preview": "/* 2018\n * \n * PAK-MAN for MakerBuino and GameBuino by Andy Jackson - Twitter @andyhighnumber\n * \n * You need to i"
},
{
"path": "PAK-MAN_MAKERbuino/font6x8AJ4.h",
"chars": 4819,
"preview": "/*\n * Font file - originally from SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays\n *\n "
},
{
"path": "Pacman_Attiny_Arcade/Pacman_Attiny_Arcade.ino",
"chars": 38520,
"preview": "/* 2015 / 2016 / 2017\r\n Pacman for Attiny Arcade by Andy Jackson - Twitter @andyhighnumber\r\n\r\n Inspired by http:/"
},
{
"path": "Pacman_Attiny_Arcade/font6x8AJ3.h",
"chars": 4923,
"preview": "/*\r\n * SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays\r\n *\r\n * @file: font6x8.h\r\n * @c"
},
{
"path": "README.md",
"chars": 3953,
"preview": "Games for the AttinyArcade (or hardware inspired by this system)\n======================================================="
},
{
"path": "SpaceAttackAttiny/SpaceAttackAttiny.ino",
"chars": 27687,
"preview": "/* 2015 / 2016\n * SpaceAttack game by Andy Jackson - Twitter @andyhighnumber\n * Inspired by http://webboggles.com/ and i"
},
{
"path": "SpaceAttackAttiny/font6x8AJ.h",
"chars": 4923,
"preview": "/*\n * SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays\n *\n * @file: font6x8.h\n * @creat"
},
{
"path": "Space_Attack_Analog/Space_Attack_Analog.ino",
"chars": 27609,
"preview": "/* 2015 / 2016 /2017\n * SpaceAttack game by Andy Jackson - Twitter @andyhighnumber\n * Inspired by http://webboggles.com/"
},
{
"path": "Space_Attack_Analog/font6x8AJ.h",
"chars": 4923,
"preview": "/*\n * SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays\n *\n * @file: font6x8.h\n * @creat"
},
{
"path": "Tetris_Attiny_Arcade/Tetris_Attiny_Arcade.ino",
"chars": 32122,
"preview": "/* 2015 / 2016 /2017\n Tetris for Attiny Arcade\n ========================\n\n When the game is running :\n ========="
},
{
"path": "Tetris_Attiny_Arcade/font8x8AJ.h",
"chars": 5239,
"preview": "/*\n * This font is from http://arduino-er.blogspot.co.uk/2014/08/port-ascii-font-to-arduino-88-led-matrix.html\n * \n * S"
},
{
"path": "Tetris_Multi_Button/Tetris_Multi_Button.ino",
"chars": 34784,
"preview": "/* 2015 / 2016 /2017\n Tetris for Attiny Arcade\n ========================\n\n Before the game starts:\n ============"
},
{
"path": "Tetris_Multi_Button/font8x8AJ.h",
"chars": 5704,
"preview": "/*\n * This font is from http://arduino-er.blogspot.co.uk/2014/08/port-ascii-font-to-arduino-88-led-matrix.html\n * \n * S"
},
{
"path": "UFO_Breakout_Arduino/UFO_Breakout_Arduino.ino",
"chars": 26931,
"preview": "/* 2015 / 2016\n * UFO and Breakout games by Ilya Titov. Find building instructions on http://webboggles.com/\n * The code"
},
{
"path": "UFO_Breakout_Arduino/font6x8AJ.h",
"chars": 4923,
"preview": "/*\n * SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays\n *\n * @file: font6x8.h\n * @creat"
},
{
"path": "UFO_Stacker_Attiny/UFO_Stacker_Attiny.ino",
"chars": 27718,
"preview": "/* 2015 / 2016 / 2017\n * Stacker game by Andy Jackson @andyhighnumber\n * UFO game by Ilya Titov. Find building instructi"
},
{
"path": "UFO_Stacker_Attiny/font6x8AJ.h",
"chars": 4982,
"preview": "/*\n * SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays\n *\n * @file: font6x8.h\n * @creat"
},
{
"path": "WrenRollercoasterAttinyArcade/WrenRollercoasterAttinyArcade.ino",
"chars": 21945,
"preview": "/* 2015 / 2016 /2017\n WREN ROLLERCOASTER game by Andy Jackson - Twitter @andyhighnumber\n \n Inspired by http:/"
},
{
"path": "WrenRollercoasterAttinyArcade/font6x8AJ.h",
"chars": 4925,
"preview": "/*\n * SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays\n *\n * @file: font6x8.h\n * @creat"
}
]
// ... and 3 more files (download for full content)
About this extraction
This page contains the full source code of the andyhighnumber/Attiny-Arduino-Games GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 36 files (598.6 KB), approximately 255.5k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.