STEMGAME ESP32 LCD INTEGRADO
ESQUEMA FRITZING
Permite usar un teclado flexible 1x4 o 4 botones físicos, si usa teclado flexible (2 - 1 - 4 - 3 - GND)
*PCB sin botones físicos - Requiere flex.
CODIGO ARDUINO
//STEMGAME ESP32 CON PANTALLA INTEGRADA
//CONFIGURACION DE BOTONES PULLUP CON USO DE RESISTENCIA INTERNA
//NUMEROS ENTEROS - NUMEROS DECIMALES - QUIMICA - BIOLOGIA
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <SPI.h>
#define TFT_CS 15
#define TFT_RST 4
#define TFT_DC 2
#define TFT_BL 32 // Pin para controlar el backlight
// Definición de pines
#define BUTTON_A 25
#define BUTTON_B 27
#define BUTTON_C 14
#define BUTTON_D 13
#define BUZZER 16
const int botones[] = {BUTTON_A, BUTTON_B, BUTTON_C, BUTTON_D};
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);
// ========== VARIABLES GLOBALES ==========
int juegoActual = 0; // 0: Menú, 1: Enteros, 2: Decimales, 3: Química, 4: Biología
bool juegoSeleccionado = false;
// ========== VARIABLES PARA JUEGOS MATEMÁTICOS ==========
// Variables para el juego de números enteros
float scoreEnteros = 0;
int currentQuestionEnteros = 0;
int totalQuestionsEnteros = 10;
unsigned long startTimeEnteros = 0;
unsigned long totalTimeEnteros = 0;
bool juegoEnProgresoEnteros = false;
struct Question {
int num1;
int num2;
char operation;
int correctAnswer;
int options[4];
};
Question questionsEnteros[10];
// Variables para el juego de números decimales
float puntuacionDecimales = 0;
int preguntaActualDecimales = 0;
unsigned long tiempoInicioDecimales = 0;
unsigned long tiempoFinalDecimales = 0;
bool midiendoTiempoDecimales = false;
float num1Decimales, num2Decimales, resultadoDecimales;
char opcionesDecimales[4][10];
int respuestaCorrectaDecimales;
// ========== VARIABLES PARA QUIZZES ==========
int pregunta_actual = 0;
int puntuacion = 0;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 200;
int preguntas_seleccionadas[10];
// Datos de Química
const char* preguntas_quimica[] = {
"Simbolo quimico del agua?", // A (H2O)
"Elemento mas abundante?", // B (Silicio)
"Que es un atomo?", // A (Unidad basica)
"Formula del Dioxido de carbono?", // C (CO2)
"Que gas liberan las plantas durante la fotosintesis", // B (Organizacion)
"pH de solucion neutra?", // A (7)
"Que es un ion?", // B (Atomo cargado)
"Gas noble mas ligero?", // A (Helio)
"Reaccion quimica?", // C (Cambio composicion)
"Elemento mas ligero?", // A (Hidrogeno)
"Que es compuesto quimico?", // B (Sustancia pura)
"Simbolo del oro?", // B (Au)
"Que es catalizador?", // A (Acelera reacciones)
"Formula del amoniaco?", // B (NH3)
"Que es isotopo?", // C (Atomo con neutrones extra)
"Elemento mas reactivo?", // A (Fluor)
"Donde se da enlace covalente?", // B (Entre no metales)
"Formula acido sulfurico?", // C (H2SO4)
"Que es un acido?", // A (Donador protones)
"Simbolo del hierro?", // A (Fe)
"Metal alcalino?", // A (Grupo 1)
"Formula del metano?", // A (CH4)
"Que es polimero?", // B (Macromolecula)
"Elemento mas pesado?", // A (Uranio)
"Enlace ionico?", // C (Entre iones)
"Formula del ozono?", // B (O3)
"Que es gas noble?", // A (Grupo 18)
"Simbolo del sodio?", // A (Na)
"Que es anion?", // B (Ion negativo)
"Formula agua oxigenada?" // A (H2O2)
};
const char* respuestas_quimica[][3] = {
{"A. H2O", "B. CO2", "C. NaCl"},
{"A. Oxigeno", "B. Silicio", "C. Hierro"},
{"A. Unidad basica", "B. Molecula", "C. Compuesto"},
{"A. H2O", "B. O2", "C. CO2"},
{"A. Dioxido de carbono (CO₂)", "B. Oxigeno (O₂)", "C. Nitrogeno (N₂)"},
{"A. 7", "B. 5", "C. 10"},
{"A. Atom neutro", "B. Atom cargado", "C. Molecula"},
{"A. Helio", "B. Neon", "C. Argon"},
{"A. Cambio fisico", "B. Cambio estado", "C. Cambio composicion"},
{"A. Hidrogeno", "B. Helio", "C. Litio"},
{"A. Mezcla", "B. Sust pura", "C. Elemento"},
{"A. Ag", "B. Au", "C. Fe"},
{"A. Acelera", "B. Inhibe", "C. No afecta"},
{"A. NH4", "B. NH3", "C. NO2"},
{"A. Enlace", "B. Molecula", "C. Atom +neutr"},
{"A. Fluor", "B. Sodio", "C. Oro"},
{"A. Entre metales", "B. Entre no metales", "C. Entre iones"},
{"A. H2SO3", "B. H2CO3", "C. H2SO4"},
{"A. Donador H+", "B. Aceptor H+", "C. Neutro"},
{"A. Fe", "B. Au", "C. Ag"},
{"A. Grupo 1", "B. Grupo 2", "C. Grupo 17"},
{"A. CH4", "B. C2H6", "C. C3H8"},
{"A. Ion", "B. Macromolec", "C. Enlace"},
{"A. Uranio", "B. Oro", "C. Plomo"},
{"A. No metales", "B. Metales", "C. Iones"},
{"A. O2", "B. O3", "C. CO2"},
{"A. Grupo 18", "B. Grupo 1", "C. Grupo 2"},
{"A. Na", "B. K", "C. Li"},
{"A. Ion +", "B. Ion -", "C. Atom neutro"},
{"A. H2O2", "B. H2O", "C. HO"}
};
const int respuestas_correctas_quimica[] = {0,1,0,2,1,0,1,0,2,0,1,1,0,1,2,0,1,2,0,0,0,0,1,0,2,1,0,0,1,0};
// Datos de Biología
const char* preguntas_biologia[] = {
"Organelo celular de la respiracion?", // B (Mitocondria)
"Molecula portadora de energia?", // A (ATP)
"Que es el ADN?", // C (Material genetico)
"Funcion de los ribosomas?", // A (Sintesis proteica)
"Tejido que transporta nutrientes?", // B (Floema)
"Organismo unicelular procariota?", // C (Bacteria)
"Proceso de division celular?", // A (Mitosis)
"Hormona del crecimiento vegetal?", // B (Auxina)
"Capa protectora de la piel?", // A (Epidermis)
"Organismo productor en ecologia?", // A (Planta)
"Parte del cerebro para memoria?", // B (Hipocampo)
"Enzima que digiere carbohidratos?", // A (Amilasa)
"Celula reproductora femenina?", // B (Ovulo)
"Proceso de fotosintesis ocurre en?", // C (Cloroplasto)
"Sistema que incluye el corazon?", // A (Circulatorio)
"Grupo sanguineo donante universal?", // B (O negativo)
"Organo filtrador de sangre?", // A (Rinon)
"Vitaminas liposolubles?", // C (A, D, E, K)
"Que son los gametos?", // A
"Hueso mas largo del cuerpo?", // B (Femur)
"Glandula productora de insulina?", // A (Pancreas)
"Proceso de paso de agua por membrana?", // B (Osmosis)
"Estructura que produce polen?", // C (Antera)
"Numero de cromosomas humanos?", // A (46)
"Organismo descomponedor?", // B (Hongo)
"Hormona del estres?", // A (Cortisol)
"Biomolecula formada por aminoacidos?", // C
"Organo del olfato?", // A (Nariz)
"Ciencia que estudia los tejidos?", // B (Histologia)
"Proceso de formacion de gametos?" // A (Gametogenesis)
};
const char* respuestas_biologia[][3] = {
{"A. Nucleo", "B. Mitocondria", "C. Lisosoma"},
{"A. ATP", "B. ADN", "C. ARN"},
{"A. Proteina", "B. Carbohidrato", "C. Material genetico"},
{"A. Sintesis proteica", "B. Produccion ATP", "C. Digestión"},
{"A. Xilema", "B. Floema", "C. Epidermis"},
{"A. Levadura", "B. Alga", "C. Bacteria"},
{"A. Mitosis", "B. Meiosis", "C. Fotosintesis"},
{"A. Giberelina", "B. Auxina", "C. Citocinina"},
{"A. Epidermis", "B. Dermis", "C. Hipodermis"},
{"A. Planta", "B. Hongo", "C. Animal"},
{"A. Cerebelo", "B. Hipocampo", "C. Talamo"},
{"A. Amilasa", "B. Lipasa", "C. Proteasa"},
{"A. Esperma", "B. Ovulo", "C. Zigoto"},
{"A. Mitocondria", "B. Nucleo", "C. Cloroplasto"},
{"A. Circulatorio", "B. Nervioso", "C. Digestivo"},
{"A. AB positivo", "B. O negativo", "C. B positivo"},
{"A. Rinon", "B. Higado", "C. Pulmon"},
{"A. B, C", "B. Complejo B", "C. A, D, E, K"},
{"A. Celula reproductiva", "B. Semillas secas", "C. Parasitos"},
{"A. Tibia", "B. Femur", "C. Humero"},
{"A. Pancreas", "B. Higado", "C. Tiroides"},
{"A. Difusion", "B. Osmosis", "C. Transp activo"},
{"A. Estigma", "B. Estilo", "C. Antera"},
{"A. 46", "B. 23", "C. 48"},
{"A. Bacteria", "B. Hongo", "C. Planta"},
{"A. Cortisol", "B. Adrenalina", "C. Insulina"},
{"A. Carbohidratos", "B. Lipidos", "C. Proteinas"},
{"A. Nariz", "B. Lengua", "C. Oido"},
{"A. Citologia", "B. Histologia", "C. Embriologia"},
{"A. Gametogenesis", "B. Fecundacion", "C. Ovulacion"}
};
const int respuestas_correctas_biologia[] = {1,0,2,0,1,2,0,1,0,0,1,0,1,2,0,1,0,2,0,1,0,1,2,0,1,0,2,0,1,0};
// ========== CONFIGURACIÓN INICIAL ==========
void setup() {
Serial.begin(9600);
// Configurar pines con PULLUP
for(int i = 0; i < 4; i++) {
pinMode(botones[i], INPUT_PULLUP);
}
pinMode(BUZZER, OUTPUT);
pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, HIGH); // Encender backlight (HIGH para encender, LOW para apagar)
randomSeed(analogRead(12));
// Inicializar pantalla ST7789
tft.init(170, 320);
tft.setRotation(3);
tft.invertDisplay(true);
tft.fillScreen(ST77XX_BLACK);
mostrarMenuPrincipal();
}
// ========== BUCLE PRINCIPAL ==========
void loop() {
if (!juegoSeleccionado) {
int opcion = esperarSeleccionMenu();
juegoSeleccionado = true;
juegoActual = opcion + 1;
switch(juegoActual) {
case 1: iniciarJuegoEnteros(); break;
case 2: iniciarJuegoDecimales(); break;
case 3: iniciarQuizQuimica(); break;
case 4: iniciarQuizBiologia(); break;
}
} else {
switch(juegoActual) {
case 1: loopEnteros(); break;
case 2: loopDecimales(); break;
case 3: loopQuizQuimica(); break;
case 4: loopQuizBiologia(); break;
}
}
}
// ========== FUNCIONES DEL MENÚ ==========
void mostrarMenuPrincipal() {
tft.fillScreen(ST77XX_BLACK);
tft.setTextSize(2);
tft.setTextColor(ST77XX_YELLOW); // Título en amarillo
centerText("SELECCIONE JUEGO", 5);
tft.setTextSize(2);
tft.setTextColor(ST77XX_CYAN); // Opciones en cian
tft.setCursor(0, 30);
tft.println("A: Numeros Enteros");
tft.println("B: Numeros Decimales");
tft.println("C: Quiz de Quimica");
tft.println("D: Quiz de Biologia");
}
int esperarSeleccionMenu() {
while(true) {
if (debounce(BUTTON_A)) return 0;
if (debounce(BUTTON_B)) return 1;
if (debounce(BUTTON_C)) return 2;
if (debounce(BUTTON_D)) return 3;
delay(10);
}
}
void reiniciarMenu() {
juegoSeleccionado = false;
juegoActual = 0;
mostrarMenuPrincipal();
}
// ========== FUNCIONES COMUNES ==========
bool debounce(int button) {
static unsigned long lastDebounceTime = 0;
// Cambiado a LOW porque ahora son pull-up (presionado = LOW)
if (digitalRead(button) == LOW && millis() - lastDebounceTime > 200) {
lastDebounceTime = millis();
return true;
}
return false;
}
void centerText(const char *text, int y) {
int16_t x1, y1;
uint16_t w, h;
tft.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
int x = (tft.width() - w) / 2;
tft.setCursor(x, y);
tft.print(text);
}
void playFunTone() {
tone(BUZZER, 1000, 200);
delay(200);
tone(BUZZER, 1500, 200);
delay(200);
tone(BUZZER, 2000, 200);
delay(200);
noTone(BUZZER);
}
void playWrongTone() {
tone(BUZZER, 500, 500);
delay(500);
noTone(BUZZER);
}
// ========== JUEGO DE NÚMEROS ENTEROS ==========
void generarPreguntasEnteros() {
for (int i = 0; i < totalQuestionsEnteros; i++) {
questionsEnteros[i].num1 = random(-10, 10);
questionsEnteros[i].operation = random(0, 4);
if (questionsEnteros[i].operation == 3) {
do {
questionsEnteros[i].num2 = random(-10, 10);
} while (questionsEnteros[i].num2 == 0 || questionsEnteros[i].num1 % questionsEnteros[i].num2 != 0);
} else {
questionsEnteros[i].num2 = random(-10, 10);
}
switch (questionsEnteros[i].operation) {
case 0: questionsEnteros[i].correctAnswer = questionsEnteros[i].num1 + questionsEnteros[i].num2; break;
case 1: questionsEnteros[i].correctAnswer = questionsEnteros[i].num1 - questionsEnteros[i].num2; break;
case 2: questionsEnteros[i].correctAnswer = questionsEnteros[i].num1 * questionsEnteros[i].num2; break;
case 3: questionsEnteros[i].correctAnswer = questionsEnteros[i].num1 / questionsEnteros[i].num2; break;
}
bool answerSet[4] = {false, false, false, false};
for (int j = 0; j < 4; j++) {
if (j == 0) {
questionsEnteros[i].options[j] = questionsEnteros[i].correctAnswer;
answerSet[j] = true;
} else {
int wrongAnswer;
if (j == 1) {
switch (questionsEnteros[i].operation) {
case 0: wrongAnswer = questionsEnteros[i].num1 - questionsEnteros[i].num2; break;
case 1: wrongAnswer = questionsEnteros[i].num1 + questionsEnteros[i].num2; break;
case 2: wrongAnswer = questionsEnteros[i].num1 / questionsEnteros[i].num2; break;
case 3: wrongAnswer = questionsEnteros[i].num1 * questionsEnteros[i].num2; break;
}
} else {
do {
wrongAnswer = random(-20, 20);
} while (wrongAnswer == questionsEnteros[i].correctAnswer);
}
for (int k = 0; k < 4; k++) {
if (!answerSet[k]) {
questionsEnteros[i].options[k] = wrongAnswer;
answerSet[k] = true;
break;
}
}
}
}
for (int j = 3; j > 0; j--) {
int randomIndex = random(0, j + 1);
int temp = questionsEnteros[i].options[j];
questionsEnteros[i].options[j] = questionsEnteros[i].options[randomIndex];
questionsEnteros[i].options[randomIndex] = temp;
}
}
}
void iniciarJuegoEnteros() {
scoreEnteros = 0;
currentQuestionEnteros = 0;
startTimeEnteros = millis();
juegoEnProgresoEnteros = true;
tft.fillScreen(ST77XX_BLACK);
tft.setTextSize(2);
tft.setTextColor(ST77XX_YELLOW);
centerText("Numeros Enteros", 20);
delay(2000);
generarPreguntasEnteros();
displayQuestionEnteros();
}
void loopEnteros() {
if (juegoEnProgresoEnteros) {
if (currentQuestionEnteros < totalQuestionsEnteros) {
if (debounce(BUTTON_A)) {
checkAnswerEnteros(questionsEnteros[currentQuestionEnteros].options[0]);
} else if (debounce(BUTTON_B)) {
checkAnswerEnteros(questionsEnteros[currentQuestionEnteros].options[1]);
} else if (debounce(BUTTON_C)) {
checkAnswerEnteros(questionsEnteros[currentQuestionEnteros].options[2]);
} else if (debounce(BUTTON_D)) {
checkAnswerEnteros(questionsEnteros[currentQuestionEnteros].options[3]);
}
} else {
juegoEnProgresoEnteros = false;
totalTimeEnteros = millis() - startTimeEnteros;
displayFinalScoreEnteros();
}
} else {
if (debounce(BUTTON_A)) {
delay(500);
playFunTone();
reiniciarMenu();
}
}
}
void displayQuestionEnteros() {
tft.fillScreen(ST77XX_BLACK);
// Mostrar "Pregunta X de 10" - Texto blanco tamaño 2 (reducido de 3)
tft.setTextSize(2);
tft.setTextColor(ST77XX_WHITE);
tft.setCursor(0, 10);
tft.print("Pregunta ");
tft.print(currentQuestionEnteros + 1);
tft.print(" de ");
tft.println(totalQuestionsEnteros);
// Operación matemática - Texto amarillo tamaño 3 (reducido de 4)
tft.setTextSize(3);
tft.setTextColor(ST77XX_YELLOW); // Cambiado de ROJO a AMARILLO
tft.setCursor(0, 40);
tft.print(questionsEnteros[currentQuestionEnteros].num1);
tft.print(" ");
tft.print(getOperationSymbol(questionsEnteros[currentQuestionEnteros].operation));
tft.print(" ");
tft.print(questionsEnteros[currentQuestionEnteros].num2);
tft.print(" = ?");
// Opciones de respuesta en dos columnas
tft.setTextSize(3); // Tamaño de fuente para opciones
tft.setTextColor(ST77XX_CYAN);
// Columna izquierda (A y B)
tft.setCursor(0, 90); // Opción A
tft.print("A) ");
tft.print(questionsEnteros[currentQuestionEnteros].options[0]);
tft.setCursor(0, 125); // Opción B
tft.print("B) ");
tft.print(questionsEnteros[currentQuestionEnteros].options[1]);
// Columna derecha (C y D)
tft.setCursor(160, 90); // Opción C (alineada frente a A)
tft.print("C) ");
tft.print(questionsEnteros[currentQuestionEnteros].options[2]);
tft.setCursor(160, 125); // Opción D (alineada frente a B)
tft.print("D) ");
tft.print(questionsEnteros[currentQuestionEnteros].options[3]);
}
char getOperationSymbol(int operation) {
switch (operation) {
case 0: return '+';
case 1: return '-';
case 2: return '*';
case 3: return '/';
default: return '?';
}
}
void checkAnswerEnteros(int selectedAnswer) {
if (selectedAnswer == questionsEnteros[currentQuestionEnteros].correctAnswer) {
tone(BUZZER, 1000, 200);
delay(200);
tone(BUZZER, 1500, 200);
delay(200);
tone(BUZZER, 2000, 200);
delay(200);
scoreEnteros += 0.5;
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST77XX_GREEN);
tft.setTextSize(3);
centerText("CORRECTO", 20);
delay(1000);
} else {
playWrongTone();
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST77XX_RED);
tft.setTextSize(3);
centerText("Incorrecto", 20);
delay(1000);
}
currentQuestionEnteros++;
if (currentQuestionEnteros >= totalQuestionsEnteros) {
juegoEnProgresoEnteros = false;
totalTimeEnteros = millis() - startTimeEnteros;
displayFinalScoreEnteros();
} else {
displayQuestionEnteros();
}
}
void displayFinalScoreEnteros() {
tft.fillScreen(ST77XX_BLACK);
tft.setTextSize(2);
tft.setTextColor(ST77XX_YELLOW);
tft.setCursor(0, 0);
tft.println("Puntuacion final:");
tft.setTextColor(ST77XX_WHITE);
tft.setCursor(0, 30);
tft.print(scoreEnteros);
tft.print(" de ");
tft.print(totalQuestionsEnteros * 0.5);
tft.setCursor(0, 55);
tft.print("Tiempo: ");
tft.print(totalTimeEnteros / 1000);
tft.print(" segundos");
tft.setTextColor(ST77XX_CYAN);
tft.setCursor(0, 85);
tft.println("Oprima boton A");
tft.println("para nueva partida");
}
// ========== JUEGO DE NÚMEROS DECIMALES ==========
void generarPreguntaDecimales() {
num1Decimales = random(1, 100) / 10.0;
num2Decimales = random(1, 100) / 10.0;
resultadoDecimales = num1Decimales + num2Decimales;
respuestaCorrectaDecimales = random(0, 4);
for (int i = 0; i < 4; i++) {
if (i == respuestaCorrectaDecimales) {
dtostrf(resultadoDecimales, 4, 2, opcionesDecimales[i]);
} else {
float incorrecta = resultadoDecimales + (random(-20, 20) / 10.0);
dtostrf(incorrecta, 4, 2, opcionesDecimales[i]);
}
}
}
void iniciarJuegoDecimales() {
puntuacionDecimales = 0;
preguntaActualDecimales = 0;
tiempoInicioDecimales = millis();
midiendoTiempoDecimales = true;
tft.fillScreen(ST77XX_BLACK);
tft.setTextSize(2);
tft.setTextColor(ST77XX_YELLOW);
centerText("Numeros Decimales", 20);
delay(2000);
generarPreguntaDecimales();
mostrarPreguntaConOpcionesDecimales();
}
void loopDecimales() {
if (preguntaActualDecimales < 10) {
if (!midiendoTiempoDecimales) {
tiempoInicioDecimales = millis();
midiendoTiempoDecimales = true;
}
int respuestaElegida = -1;
if (debounce(BUTTON_A)) respuestaElegida = 0;
else if (debounce(BUTTON_B)) respuestaElegida = 1;
else if (debounce(BUTTON_C)) respuestaElegida = 2;
else if (debounce(BUTTON_D)) respuestaElegida = 3;
if (respuestaElegida != -1) {
if (respuestaElegida == respuestaCorrectaDecimales) {
indicarResultadoDecimales(true);
puntuacionDecimales += 0.5;
} else {
indicarResultadoDecimales(false);
}
preguntaActualDecimales++;
if (preguntaActualDecimales < 10) {
generarPreguntaDecimales();
mostrarPreguntaConOpcionesDecimales();
} else {
tiempoFinalDecimales = millis();
midiendoTiempoDecimales = false;
mostrarPuntuacionYTiempoDecimales();
}
}
} else {
if (debounce(BUTTON_A)) {
delay(500);
playFunTone();
reiniciarMenu();
}
}
}
void mostrarPreguntaConOpcionesDecimales() {
tft.fillScreen(ST77XX_BLACK);
// Mostrar "Pregunta X de 10" - Texto blanco tamaño 2
tft.setTextSize(2);
tft.setTextColor(ST77XX_WHITE);
tft.setCursor(0, 10);
tft.print("Pregunta ");
tft.print(preguntaActualDecimales + 1);
tft.print(" de 10");
// Operación matemática - Texto amarillo tamaño 3
tft.setTextSize(3);
tft.setTextColor(ST77XX_YELLOW);
tft.setCursor(0, 40);
tft.print(num1Decimales, 1);
tft.print(" + ");
tft.print(num2Decimales, 1);
tft.print(" = ?");
// Opciones de respuesta en dos columnas
tft.setTextSize(2); // Tamaño de fuente para opciones
tft.setTextColor(ST77XX_CYAN);
// Columna izquierda (A y B)
tft.setCursor(0, 90); // Opción A
tft.print("A. ");
tft.print(opcionesDecimales[0]);
tft.setCursor(0, 125); // Opción B
tft.print("B. ");
tft.print(opcionesDecimales[1]);
// Columna derecha (C y D)
tft.setCursor(160, 90); // Opción C (alineada frente a A)
tft.print("C. ");
tft.print(opcionesDecimales[2]);
tft.setCursor(160, 125); // Opción D (alineada frente a B)
tft.print("D. ");
tft.print(opcionesDecimales[3]);
}
void indicarResultadoDecimales(bool esCorrecta) {
tft.fillScreen(ST77XX_BLACK);
tft.setTextSize(3);
tft.setCursor(0, 20);
if (esCorrecta) {
tft.setTextColor(ST77XX_GREEN);
centerText("CORRECTO", 20);
tone(BUZZER, 1000, 200);
} else {
tft.setTextColor(ST77XX_RED);
centerText("INCORRECTO", 20);
tone(BUZZER, 500, 200);
}
delay(1000);
}
void mostrarPuntuacionYTiempoDecimales() {
tft.fillScreen(ST77XX_BLACK);
tft.setTextSize(2);
tft.setTextColor(ST77XX_YELLOW);
tft.setCursor(0, 0);
tft.print("Puntuacion final: ");
tft.setCursor(0, 25);
tft.setTextSize(3);
tft.setTextColor(ST77XX_CYAN);
tft.print(puntuacionDecimales);
tft.print("/5.0");
unsigned long tiempoTotal = tiempoFinalDecimales - tiempoInicioDecimales;
unsigned long segundos = tiempoTotal / 1000;
unsigned long minutos = segundos / 60;
segundos = segundos % 60;
tft.setTextSize(2);
tft.setTextColor(ST77XX_WHITE);
tft.setCursor(0, 65);
tft.print("Tiempo total: ");
tft.print(minutos);
tft.print(":");
if (segundos < 10) {
tft.print("0");
}
tft.print(segundos);
tft.setTextColor(ST77XX_CYAN);
tft.setCursor(0, 95);
tft.println("Oprima el boton A");
tft.println("para nueva ronda.");
}
// ========== QUIZ DE QUÍMICA ==========
void seleccionarPreguntasAleatorias(const char* preguntas[], int total_preguntas) {
randomSeed(analogRead(12));
for(int i = 0; i < 10; i++) {
bool repetida;
int nueva_pregunta;
do {
repetida = false;
nueva_pregunta = random(total_preguntas);
for(int j = 0; j < i; j++) {
if(preguntas_seleccionadas[j] == nueva_pregunta) {
repetida = true;
break;
}
}
} while(repetida);
preguntas_seleccionadas[i] = nueva_pregunta;
}
}
void iniciarQuizQuimica() {
pregunta_actual = 0;
puntuacion = 0;
seleccionarPreguntasAleatorias(preguntas_quimica, 30);
tft.fillScreen(ST77XX_BLACK);
tft.setTextSize(2);
tft.setTextColor(ST77XX_YELLOW);
centerText("QUIZ DE QUIMICA", 10);
centerText("10 PREGUNTAS", 30);
tft.setTextSize(2);
tft.setTextColor(ST77XX_CYAN);
centerText("Presiona A", 60);
esperarCualquierBoton();
}
void loopQuizQuimica() {
static bool mostradoResultado = false; // Variable para controlar si ya se mostró el resultado
if(pregunta_actual < 10) {
int pregunta_idx = preguntas_seleccionadas[pregunta_actual];
mostrarNumeroPregunta();
delay(800);
mostrarPreguntaCompleta(preguntas_quimica[pregunta_idx], respuestas_quimica, pregunta_idx);
int respuesta = esperarRespuesta();
if(respuesta == 3) return;
verificarRespuesta(respuestas_correctas_quimica[pregunta_idx], respuesta);
pregunta_actual++;
mostradoResultado = false; // Resetear cuando comienza nueva pregunta
}
else if(!mostradoResultado) {
mostrarResultadoFinal();
mostradoResultado = true;
}
else {
if (debounce(BUTTON_A) || debounce(BUTTON_B) || debounce(BUTTON_C) || debounce(BUTTON_D)) {
reiniciarMenu();
}
}
}
// ========== QUIZ DE BIOLOGÍA ==========
void iniciarQuizBiologia() {
pregunta_actual = 0;
puntuacion = 0;
seleccionarPreguntasAleatorias(preguntas_biologia, 30);
tft.fillScreen(ST77XX_BLACK);
tft.setTextSize(2);
tft.setTextColor(ST77XX_YELLOW);
centerText("QUIZ DE BIOLOGIA", 10);
centerText("10 PREGUNTAS", 30);
tft.setTextSize(2);
tft.setTextColor(ST77XX_CYAN);
centerText("Presiona A", 60);
esperarCualquierBoton();
}
void loopQuizBiologia() {
static bool mostradoResultado = false; // Variable para controlar si ya se mostró el resultado
if(pregunta_actual < 10) {
int pregunta_idx = preguntas_seleccionadas[pregunta_actual];
mostrarNumeroPregunta();
delay(800);
mostrarPreguntaCompleta(preguntas_biologia[pregunta_idx], respuestas_biologia, pregunta_idx);
int respuesta = esperarRespuesta();
if(respuesta == 3) return;
verificarRespuesta(respuestas_correctas_biologia[pregunta_idx], respuesta);
pregunta_actual++;
mostradoResultado = false; // Resetear cuando comienza nueva pregunta
}
else if(!mostradoResultado) {
mostrarResultadoFinal();
mostradoResultado = true;
}
else {
if (debounce(BUTTON_A) || debounce(BUTTON_B) || debounce(BUTTON_C) || debounce(BUTTON_D)) {
reiniciarMenu();
}
}
}
// ========== FUNCIONES AUXILIARES PARA QUIZZES ==========
void mostrarNumeroPregunta() {
tft.fillScreen(ST77XX_BLACK);
tft.setTextSize(2);
tft.setTextColor(ST77XX_YELLOW);
centerText("Pregunta", 15);
char texto[20];
sprintf(texto, "%d de 10", pregunta_actual + 1);
tft.setTextColor(ST77XX_WHITE);
centerText(texto, 35);
}
void mostrarPreguntaCompleta(const char* pregunta, const char* opciones[][3], int idx) {
tft.fillScreen(ST77XX_BLACK);
tft.setTextSize(2);
tft.setTextColor(ST77XX_RED);
tft.setCursor(0, 0);
tft.println(pregunta);
tft.println("");
tft.setTextColor(ST77XX_BLUE);
for(int i = 0; i < 3; i++) {
tft.println(opciones[idx][i]);
tft.println("");
}
}
int esperarRespuesta() {
while(true) {
if (debounce(BUTTON_A)) return 0;
if (debounce(BUTTON_B)) return 1;
if (debounce(BUTTON_C)) return 2;
if (debounce(BUTTON_D)) return 3;
delay(10);
}
}
void verificarRespuesta(int respuesta_correcta, int respuesta) {
bool correcta = (respuesta == respuesta_correcta);
tft.fillScreen(ST77XX_BLACK);
tft.setTextSize(2);
tft.setTextColor(correcta ? ST77XX_GREEN : ST77XX_RED);
centerText(correcta ? "CORRECTO!" : "INCORRECTO", 20);
if(correcta) {
puntuacion++;
tone(BUZZER, 1000, 200);
} else {
tone(BUZZER, 300, 500);
}
delay(1000);
}
void mostrarResultadoFinal() {
tft.fillScreen(ST77XX_BLACK);
tft.setTextSize(2);
tft.setTextColor(ST77XX_YELLOW);
centerText("RESULTADO FINAL", 10);
tft.setTextSize(2);
tft.setTextColor(ST77XX_WHITE);
tft.setCursor(0, 40);
tft.print("Puntuacion: ");
tft.setTextColor(ST77XX_YELLOW);
tft.print(puntuacion);
tft.setTextColor(ST77XX_WHITE);
tft.print("/10");
tft.setTextColor(ST77XX_CYAN);
tft.setCursor(0, 80);
centerText("Presione cualquier", 80);
centerText("boton para continuar", 100);
}
void esperarCualquierBoton() {
while(!(debounce(BUTTON_A) || debounce(BUTTON_B) || debounce(BUTTON_C) || debounce(BUTTON_D))) {
delay(10);
}
delay(debounceDelay);
}
Comentarios
Publicar un comentario