import time
import random
from machine import Pin, I2C
# ==========================================
# DRIVER SIMPLIFICADO SSD1306 (Pantalla OLED)
# ==========================================
class SSD1306_I2C:
def __init__(self, width, height, i2c, addr=0x3c):
self.width = width
self.height = height
self.i2c = i2c
self.addr = addr
self.buffer = bytearray((height // 8) * width)
self.init_display()
def write_cmd(self, cmd):
self.i2c.writeto(self.addr, bytearray([0x00, cmd]))
def init_display(self):
for cmd in (0xAE, 0x20, 0x00, 0x40, 0xA1, 0xC8, 0xDA, 0x12, 0x81, 0xCF, 0xD9, 0xF1, 0xDB, 0x30, 0xA4, 0xA6, 0xAF):
self.write_cmd(cmd)
def show(self):
self.write_cmd(0x21)
self.write_cmd(0)
self.write_cmd(self.width - 1)
self.write_cmd(0x22)
self.write_cmd(0)
self.write_cmd((self.height // 8) - 1)
self.i2c.writeto(self.addr, b'\x40' + self.buffer)
def fill(self, col):
val = 0xFF if col else 0x00
for i in range(len(self.buffer)):
self.buffer[i] = val
def pixel(self, x, y, col):
if 0 <= x < self.width and 0 <= y < self.height:
index = x + (y // 8) * self.width
if col:
self.buffer[index] |= (1 << (y % 8))
else:
self.buffer[index] &= ~(1 << (y % 8))
def hline(self, x, y, w, col):
for i in range(x, x + w):
self.pixel(i, y, col)
def fill_rect(self, x, y, w, h, col):
for i in range(x, x + w):
for j in range(y, y + h):
self.pixel(i, j, col)
def text(self, string, x, y, col=1):
# Renderizado básico de texto
for char in string:
for i in range(5):
self.pixel(x + i, y, col)
x += 8
# ==========================================
# CONFIGURACIÓN DE HARDWARE
# ==========================================
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
oled = SSD1306_I2C(128, 64, i2c)
# Botón para saltar / reiniciar (GP14)
btn_jump = Pin(14, Pin.IN, Pin.PULL_UP)
# ==========================================
# VARIABLES Y LÓGICA DEL JUEGO
# ==========================================
def reset_game():
global player_x, player_y, player_size, is_jumping, jump_count, jump_max
global obstacle_x, obstacle_w, obstacle_h, obstacle_speed, score, game_over
player_x = 10
player_y = 50
player_size = 6
is_jumping = False
jump_count = 0
jump_max = 18
obstacle_x = 128
obstacle_w = 5
obstacle_h = 10
obstacle_speed = 3
score = 0
game_over = False
reset_game()
def draw():
oled.fill(0)
# Suelo
oled.hline(0, 56, 128, 1)
# Jugador
oled.fill_rect(player_x, int(player_y), player_size, player_size, 1)
# Obstáculo
oled.fill_rect(int(obstacle_x), 56 - obstacle_h, obstacle_w, obstacle_h, 1)
# Puntaje
oled.text(f"P: {score}", 0, 0)
if game_over:
oled.text("GAME OVER", 28, 20)
oled.text("BTN: Rejugar", 10, 38)
oled.show()
# ==========================================
# BUCLE PRINCIPAL
# ==========================================
while True:
if not game_over:
# Detectar salto
if btn_jump.value() == 0 and not is_jumping:
is_jumping = True
jump_count = jump_max
# Lógica de salto
if is_jumping:
if jump_count >= -jump_max:
player_y -= jump_count * 0.4
jump_count -= 2
else:
is_jumping = False
player_y = 50
# Mover obstáculo
obstacle_x -= obstacle_speed
if obstacle_x < -obstacle_w:
obstacle_x = 128
score += 1
obstacle_speed = min(8, 3 + score // 5)
# Colisiones
if (obstacle_x < player_x + player_size and
obstacle_x + obstacle_w > player_x and
player_y + player_size > 56 - obstacle_h):
game_over = True
draw()
time.sleep(0.03)
else:
draw()
# Presionar botón para volver a jugar tras perder
if btn_jump.value() == 0:
reset_game()
time.sleep(0.3) # Anti-rebote
time.sleep(0.05)Loading
ssd1306
ssd1306