#include <LiquidCrystal_I2C.h>
#include <avr/pgmspace.h> // Nécessaire pour PROGMEM
// === Déclarations et constantes ===
const int SEUIL_ACTION_BAS = 15;
const int SEUIL_ACTION_HAUT = 1000;
// Dimensions
const int NB_ZONES = 3; // 3x3 zones
const int MAX_BUISSONS = 10; // 20 buissons par zone
const int LCD_COLONNES = 20;
const int LCD_LIGNES = 4;
// === Définition des graphismes personnalisés ===
byte persoGraphique[] = {B01110, B01010, B00100, B01110, B00100, B00100, B01010, B11011};
byte buissonGraphique[] = {B00000, B01110, B11111, B11111, B11111, B01110, B00000, B00000};
byte clefGraphique[] = {B00110, B00100, B00110, B00100, B00100, B01110, B01010, B01110};
// === Structures ===
struct Coordonnees {
int colonne;
int ligne;
};
struct Zone {
Coordonnees positionPerso;
Coordonnees positionClef;
Coordonnees positionBuissons[MAX_BUISSONS];
int nbBuissons;
bool clefPresente;
};
struct Perso {
Coordonnees position;
int vitesse;
unsigned long compteurVitesse;
};
// === Variables globales ===
LiquidCrystal_I2C lcd(0x27, LCD_COLONNES, LCD_LIGNES);
Zone zones[NB_ZONES][NB_ZONES];
Perso perso = {{0, 0}, 100, 0};
int zoneActuelleX = 1;
int zoneActuelleY = 1;
int J1, J2;
// === Prototypes de fonctions ===
void initialiserZones();
void initialiserLCD();
void changerZone(int nouvelleZoneX, int nouvelleZoneY, const char* direction = "");
void afficherPersonnage();
void effacerCase(int colonne, int ligne);
void ramasserObjets();
void deplacementJoystick();
void gererCollisionBuissons();
void deplacerPerso(int dx, int dy);
void effetEffacementProgressif();
void effetClignotement();
// === Configuration initiale ===
void setup() {
initialiserZones();
initialiserLCD();
}
void loop() {
if (millis() > perso.compteurVitesse + perso.vitesse) {
deplacementJoystick();
ramasserObjets();
afficherPersonnage();
perso.compteurVitesse = millis(); // Mise à jour après les actions
}
}
// Exemple de motif générique en forme de forêt (max 20 buissons)
const byte MOTIF_FORET[10][2] = {
{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1},
{15, 1}, {16, 1}, {17, 1}, {18, 1}, {19, 1}
/*
, {2, 2}, {2, 3}, {2, 4 },
{3, 1}, {3, 2}, {3, 3}, {3, 4},
{0, 1}, {0, 2}, {0, 3},{0, 0},
*/
};
const byte MOTIF_FORET_DEUX[10][2] = {
{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1},
{15, 1}, {16, 1}, {17, 1}, {18, 1}, {19, 1}
/*
{5, 0}
, {2, 3}, {2, 4 },
{3, 1}, {3, 2}, {3, 3}, {3, 4},
{0, 1}, {0, 2}, {0, 3},{0, 0},
*/
};
const byte MOTIF_FORET_TROIS[10][2] = {
{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1},
{15, 1}, {16, 1}, {17, 1}, {18, 1}, {19, 1}
/*
, {2, 2}, {2, 3}, {2, 4 },
{3, 1}, {3, 2}, {3, 3}, {3, 4},
{0, 1}, {0, 2}, {0, 3},{0, 0},
*/
};
// Fonction pour initialiser les zones avec le motif décalé
void initialiserZones() {
for (int i = 0; i < NB_ZONES; i++) {
for (int j = 0; j < NB_ZONES; j++) {
zones[i][j].nbBuissons = MAX_BUISSONS;
zones[i][j].clefPresente = true;
// zone à gauche
if (i == 0 && j == 1) { // Zone à gauche de centre
for (int k = 0; k < MAX_BUISSONS; k++) {
if (k < 10) { // Ajustement pour éviter de dépasser MAX_BUISSONS
zones[i][j].positionBuissons[k] = {MOTIF_FORET[k][0], MOTIF_FORET[k][1]};
}
}
}
// zone centrale
else if (i == 1 && j == 1) { // Centre de la grille (modifiable selon vos besoins)
for (int k = 0; k < MAX_BUISSONS; k++) {
if (k < 10) { // Ajustement pour éviter de dépasser MAX_BUISSONS
zones[i][j].positionBuissons[k] = {MOTIF_FORET_DEUX[k][0], MOTIF_FORET_DEUX[k][1]};
}
}
}
// zone à droite
else if (i == 2 && j == 1) { // Zone à gauche de centre
for (int k = 0; k < MAX_BUISSONS; k++) {
if (k < 10) { // Ajustement pour éviter de dépasser MAX_BUISSONS
zones[i][j].positionBuissons[k] = {MOTIF_FORET_TROIS[k][0], MOTIF_FORET_TROIS[k][1]};
}
}
}
}
}
}
/*
// === Initialisation des zones ===
void initialiserZones() {
for (int i = 0; i < NB_ZONES; i++) {
for (int j = 0; j < NB_ZONES; j++) {
zones[i][j].nbBuissons = MAX_BUISSONS;
zones[i][j].clefPresente = true;
zones[i][j].positionClef = {random(0, LCD_COLONNES), random(0, LCD_LIGNES)};
int index = 0;
// Choix du motif en fonction de (i + j) % 2
if ((i + j) % 2 == 0) {
// Motif 1 : Une ligne horizontale au centre
int centreY = LCD_LIGNES / 2;
for (int x = 0; x < MAX_BUISSONS && x < LCD_COLONNES; x++) {
zones[i][j].positionBuissons[index++] = {x, centreY};
}
} else {
// Motif 2 : Un carré autour du centre
int centreX = LCD_COLONNES / 2;
int centreY = LCD_LIGNES / 2;
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
if (index < MAX_BUISSONS) {
zones[i][j].positionBuissons[index++] = {centreX + dx, centreY + dy};
}
}
}
}
}
}
}
*/
/*Ligne diagonale :
for (int k = 0; k < MAX_BUISSONS; k++) {
zones[i][j].positionBuissons[k] = {k, k}; // Diagonale simple
}
*/
/* Carré autour du centre :
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
if (index < MAX_BUISSONS) {
zones[i][j].positionBuissons[index++] = {centreX + dx, centreY + dy};
}
}
}
*/
/*
// Horizontal de la croix
for (int x = centreX - 2; x <= centreX + 2; x++) {
if (index < MAX_BUISSONS) {
zones[i][j].positionBuissons[index++] = {x, centreY};
}
}
// Vertical de la croix
for (int y = centreY - 2; y <= centreY + 2; y++) {
if (index < MAX_BUISSONS) {
zones[i][j].positionBuissons[index++] = {centreX, y};
}
}
*/
// === Initialisation de l'afficheur LCD ===
void initialiserLCD() {
lcd.init();
lcd.backlight();
lcd.createChar(0, persoGraphique);
lcd.createChar(1, buissonGraphique);
lcd.createChar(4, clefGraphique);
changerZone(1, 1);
}
// === Gestion des zones et transitions ===
void changerZone(int nouvelleZoneX, int nouvelleZoneY, const char* direction) {
if (nouvelleZoneX < 0 || nouvelleZoneX >= NB_ZONES || nouvelleZoneY < 0 || nouvelleZoneY >= NB_ZONES) {
return; // Hors limites
}
zones[zoneActuelleX][zoneActuelleY].positionPerso = perso.position; // Sauvegarde
zoneActuelleX = nouvelleZoneX;
zoneActuelleY = nouvelleZoneY;
// Réinitialisation du personnage
if (strcmp(direction, "droite") == 0) {
perso.position = {0, perso.position.ligne};
} else if (strcmp(direction, "gauche") == 0) {
perso.position = {LCD_COLONNES - 1, perso.position.ligne};
} else if (strcmp(direction, "haut") == 0) {
perso.position = {perso.position.colonne, LCD_LIGNES - 1};
} else if (strcmp(direction, "bas") == 0) {
perso.position = {perso.position.colonne, 0};
}
effetClignotement();
effetEffacementProgressif();
Zone &zone = zones[zoneActuelleX][zoneActuelleY];
if (zone.clefPresente) {
lcd.setCursor(zone.positionClef.colonne, zone.positionClef.ligne);
lcd.write(4);
}
for (int i = 0; i < zone.nbBuissons; i++) {
lcd.setCursor(zone.positionBuissons[i].colonne, zone.positionBuissons[i].ligne);
lcd.write(1);
}
afficherPersonnage();
}
// === Affichage et gestion des objets ===
void effacerCase(int colonne, int ligne) {
lcd.setCursor(colonne, ligne);
lcd.print(" ");
}
void afficherPersonnage() {
lcd.setCursor(perso.position.colonne, perso.position.ligne);
lcd.write(0);
}
void ramasserObjets() {
Zone &zone = zones[zoneActuelleX][zoneActuelleY];
if (perso.position.colonne == zone.positionClef.colonne &&
perso.position.ligne == zone.positionClef.ligne &&
zone.clefPresente) {
zone.clefPresente = false;
effacerCase(zone.positionClef.colonne, zone.positionClef.ligne);
}
}
void gererCollisionBuissons() {
Zone &zone = zones[zoneActuelleX][zoneActuelleY];
for (int i = 0; i < zone.nbBuissons; i++) {
if (perso.position.colonne == zone.positionBuissons[i].colonne &&
perso.position.ligne == zone.positionBuissons[i].ligne) {
return; // Collision détectée
}
}
}
void deplacerPerso(int dx, int dy) {
int nouvelleColonne = perso.position.colonne + dx;
int nouvelleLigne = perso.position.ligne + dy;
Zone &zone = zones[zoneActuelleX][zoneActuelleY];
for (int i = 0; i < zone.nbBuissons; i++) {
if (nouvelleColonne == zone.positionBuissons[i].colonne &&
nouvelleLigne == zone.positionBuissons[i].ligne) {
return; // Collision
}
}
if (nouvelleColonne >= 0 && nouvelleColonne < LCD_COLONNES &&
nouvelleLigne >= 0 && nouvelleLigne < LCD_LIGNES) {
effacerCase(perso.position.colonne, perso.position.ligne);
perso.position.colonne = nouvelleColonne;
perso.position.ligne = nouvelleLigne;
afficherPersonnage();
}
}
// === Effets visuels ===
void effetEffacementProgressif() {
for (int ligne = 0; ligne < LCD_LIGNES; ligne++) {
lcd.setCursor(0, ligne);
lcd.print(" ");
delay(50);
}
delay(100);
}
void effetClignotement() {
for (int i = 0; i < 3; i++) {
lcd.noBacklight();
delay(100);
lcd.backlight();
delay(100);
}
}
// === Déplacement du personnage ===
void deplacementJoystick() {
J1 = analogRead(0);
J2 = analogRead(1);
if (J1 < SEUIL_ACTION_BAS) {
if (perso.position.ligne < LCD_LIGNES - 1) {
deplacerPerso(0, 1);
} else if (zoneActuelleY < NB_ZONES - 1) {
changerZone(zoneActuelleX, zoneActuelleY + 1, "bas");
}
}
if (J1 > SEUIL_ACTION_HAUT) {
if (perso.position.ligne > 0) {
deplacerPerso(0, -1);
} else if (zoneActuelleY > 0) {
changerZone(zoneActuelleX, zoneActuelleY - 1, "haut");
}
}
if (J2 < SEUIL_ACTION_BAS) {
if (perso.position.colonne < LCD_COLONNES - 1) {
deplacerPerso(1, 0);
} else if (zoneActuelleX < NB_ZONES - 1) {
changerZone(zoneActuelleX + 1, zoneActuelleY, "droite");
}
}
if (J2 > SEUIL_ACTION_HAUT) {
if (perso.position.colonne > 0) {
deplacerPerso(-1, 0);
} else if (zoneActuelleX > 0) {
changerZone(zoneActuelleX - 1, zoneActuelleY, "gauche");
}
}
}