#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "icone.h"
#include "puro.h"
#include "puroEarsAnim.h"
#include "puroTailAnim.h"
#include "puroEyesAnim.h"
void createMenu();
void displayHunger();
void displayPuroBase();
void displayMenu();
void displayPuroRigthEarAnim();
void displayPuroLeftEarAnim();
void resetMillis();
void displayBlank(uint8_t Xi, uint8_t Xf, uint8_t Yi, uint8_t Yf);
void select();
void selectHunger();
void selectLight();
void selectBrush();
void selectGame();
void selectPet();
void selectStatus();
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//variabili per fame
uint8_t oldHunger = 0;
uint8_t newHunger = 40;
static const uint8_t maxHunger = 120;
//variabile per 'morte'
bool puroDeath = false;
//struct per menu
typedef struct cell{
unsigned char * data;
cell * next;
cell * prev;
};
cell * menu = nullptr;
uint8_t Brpin = 19;
bool Br;
uint8_t Bcpin = 18;
bool Bc;
uint8_t Blpin = 4;
bool Bl;
bool refresh = false;
unsigned long previousTime;
unsigned long currentTime;
unsigned long deltaTime;
unsigned long hungerRemove = 5 * 60 * 1000;
//array di puntatori alle bitmap
static unsigned char * icons[] = {HUNGER_ICO, LIGHT_ICO, BRUSH_ICO, PET_ICO, GAME_ICO, STATUS_ICO};
void setup() {
Serial.begin(9600);
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { //se non trova il display entra in un loop infinito
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
unsigned long startUp = millis();
pinMode(19, INPUT);
pinMode(18, INPUT);
pinMode(4, INPUT);
createMenu(); //creo il menu con lista circolare doppiamente linkata senza sentinella
display.clearDisplay(); //pulisce display
}
void loop() {
displayHunger(); Serial.println(newHunger);
displayPuroBase(); //display puro idle animation
displayMenu(); //display menu
if(!newHunger) puroDeath = true;//se la fame scende a zero sarà visualizzata la sprite di 'morte' finche non si fa qualcosa che deve essere ancora scelto
if(puroDeath) for(;;){
/*************************************/
/*codice da eseguire in caso di morte*/
/*************************************/
displayPuroBase(); //display puro idle animation
displayMenu(); //display menu
}
display.display();
//newHunger--;//test
/*
quando dovrai fare l'animazione, per evitare di dover aspettare la fine dell'animazione fai una cosa come
nel casco e ci metti un 'whilie per il blink', così nel frattempo che si aspetta per il cambio frame
comunque si controlla per la pressione del pulsante
*/
while(!refresh){
Br = digitalRead(Brpin);
Bl = digitalRead(Blpin);
Bc = digitalRead(Bcpin);
if(Br){
while(digitalRead(Brpin)) delay(1);
displayPuroRigthEarAnim();
menu = menu->next;
refresh = true;
}
if(Bl){
while(digitalRead(Blpin)) delay(1);
displayPuroLeftEarAnim();
menu = menu->prev;
refresh = true;
}
if(Bc){
while(digitalRead(Bcpin)) delay(1);
select();
refresh = true;
}
delay(1);
currentTime = millis();
if(currentTime < previousTime) resetMillis();
else if(currentTime - previousTime >= hungerRemove){
newHunger--;
previousTime = currentTime;
}
if(newHunger != oldHunger) refresh = true;
}
refresh = false;
display.clearDisplay(); //pulisce display
}
void resetMillis() {
// Disabilita le interruzioni
cli();
// Resetta il conteggio di millis()
*((volatile unsigned long *)0x44) = 0;
*((volatile unsigned long *)0x48) = 0;
// Abilita le interruzioni
sei();
}
void displayPuroBase() {
display.drawBitmap(20, 2, Puro, 72, 52, 1); //display Puro bitmap
}
void displayPuroRigthEarAnim(){
displayBlank(20, 35, 10, 30);
display.drawBitmap(20, 2, PuroRigthEarIdle1, 72, 52, 1); //display idlePuro ear1
display.display();
displayBlank(20, 35, 10, 30);
display.drawBitmap(20, 2, PuroRigthEarIdle2, 72, 52, 1); //display idlePuro ear2
display.display();
displayBlank(20, 35, 10, 30);
display.drawBitmap(20, 2, PuroRigthEarIdle1, 72, 52, 1); //display idlePuro ear1
display.display();
}
void displayPuroLeftEarAnim(){
displayBlank(23, 35, 34, 44);
display.drawBitmap(20, 2, PuroLeftEarIdle1, 72, 52, 1); //display idlePuro ear1
display.display();
displayBlank(23, 35, 34, 44);
display.drawBitmap(20, 2, PuroLeftEarIdle2, 72, 52, 1); //display idlePuro ear2
display.display();
displayBlank(23, 35, 34, 44);
display.drawBitmap(20, 2, PuroLeftEarIdle1, 72, 52, 1); //display idlePuro ear1
display.display();
}
void displayPuroTailAnim(){
displayBlank(73, 89, 2, 17);
display.drawBitmap(20, 2, PuroTailIdle1, 72, 52, 1); //display idlePuro ear1
display.display();
displayBlank(73, 89, 2, 17);
display.drawBitmap(20, 2, PuroTailIdle2, 72, 52, 1); //display idlePuro ear2
display.display();
displayBlank(73, 89, 2, 17);
display.drawBitmap(20, 2, PuroTailIdle1, 72, 52, 1); //display idlePuro ear1
display.display();
}
void displayBlank(uint8_t Xi, uint8_t Xf, uint8_t Yi, uint8_t Yf){
for(uint8_t i = Xi ; i < Xf ; ++i){//x
for(uint8_t j = Yi ; j < Yf ; ++j){//y
display.drawPixel(i, j, SSD1306_BLACK);
}
}
}
void displayHunger(){
uint8_t upperHunger = newHunger/2, lowerHunger = newHunger-upperHunger; //calcolo lower e upper hunger
if(newHunger == 0) display.drawPixel(11, 60, SSD1306_BLACK);
else{
if(newHunger == 1) display.drawPixel(11, 60, SSD1306_WHITE); //se la fame è a uno fa vedere un pixel
else{
if(upperHunger > 0) {
display.drawLine(10, 60, 10, 61-upperHunger, SSD1306_WHITE); //display upper hunger
display.drawLine(11, 60, 11, 61-lowerHunger, SSD1306_WHITE); //display lower hunger
}
}//SSD1306_BLACK
}
//display.display(); //aggiorna buffer
oldHunger = newHunger; //aggiorna hunger
}
void createEmptyList() { //crea lista vuota con la sentinella
menu= new cell;
menu->next = menu;
menu->prev = menu;
menu->data = sentinel; //si inizializza con una sprite apposita
}
void headInsert(unsigned char * icona){ //inserimento in testa delle icone del menu
cell * newElement = new cell; //creazione nuova cella
newElement->data = icona; //inserimento icona
newElement->next = menu->next; //il prossimo elemento sarà quello precedentemente inserito
newElement->prev = menu; //il precedente sarà il menu
newElement->prev->next = newElement; //il prossimo elemento dopo la sentinella sarà la cella inserita
newElement->next->prev = newElement; //il precedente dell'elemento dopo è l'elemento inserito
}
void createMenu(){
createEmptyList(); //crea lista vuota
for(uint8_t i = 0 ; i < 6 ; ++i) headInsert(icons[5-i]); //inserimento di tutti gli elementi al contrario, così la prima sarà la fame
cell * cur = menu -> next; //eliminazione dela sentinella
menu->prev->next = menu->next;
menu->next->prev = menu->prev;
delete menu;
menu = cur;
}
void displayMenu(){
display.drawBitmap(109, 43, menu->prev->data, 16, 16, 1); //display menu cella precedente
display.drawBitmap(109, 23, menu->data, 16, 16, 1); //display menu cella puntata
display.drawBitmap(108, 22, frame, 24, 18, 1); //display frame
display.drawBitmap(109, 3, menu->next->data, 16, 16, 1); //display menu cella successiva
//display.display(); //aggiorna buffer
}
void select(){
if(menu->data == HUNGER_ICO) selectHunger();
if(menu->data == LIGHT_ICO) selectLight();
if(menu->data == BRUSH_ICO) selectBrush();
if(menu->data == GAME_ICO) selectGame();
if(menu->data == PET_ICO) selectPet();
if(menu->data == STATUS_ICO) selectStatus();
}
void selectHunger()
{
Serial.println("hunger");
displayPuroTailAnim();
}
void selectLight()
{
Serial.println("light");
}
void selectBrush()
{
Serial.println("brush");
}
void selectGame()
{
Serial.println("game");
}
void selectPet()
{
Serial.println("pet");
}
void selectStatus()
{
Serial.println("status");
}