from machine import Pin, I2C
import ssd1306
import time
# Configuración de I2C para ESP32
i2c = I2C(0, scl=Pin(22), sda=Pin(21)) # Configuración de los pines I2C del ESP32
ancho_oled = 128 # Ancho de la pantalla OLED
alto_oled = 64 # Altura de la pantalla OLED
oled = ssd1306.SSD1306_I2C(ancho_oled, alto_oled, i2c) # Inicialización del objeto OLED
# Configuración del botón
boton = Pin(9, Pin.IN, Pin.PULL_UP) # Botón conectado al pin GPIO09 con resistencia pull-up
# Carácter personalizado 16x16 píxeles dividido en 4 bloques de 8x8
bloques_caracter_personalizado = [
[ # Bloque superior izquierdo
0b01111111,
0b01111111,
0b00000011,
0b00001111,
0b00011111,
0b00110001,
0b00110001,
0b00110001,
],
[ # Bloque superior derecho
0b11111110,
0b11111110,
0b11000000,
0b11110000,
0b11111000,
0b10001100,
0b10001100,
0b10001100,
],
[ # Bloque inferior izquierdo
0b00110001,
0b00110001,
0b00110001,
0b00011111,
0b00001111,
0b00000011,
0b01111111,
0b01111111,
],
[ # Bloque inferior derecho
0b10001100,
0b10001100,
0b10001100,
0b11111000,
0b11110000,
0b11000000,
0b11111110,
0b11111110,
]
]
def dibujar_caracter_personalizado(x, y, bloques_caracter):
"""Dibuja un carácter personalizado de 16x16 píxeles en la posición x, y."""
for fila_bloque in range(2): # Dos filas de bloques (superior e inferior)
for col_bloque in range(2): # Dos columnas de bloques (izquierda y derecha)
for fila, byte in enumerate(bloques_caracter[fila_bloque * 2 + col_bloque]):
for col in range(8): # 8 píxeles de ancho por bloque
if byte & (1 << (7 - col)): # Verifica si el bit está encendido
oled.pixel(x + col + (col_bloque * 8), y + fila + (fila_bloque * 8), 1) # Dibuja el píxel
def borrar_caracter_personalizado(x, y, ancho, alto):
"""Borra un área rectangular donde estaba el carácter."""
for fila in range(alto):
for col in range(ancho):
oled.pixel(x + col, y + fila, 0) # Limpia los píxeles del área
def actualizar_puntaje(puntaje):
"""Actualiza el puntaje en la pantalla OLED."""
oled.text(" ", 70, 0) # Borra el texto anterior en la posición del marcador
oled.text(f"Score:{puntaje}", 70, 0) # Muestra el nuevo puntaje
def verificar_colision(x_jugador, y_jugador, x_obstaculo, y_obstaculo):
"""Verifica si hay una colisión entre el jugador y el obstáculo."""
return (abs(x_jugador - x_obstaculo) < 10) and (y_jugador == y_obstaculo)
def esperar_reinicio():
"""Espera a que se presione el botón para reiniciar el juego."""
while True:
if boton.value() == 0: # Botón presionado
oled.fill(0) # Limpia la pantalla
oled.show()
reiniciar_variables() # Reinicia las variables globales
main() # Reinicia todo el juego
def fin_del_juego():
"""Muestra el mensaje de 'Game Over' y espera reinicio."""
oled.fill(0)
oled.text("Game Over!", 20, 20) # Mensaje de juego terminado
oled.text(f"Score: {puntaje}", 20, 40) # Muestra el puntaje final
oled.show()
esperar_reinicio() # Espera a que el jugador reinicie
def ganaste():
"""Muestra el mensaje de 'You Win' y espera reinicio."""
oled.fill(0)
oled.text("You WIN!", 30, 30) # Mensaje de victoria
oled.show()
esperar_reinicio()
def reiniciar_variables():
"""Reinicia todas las variables globales del juego."""
global posicion_jugador, y_jugador, posicion_obstaculo, esta_saltando, fase_salto, puntaje, velocidad_juego
posicion_jugador = 2
y_jugador = 40
posicion_obstaculo = 120
esta_saltando = False
fase_salto = 0
puntaje = 0
velocidad_juego = 150 # Reinicia la velocidad inicial
def primer_codigo():
"""Ejecuta la animación inicial del primer código."""
oled.text("Hola Mundo", 30, 10) # Muestra el mensaje inicial
oled.show()
tiempo_ultima_animacion = time.ticks_ms()
intervalo_animacion = 300 # Intervalo de 300 ms entre animaciones
posicion = 0
while True:
tiempo_actual = time.ticks_ms()
# Controlar animación del carácter
if time.ticks_diff(tiempo_actual, tiempo_ultima_animacion) > intervalo_animacion:
borrar_caracter_personalizado(posicion, 40, 16, 16) # Borra el carácter anterior
posicion = (posicion + 16) % ancho_oled # Mueve el carácter a la siguiente posición
dibujar_caracter_personalizado(posicion, 40, bloques_caracter_personalizado) # Dibuja el carácter
oled.show()
tiempo_ultima_animacion = tiempo_actual
# Verificar si el botón fue presionado para saltar al segundo código
if boton.value() == 0: # Botón presionado
oled.fill(0)
oled.show()
segundo_codigo()
# Variables del segundo código
posicion_jugador = 2
y_jugador = 40 # Posición inicial del jugador (en el suelo)
posicion_obstaculo = 120
esta_saltando = False
fase_salto = 0 # Fase del salto: 0 = suelo, 1 = subida, 2 = aire, 3 = bajada
puntaje = 0
velocidad_juego = 150 # Velocidad inicial del juego en ms
zona_segura = 10 # Margen adicional de seguridad para colisiones
# Caracteres personalizados para el jugador y el obstáculo
caracter_jugador_suelo = [
0b00100,
0b01110,
0b00100,
0b11111,
0b00100,
0b01110,
0b01010,
0b01010
] # Representa al jugador en el suelo
caracter_jugador_salto = [
0b00100,
0b01110,
0b00101,
0b11111,
0b10100,
0b00111,
0b11101,
0b00001
] # Representa al jugador saltando
caracter_obstaculo = [
0b00001,
0b10010,
0b10100,
0b01110,
0b01110,
0b00101,
0b01001,
0b10000
] # Representa el obstáculo
def caracter_personalizado(x, y, datos_caracter, escala=2):
"""Dibuja un carácter personalizado escalado según la escala proporcionada."""
for fila, datos in enumerate(datos_caracter):
for col in range(5):
if datos & (1 << (4 - col)): # Verifica si el bit está encendido
for sx in range(escala):
for sy in range(escala):
oled.pixel(x + col * escala + sx, y + fila * escala + sy, 1)
def dibujar_jugador(x, y, saltando):
"""Dibuja al jugador, cambiando su estado según si está saltando o en el suelo."""
if saltando:
caracter_personalizado(x, y, caracter_jugador_salto, escala=2)
else:
caracter_personalizado(x, y, caracter_jugador_suelo, escala=2)
def dibujar_obstaculo(x, y):
"""Dibuja el obstáculo en la pantalla OLED."""
caracter_personalizado(x, y, caracter_obstaculo, escala=2)
def borrar_area(x, y, ancho=10, alto=16):
"""Borra manualmente un área rectangular escalada en la pantalla OLED."""
for fila in range(alto):
for col in range(ancho):
oled.pixel(x + col, y + fila, 0)
def segundo_codigo():
"""Ejecuta la lógica principal del juego."""
global y_jugador, posicion_obstaculo, esta_saltando, fase_salto, puntaje, velocidad_juego
oled.fill(0)
oled.text("Score: 0", 70, 0) # Muestra el puntaje inicial
oled.show()
tiempo_ultima_actualizacion = time.ticks_ms()
intervalo_obstaculo = 100 # Intervalo para mover el obstáculo
while True:
tiempo_actual = time.ticks_ms()
# Leer el estado del botón
if boton.value() == 0 and not esta_saltando: # Botón presionado
esta_saltando = True
fase_salto = 1 # Iniciar fase de subida
# Manejar el salto
if esta_saltando:
if fase_salto == 1: # Subida inicial
y_jugador = 22
fase_salto = 2
elif fase_salto == 2: # En el aire
y_jugador = 20
fase_salto = 3
elif fase_salto == 3: # Bajada intermedia
y_jugador = 22
fase_salto = 4
elif fase_salto == 4: # Regresar al suelo
y_jugador = 40
esta_saltando = False
# Actualizar obstáculo y escenario
if time.ticks_diff(tiempo_actual, tiempo_ultima_actualizacion) > intervalo_obstaculo:
borrar_area(posicion_obstaculo, 40)
posicion_obstaculo -= 8
if posicion_obstaculo < 0:
posicion_obstaculo = 120
puntaje += 1
actualizar_puntaje(puntaje) # Actualiza el puntaje
if velocidad_juego > 50:
velocidad_juego -= 10 # Incrementa la velocidad del juego
# Dibujar escenario
oled.fill(0)
dibujar_obstaculo(posicion_obstaculo, 40)
dibujar_jugador(posicion_jugador, y_jugador, esta_saltando)
actualizar_puntaje(puntaje)
oled.show()
tiempo_ultima_actualizacion = tiempo_actual
# Verificar colisión
if verificar_colision(posicion_jugador, y_jugador, posicion_obstaculo, 40):
fin_del_juego()
# Verificar si el jugador gana
if puntaje == 10:
ganaste()
def main():
"""Función principal del programa."""
primer_codigo()
if __name__ == "__main__":
main()