import time
import math
import random
from machine import Pin, I2C, ADC, PWM
import framebuf
from ssd1306 import SSD1306_I2C
# =============================================
# CONFIGURACAO HARDWARE
# =============================================
i2c = I2C(1, scl=Pin(22), sda=Pin(21), freq=400000)
oled = SSD1306_I2C(128, 64, i2c)
servo1 = PWM(Pin(26), freq=50)
servo2 = PWM(Pin(25), freq=50)
buzzer = PWM(Pin(23))
buzzer.duty(0)
R1 = Pin(13, Pin.IN, Pin.PULL_UP)
R2 = Pin(12, Pin.IN, Pin.PULL_UP)
R3 = Pin(14, Pin.IN, Pin.PULL_UP)
R4 = Pin(27, Pin.IN, Pin.PULL_UP)
C1 = Pin(19, Pin.OUT)
C2 = Pin(18, Pin.OUT)
C3 = Pin(5, Pin.OUT)
C4 = Pin(4, Pin.OUT)
C1.value(1); C2.value(1); C3.value(1); C4.value(1)
pot = ADC(Pin(34))
pot.atten(ADC.ATTN_11DB)
pot.width(ADC.WIDTH_12BIT)
pot2 = ADC(Pin(35))
pot2.atten(ADC.ATTN_11DB)
pot2.width(ADC.WIDTH_12BIT)
# =============================================
# ESTADO GLOBAL
# =============================================
mapa_desbloqueado = False
# =============================================
# TECLADO
# =============================================
teclado = [
['1', '2', '3', 'A'],
['4', '5', '6', 'B'],
['7', '8', '9', 'C'],
['*', '0', '#', 'D']
]
def ler_teclado():
tecla_pressionada = None
colunas = [C1, C2, C3, C4]
for col_index, col_pin in enumerate(colunas):
col_pin.value(0)
time.sleep(0.001)
if R1.value() == 0:
tecla_pressionada = teclado[0][col_index]
elif R2.value() == 0:
tecla_pressionada = teclado[1][col_index]
elif R3.value() == 0:
tecla_pressionada = teclado[2][col_index]
elif R4.value() == 0:
tecla_pressionada = teclado[3][col_index]
col_pin.value(1)
if tecla_pressionada is not None:
beep()
time.sleep(0.1)
break
return tecla_pressionada
def limpar_teclas():
while ler_teclado() is not None:
time.sleep(0.05)
def limpar_e_esperar():
limpar_teclas()
time.sleep(0.4)
limpar_teclas()
def apertar_bt_next(bt):
global mapa_desbloqueado
i = 1
tecla = "x"
while tecla != bt:
tecla = ler_teclado()
if tecla == "B" and mapa_desbloqueado:
mostrar_mapa_angulos()
tecla = "x"
if (i // 4) % 2 == 0:
oled.text("{} >".format(bt), 104, 54, 1)
else:
oled.text("{} >".format(bt), 104, 54, 0)
i += 1
oled.show()
time.sleep(0.083)
def aguardar_hash_sem_piscar():
global mapa_desbloqueado
while True:
tecla = ler_teclado()
if tecla == "#":
limpar_e_esperar()
break
elif tecla == "B" and mapa_desbloqueado:
mostrar_mapa_angulos()
time.sleep(0.05)
def aguardar_escolha():
global mapa_desbloqueado
while True:
tecla = ler_teclado()
if tecla in ["1", "2", "3"]:
limpar_e_esperar()
return tecla
elif tecla == "B" and mapa_desbloqueado:
mostrar_mapa_angulos()
time.sleep(0.05)
def coletar_resposta_com_teclado():
global mapa_desbloqueado
resposta = ""
while True:
oled.fill(0)
oled.text("Resposta:", 0, 20)
if resposta:
oled.text(resposta, 0, 35)
else:
oled.text("_", 0, 35)
oled.text("# confirma", 0, 54)
oled.show()
tecla = ler_teclado()
if tecla:
if tecla in '0123456789':
resposta += tecla
elif tecla == '#':
if resposta:
limpar_teclas()
time.sleep(0.3)
limpar_teclas()
break
elif tecla == '*':
if resposta:
resposta = resposta[:-1]
elif tecla == "B" and mapa_desbloqueado:
mostrar_mapa_angulos()
limpar_e_esperar()
time.sleep(0.1)
return resposta
def beep(freq=1000, tempo=0.05):
buzzer.freq(freq)
buzzer.duty(512)
time.sleep(tempo)
buzzer.duty(0)
def som_vitoria():
for freq, tempo in [(523, 0.1), (659, 0.1), (784, 0.2)]:
buzzer.freq(freq); buzzer.duty(512); time.sleep(tempo)
buzzer.duty(0)
def som_errado():
for freq, tempo in [(600, 0.18), (500, 0.18), (400, 0.22), (250, 0.35)]:
buzzer.freq(freq); buzzer.duty(512); time.sleep(tempo)
buzzer.duty(0); time.sleep(0.04)
def som_estatica():
for _ in range(6):
buzzer.freq(random.randint(200, 2000)); buzzer.duty(300); time.sleep(0.04)
buzzer.duty(0); time.sleep(0.02)
def som_tensao():
for _ in range(8):
buzzer.freq(120); buzzer.duty(200); time.sleep(0.12)
buzzer.duty(100); time.sleep(0.08)
buzzer.duty(0)
def som_whatsapp():
notas = [(1047,0.08),(1319,0.08),(1568,0.08),(1319,0.08),
(1568,0.16),(1760,0.08),(1568,0.08),(1319,0.16)]
for freq, tempo in notas:
buzzer.freq(freq); buzzer.duty(400); time.sleep(tempo)
buzzer.duty(0); time.sleep(0.02)
def som_warp():
for freq in range(200, 2000, 80):
buzzer.freq(freq); buzzer.duty(300); time.sleep(0.01)
buzzer.duty(0)
def som_explosao():
for freq in range(800, 100, -60):
buzzer.freq(freq); buzzer.duty(400); time.sleep(0.015)
buzzer.duty(0)
def som_vilao():
for freq, tempo in [(300,0.1),(280,0.1),(260,0.15),(240,0.2),(200,0.3)]:
buzzer.freq(freq); buzzer.duty(300); time.sleep(tempo)
buzzer.duty(0); time.sleep(0.03)
buzzer.duty(0)
# =============================================
# MELODIA IMPERIAL
# =============================================
NOTAS_IMPERIAL = {
'c':261,'d':294,'e':329,'f':349,'g':392,'a':440,'b':493,
'C':523,'D':587,'E':659,'F':698,'G':784,'A':880,'B':987,'p':0
}
MELODIA_IMPERIAL = [
('a',500),('a',500),('a',500),('f',350),('C',150),
('a',500),('f',350),('C',150),('a',1000),
('E',500),('E',500),('E',500),('F',350),('C',150),
('a',500),('f',350),('C',150),('a',1000)
]
# =============================================
# ANIMACOES
# =============================================
def anim_warp():
som_warp(); cx, cy = 64, 32
for r in range(1, 70, 3):
oled.fill(0)
for ang in range(0, 360, 30):
rad = math.radians(ang)
x0 = int(cx+r*0.3*math.cos(rad)); y0 = int(cy+r*0.3*math.sin(rad))
x1 = int(cx+r*math.cos(rad)); y1 = int(cy+r*math.sin(rad))
if 0 <= x1 < 128 and 0 <= y1 < 64: oled.line(x0,y0,x1,y1,1)
oled.show(); time.sleep(0.03)
oled.fill(0); oled.show()
def scroll_star_wars(linhas, delay_scroll=0.10):
altura_display = 64; altura_linha = 10
total_frames = (len(linhas) + 7) * altura_linha
frame = 0
melodia_dupla = MELODIA_IMPERIAL + MELODIA_IMPERIAL
for nota, duracao_ms in melodia_dupla:
freq = NOTAS_IMPERIAL[nota]
if freq == 0: buzzer.duty(0)
else: buzzer.freq(freq); buzzer.duty(400)
frames_nota = max(1, int(duracao_ms / (delay_scroll * 1000)))
for _ in range(frames_nota):
if frame >= total_frames: break
oled.fill(0)
for idx, linha in enumerate(linhas):
y = altura_display - frame + idx * altura_linha
if -10 < y < altura_display:
oled.text(linha, texto_centralizado(linha), y)
oled.show(); time.sleep(delay_scroll); frame += 1
buzzer.duty(0); time.sleep(0.05)
if frame >= total_frames: break
buzzer.duty(0)
while frame < total_frames:
oled.fill(0)
for idx, linha in enumerate(linhas):
y = altura_display - frame + idx * altura_linha
if -10 < y < altura_display:
oled.text(linha, texto_centralizado(linha), y)
oled.show(); time.sleep(delay_scroll); frame += 1
# =============================================
# SERVO
# =============================================
def mover_servo(angulo, servo):
angulo = max(0, min(180, angulo))
duty = int(40 + (angulo / 180) * (115 - 40))
servo.duty(duty)
# =============================================
# QUESTOES
# =============================================
def gerar_questao_cosseno():
hip = random.choice([50, 75, 100, 125, 150])
angulo = random.randint(15, 60)
mover_servo(angulo, servo1); mover_servo(angulo, servo2)
cos_display = round(math.cos(math.radians(angulo)), 2)
return angulo, hip, cos_display, round(hip * cos_display)
def gerar_questao_seno():
hip = random.choice([50, 75, 100, 125, 150])
angulo = random.randint(15, 60)
mover_servo(angulo, servo1); mover_servo(angulo, servo2)
sen_display = round(math.sin(math.radians(angulo)), 2)
return angulo, hip, sen_display, round(hip * sen_display)
def gerar_questao_tangente():
base = random.choice([50, 75, 100, 125, 150])
angulo = random.randint(15, 60)
mover_servo(angulo, servo1); mover_servo(angulo, servo2)
tan_display = round(math.tan(math.radians(angulo)), 2)
return angulo, base, tan_display, round(base * tan_display)
def gerar_questao_central():
tipo = random.randint(1, 3); angulo = random.randint(15, 60)
mover_servo(angulo, servo1); mover_servo(angulo, servo2)
if tipo == 1:
hip = random.choice([50, 75, 100, 125, 150])
cos_v = round(math.cos(math.radians(angulo)), 2)
resp = round(hip * cos_v)
desc = ["Conheco:", "hip={}".format(hip), "ang={}g".format(angulo), "Quero: posicao", "horizontal"]
return tipo,angulo,hip,resp,desc,"2","COSSENO","pos=hip*cos","{}*{}={}".format(hip,cos_v,resp),"cos",cos_v
elif tipo == 2:
hip = random.choice([50, 75, 100, 125, 150])
sen_v = round(math.sin(math.radians(angulo)), 2)
resp = round(hip * sen_v)
desc = ["Conheco:", "hip={}".format(hip), "ang={}g".format(angulo), "Quero:", "altitude"]
return tipo,angulo,hip,resp,desc,"1","SENO","alt=hip*sen","{}*{}={}".format(hip,sen_v,resp),"sen",sen_v
else:
base = random.choice([50, 75, 100, 125, 150])
tan_v = round(math.tan(math.radians(angulo)), 2)
resp = round(base * tan_v)
desc = ["Conheco:", "base={}".format(base), "ang={}g".format(angulo), "Quero:", "altitude"]
return tipo,angulo,base,resp,desc,"3","TANGENTE","alt=base*tan","{}*{}={}".format(base,tan_v,resp),"tan",tan_v
def gerar_questao_angulo():
angulo_real = random.randint(15, 60); tipo = random.randint(1, 3)
if tipo == 1:
hip = random.choice([50, 75, 100, 125, 150])
sen_v = round(math.sin(math.radians(angulo_real)), 2)
lado = round(hip * sen_v)
return angulo_real, ["hip={}".format(hip), "alt={}".format(lado), "sen=alt/hip"], "SEN", round(lado/hip,2)
elif tipo == 2:
hip = random.choice([50, 75, 100, 125, 150])
cos_v = round(math.cos(math.radians(angulo_real)), 2)
lado = round(hip * cos_v)
return angulo_real, ["hip={}".format(hip), "pos={}".format(lado), "cos=pos/hip"], "COS", round(lado/hip,2)
else:
base = random.choice([50, 75, 100, 125, 150])
tan_v = round(math.tan(math.radians(angulo_real)), 2)
lado = round(base * tan_v)
return angulo_real, ["base={}".format(base), "alt={}".format(lado), "tan=alt/base"], "TAN", round(lado/base,2)
# =============================================
# DESENHO
# =============================================
def dlin(x0, y0, x1, y1, cor=1):
dx = abs(x1-x0); dy = -abs(y1-y0)
sx = 1 if x0<x1 else -1; sy = 1 if y0<y1 else -1
err = dx + dy
while True:
oled.pixel(x0, y0, cor)
if x0==x1 and y0==y1: break
e2 = 2*err
if e2 >= dy: err += dy; x0 += sx
if e2 <= dx: err += dx; y0 += sy
def arc_circulo(cx, cy, r, ang):
step = int(ang * 180 / math.pi)
for grau in range(0, step+1):
t = math.radians(grau)
x = int(cx + r*math.cos(t)); y = int(cy - r*math.sin(t))
oled.pixel(x, y, 1)
def arc_circulo_esq(cx, cy, r, ang):
step = int(ang * 180 / math.pi)
for grau in range(0, step+1):
t = math.radians(grau)
x = int(cx - r*math.cos(t)); y = int(cy - r*math.sin(t))
oled.pixel(x, y, 1)
def desenhar_triangulo(cx, cy, escala, ang, modo="cos"):
a = abs(math.radians(ang))
x = int(cx + escala*math.cos(a)); y = int(cy - escala*math.sin(a))
dlin(cx,cy,x,y); dlin(x,y,x,cy); dlin(x,cy,cx,cy)
arc_circulo(cx, cy, escala//3, a)
dlin(x-3,cy,x-3,cy-3); dlin(x-3,cy-3,x,cy-3)
if modo == "cos":
for off in range(3): dlin(cx, cy-off, x, cy-off)
oled.text("h", cx-8, int((cy+y)/2), 1)
oled.text("?", (cx+x)//2, cy+2, 1)
oled.text("v", x+2, int((y+cy)/2), 1)
elif modo == "sen":
for off in range(3): dlin(x+off, y, x+off, cy)
oled.text("h", cx-8, int((cy+y)/2), 1)
oled.text("d", (cx+x)//2, cy+2, 1)
oled.text("?", x+2, int((y+cy)/2), 1)
elif modo == "tan":
for off in range(3): dlin(x+off, y, x+off, cy)
oled.text("?", x+2, int((y+cy)/2), 1)
oled.text("b", (cx+x)//2, cy+2, 1)
def triang_pot(cx, cy, hip, bt="A"):
i = 1
while ler_teclado() != bt:
oled.fill(0)
valor1 = pot.read()
angulo1 = max(0, min(180, int((valor1/4095)*180)))
mover_servo(angulo1, servo1); mover_servo(angulo1, servo2)
a = math.radians(angulo1)
x = int(cx + hip*math.cos(a)); y = int(cy - hip*math.sin(a))
dlin(cx,cy,cx+hip,cy); dlin(x,cy,x,y); dlin(cx,cy,x,y)
arc_circulo(cx, cy, 8, a)
oled.text("ang:{}".format(angulo1), 0, 0)
oled.text("sen:{:.2f}".format(math.sin(a)), 0, 22)
oled.text("cos:{:.2f}".format(math.cos(a)), 0, 32)
if (i//4)%2==0: oled.text("{} >".format(bt), 100, 54, 1)
oled.show(); i += 1; time.sleep(0.03)
# =============================================
# TEXTO
# =============================================
def texto_centralizado(texto, lim_x=128):
return max(0, (lim_x - len(texto)*8) // 2)
def animacao_letra(texto, x, y, delay=0.055):
for char in texto:
oled.text(char, x, y); x += 8
oled.show(); time.sleep(delay)
def tela_texto(linhas, proximo="#"):
oled.fill(0); oled.show()
for idx, linha in enumerate(linhas):
y = idx*10+2; x = texto_centralizado(linha)
for char in linha:
oled.text(char, x, y); x += 8
oled.show(); time.sleep(0.045)
apertar_bt_next(proximo)
limpar_e_esperar()
def tela_blorbe(linhas, proximo="#"):
sprite_vel = 2; contador = 0
oled.fill(0); oled.show()
for idx, linha in enumerate(linhas):
y = idx*10+2; x = max(0, texto_centralizado(linha, 100))
for char in linha:
oled.text(char, x, y); x += 8
oled.framebuf.fill_rect(96, 0, 32, 32, 0)
if (contador//sprite_vel)%2==0:
oled.framebuf.blit(fbblorbe1, 96, 0)
else:
oled.framebuf.blit(fbblorbe2, 96, 0)
oled.show(); time.sleep(0.045); contador += 1
apertar_bt_next(proximo)
limpar_e_esperar()
def tela_tangos(linhas, proximo="#"):
"""Fala do vilao Tangos com sprite 16x16 no canto inferior direito"""
oled.fill(0); oled.show()
for idx, linha in enumerate(linhas):
y = idx*10+2; x = max(0, texto_centralizado(linha, 94))
for char in linha:
oled.text(char, x, y); x += 8
oled.framebuf.fill_rect(110, 46, 18, 18, 0)
oled.framebuf.blit(fbtangos, 110, 47)
oled.show(); time.sleep(0.05)
apertar_bt_next(proximo)
limpar_e_esperar()
def tela_feedback(linhas):
oled.fill(0); oled.show()
for idx, linha in enumerate(linhas):
y = idx*10+2; x = texto_centralizado(linha)
for char in linha:
oled.text(char, x, y); x += 8
oled.show(); time.sleep(0.04)
oled.show(); time.sleep(2)
def tela_radio(linhas, proximo="#"):
som_estatica(); tela_texto(linhas, proximo)
# =============================================
# MAPA DOS ANGULOS NOTAVEIS
# =============================================
def mostrar_mapa_angulos():
oled.fill(0)
oled.text("ANG NOTAVEIS", texto_centralizado("ANG NOTAVEIS"), 0)
oled.line(0, 9, 127, 9, 1)
oled.text(" 30 45 60 90", 0, 12)
oled.text("s:.50 .71 .87 1", 0, 22)
oled.text("c:.87 .71 .50 0", 0, 32)
oled.text("t:.58 1 1.73 x", 0, 42)
oled.text("# voltar", 0, 54)
oled.show()
while True:
t = ler_teclado()
if t == "#":
limpar_e_esperar(); break
time.sleep(0.05)
# =============================================
# SPRITES BLORBE
# =============================================
blorbeab = bytearray([
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x40,0x40,0x20,0x20,
0x20,0x20,0x20,0x40,0x40,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x0c,0x03,0x70,0x9c,0xea,0x6a,0x30,0x20,
0x20,0x20,0x30,0x6a,0xea,0x9c,0x70,0x03,0x0c,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x18,0x3e,0xf1,0x60,0x41,0xc6,0xca,
0xca,0xca,0xc6,0x41,0x60,0xf1,0x3e,0x18,0x06,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,
0x02,0x02,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
])
blorbefec = bytearray([
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x40,0x40,0x20,0x20,
0x20,0x20,0x20,0x40,0x40,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x0c,0x03,0x70,0x9c,0xea,0x6a,0x30,0x20,
0x20,0x20,0x30,0x6a,0xea,0x9c,0x70,0x03,0x0c,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x18,0x3e,0xf1,0x60,0x41,0xc2,0xc2,
0xc2,0xc2,0xc2,0x41,0x60,0xf1,0x3e,0x18,0x06,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x02,
0x02,0x02,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
])
fbblorbe1 = framebuf.FrameBuffer(blorbeab, 32, 32, framebuf.MONO_VLSB)
fbblorbe2 = framebuf.FrameBuffer(blorbefec, 32, 32, framebuf.MONO_VLSB)
# =============================================
# SPRITE TANGOS (extraido do bitmap 128x64)
# =============================================
# =============================================
# SPRITE TANGOS (16x16 villain, canto inferior direito)
# =============================================
# Chapeu pontiagudo, olhos X, capa, corpo de vilao
_tangos_16 = bytearray([
0b00001000, 0b00000000, # ponta do chapeu
0b00011100, 0b00000000, # chapeu
0b00111110, 0b00000000, # aba do chapeu
0b01111111, 0b00000000, # aba larga
0b00111110, 0b00000000, # cabeca topo
0b00100010, 0b00000000, # olhos X X
0b00010100, 0b00000000, # olhos X (cruzado)
0b00100010, 0b00000000, # olhos X
0b00111110, 0b00000000, # rosto/boca
0b01111111, 0b00000000, # ombros/capa
0b00111110, 0b00000000, # corpo
0b00101010, 0b00000000, # capa aberta
0b01001001, 0b00000000, # capa larga
0b00100010, 0b00000000, # pernas
0b00110110, 0b00000000, # botas
0b00000000, 0b00000000,
])
fbtangos = framebuf.FrameBuffer(_tangos_16, 16, 16, framebuf.MONO_HLSB)
# =============================================
# INTRODUCAO COM BLORBE
# =============================================
roteiro = [
"Alo!?","Alguem ai?","Teste...","1...","2...",
"Precisamos","de ajuda!","Calcule","nossa rota","de fuga"
]
def cx_txt_pers(sprite1, sprite2, nome, i=0):
som_whatsapp(); sprite_vel = 2
while i < len(roteiro):
linha_atual = 0; letras = 0
while linha_atual < 5 and i+linha_atual < len(roteiro):
linha = roteiro[i+linha_atual]
if letras < len(linha):
letras += 1
else:
linha_atual += 1; letras = 0; continue
oled.framebuf.fill_rect(4, 20, 121, 40, 0)
for n in range(linha_atual+1):
ln = roteiro[i+n]
mostrar = ln if n < linha_atual else ln[:letras]
y = n*8+20
oled.text(mostrar, texto_centralizado(ln, 110), y)
oled.framebuf.fill_rect(100, 0, 32, 32, 0)
if (letras//sprite_vel)%2==0:
oled.framebuf.blit(sprite1, 100, 0)
else:
oled.framebuf.blit(sprite2, 100, 0)
oled.text(nome, 0, 3, 1)
oled.show(); time.sleep(0.083)
apertar_bt_next("A")
oled.fill(0); i += 5
# =============================================
# FASE TESTE
# =============================================
def fase_teste():
tela_texto(["Antes da","missao,","vamos aprender","a lingua","das estrelas!"])
tela_blorbe(["Imagine uma","lanterna no","espaco..."])
# --- desenho da lanterna ---
tela_blorbe(["Ela aponta","para uma nave","com um angulo."])
tela_blorbe(["A distancia","da nave ate","voce e a","HIPOTENUSA,","o feixe todo."])
tela_blorbe(["Mas voce quer","saber so o","quanto a nave","esta ao lado,","na horizontal."])
tela_blorbe(["Isso e o","COSSENO!","Ele mede o","lado horizontal","do triangulo."])
tela_blorbe(["Angulo pequeno?","A nave esta","quase na sua","frente.","Cos alto!"])
tela_blorbe(["Angulo grande?","A nave desviou","muito pro lado.","Cos menor."])
tela_texto(["Formula:","pos = hip*cos","hip=distancia","cos=tabela","pos=resultado"])
# --- analogia foguete subindo ---
tela_blorbe(["Agora pensa","numa nave","subindo..."])
tela_blorbe(["Ela sobe em","angulo como","um foguete","inclinado."])
tela_blorbe(["A distancia","percorrida e","a HIPOTENUSA,","o caminho","total da nave."])
tela_blorbe(["Mas voce quer","saber so o","quanto ela","SUBIU,","a altitude."])
tela_blorbe(["Isso e o","SENO!","Ele mede o","lado vertical,","a altura."])
tela_blorbe(["Angulo pequeno?","A nave subiu","pouco.","Seno pequeno."])
tela_blorbe(["Angulo grande?","A nave subiu","bastante!","Seno maior!"])
tela_texto(["Formula:","alt = hip*sen","hip=distancia","sen=tabela","alt=resultado"])
# --- interceptacao de radio do Tangos ---
tela_radio(["!! SINAL ESTRANHO","INTERCEPTADO !!"])
som_vilao()
tela_tangos(["Tangos:","Heh...","trigonometria.","Como se isso","fosse me parar."])
tela_blorbe(["Blorbe:","Era o Capitao","Tangos!","O pirata das","tangentes!"])
tela_blorbe(["Ignore ele!","Vamos treinar","com o pot."])
oled.fill(0)
animacao_letra("Gire e veja", texto_centralizado("Gire e veja"), 10)
animacao_letra("sen e cos", texto_centralizado("sen e cos"), 22)
animacao_letra("mudando!", texto_centralizado("mudando!"), 34)
triang_pot(50, 60, 12)
tela_blorbe(["Percebeu?","Sen sobe quando","o angulo sobe.","Cos desce.","Sao opostos!"])
tela_blorbe(["Agora vamos","para a missao","real!","Blorbe precisa","de voce!"])
# =============================================
# TRANSICOES COM POT
# =============================================
def transicao_calibracao():
tela_radio(["Blorbe:","Antes de prosseguir","preciso calibrar","o sensor!","Ajude-me!"])
tela_texto(["Gire o controle","ate o seno","chegar em 0.50.","# para confirmar"])
alvo_sen = 0.50
while True:
oled.fill(0)
valor = pot.read()
ang = max(1, min(179, int((valor/4095)*180)))
mover_servo(ang, servo1); mover_servo(ang, servo2)
a = math.radians(ang); sen_atual = round(math.sin(a), 2)
distancia = abs(sen_atual - alvo_sen)
cx, cy, escala = 90, 62, 25
xa = int(cx + escala*math.cos(a)); ya = int(cy - escala*math.sin(a))
dlin(cx,cy,xa,ya); dlin(xa,ya,xa,cy); dlin(xa,cy,cx,cy)
oled.text("alvo:0.50", 0, 0)
oled.text("sen:{:.2f}".format(sen_atual), 0, 12)
oled.text("ang:{}".format(ang), 0, 24)
if distancia <= 0.03: oled.text("CALIBRADO!", 0, 40)
else: oled.text("ajustando...", 0, 40)
oled.show()
tecla = ler_teclado()
if tecla == "#":
if distancia <= 0.05:
limpar_e_esperar(); som_vitoria()
tela_radio(["Blorbe:","Sensor calibrado!","Seno = 0.50","Angulo ~ 30g","Partindo!"])
break
else:
tela_feedback(["Ainda nao!","Chegue mais","perto de 0.50"])
elif tecla == "B" and mapa_desbloqueado:
mostrar_mapa_angulos()
time.sleep(0.03)
def transicao_decodificador():
tela_radio(["Blorbe:","Sinal criptografado","recebido!","Decodifique","pelo angulo!"])
tela_texto(["Cada valor","de seno esconde","um angulo.","Gire ate","encontrar!"])
angulos = [30, 45, 60]
for i, alvo in enumerate(angulos):
alvo_sen = round(math.sin(math.radians(alvo)), 2)
tela_texto(["Letra {}/3".format(i+1),"Encontre:","sen={:.2f}".format(alvo_sen),"# confirmar"])
while True:
oled.fill(0)
valor = pot.read()
ang = max(1, min(89, int((valor/4095)*90)))
mover_servo(ang, servo1)
a = math.radians(ang); sen_atual = round(math.sin(a), 2)
distancia = abs(sen_atual - alvo_sen)
cx, cy, escala = 90, 62, 25
xa = int(cx + escala*math.cos(a)); ya = int(cy - escala*math.sin(a))
dlin(cx,cy,xa,ya); dlin(xa,ya,xa,cy); dlin(xa,cy,cx,cy)
oled.text("alvo:{:.2f}".format(alvo_sen), 0, 0)
oled.text("sen:{:.2f}".format(sen_atual), 0, 12)
oled.text("letra {}/3".format(i+1), 0, 24)
if distancia <= 0.04: oled.text("ACHOU!", 0, 40)
else: oled.text("buscando...", 0, 40)
oled.show()
tecla = ler_teclado()
if tecla == "#":
if distancia <= 0.06:
limpar_e_esperar(); beep(1400, 0.1)
tela_feedback(["Letra {}/3".format(i+1),"decodificada!","ang={}g".format(alvo)])
break
else:
tela_feedback(["Nao encontrou!","Aproxime mais","do valor alvo"])
elif tecla == "B" and mapa_desbloqueado:
mostrar_mapa_angulos()
time.sleep(0.03)
som_vitoria()
tela_radio(["Mensagem:","\"SOS\"","Decodificada!","Blorbe entende","a rota agora!"])
# =============================================
# FASE 1 - COSSENO (FUGA DE KEPLER)
# =============================================
def fase_cosseno():
global mapa_desbloqueado
scroll_star_wars([
"MISSAO 1","FUGA DE KEPLER","","A nave Blorbe","esta presa","num campo","gravitacional.","","Calcule a","posicao horizontal","usando o COSSENO!","","pos = hip * cos"
])
tela_blorbe(["Blorbe:","Preciso calcular","minha posicao","horizontal","para escapar!"])
tela_blorbe(["O motor aponta","em um angulo.","A distancia","percorrida e","a hipotenusa."])
tela_texto(["FORMULA:","pos = hip * cos","Use a tabela","de cos do","angulo!"])
acertos = 0
while True:
ang, hip, cos_v, resp_certa = gerar_questao_cosseno()
oled.fill(0)
oled.text("hip={}".format(hip), 0, 0)
oled.text("ang={}g".format(ang), 0, 10)
oled.text("cos={}".format(cos_v), 0, 20)
oled.text("pos=hip*cos", 0, 34)
oled.text("# responder", 0, 54)
desenhar_triangulo(50, 62, 30, ang, "cos")
oled.show()
aguardar_hash_sem_piscar()
resposta = coletar_resposta_com_teclado()
try:
resp_num = int(resposta)
if abs(resp_num - resp_certa) <= 1:
som_vitoria(); acertos += 1
if acertos == 1 and not mapa_desbloqueado:
mapa_desbloqueado = True
tela_blorbe(["CORRETO!","Primeiro acerto!","Voce desbloqueou","o MAPA DOS","ANG NOTAVEIS!"])
tela_blorbe(["Pressione B","a qualquer","momento para","consultar","o mapa!"])
# Revelar identidade fundamental
tela_blorbe(["Curiosidade:","sen2+cos2=1","sempre!","Isso e a","ID Fundamental!"])
else:
tela_feedback(["CORRETO!","pos={}".format(resp_certa)])
break
else:
som_errado()
tela_feedback(["Errado!","Era: {}".format(resp_certa),"hip*cos","{}*{}".format(hip,cos_v)])
except:
tela_feedback(["Resposta","invalida!"])
# Tangos aparece
tela_radio(["!! INTERCEPTADO !!"])
som_vilao()
tela_tangos(["Tangos:","Nao deixe ele","descobrir a","identidade","fundamental!"])
tela_blorbe(["Ignorem!","Seguimos em","frente!"])
# =============================================
# FASE 2 - SENO (COLISAO ESTELAR)
# =============================================
def fase_seno():
scroll_star_wars([
"MISSAO 2","COLISAO ESTELAR","","Uma estrela","anao se aproxima!","","Para desviar,","calcule a","altitude de fuga","usando o SENO!","","alt = hip * sen"
])
tela_blorbe(["Blorbe:","Preciso subir","rapidamente!","A altitude","e vital!"])
tela_blorbe(["O motor aponta","em angulo.","A hipotenusa","e o caminho","total percorrido."])
tela_texto(["FORMULA:","alt = hip * sen","O seno mede","o lado vertical","do triangulo!"])
while True:
ang, hip, sen_v, resp_certa = gerar_questao_seno()
oled.fill(0)
oled.text("hip={}".format(hip), 0, 0)
oled.text("ang={}g".format(ang), 0, 10)
oled.text("sen={}".format(sen_v), 0, 20)
oled.text("alt=hip*sen", 0, 34)
oled.text("# responder", 0, 54)
desenhar_triangulo(50, 62, 30, ang, "sen")
oled.show()
aguardar_hash_sem_piscar()
resposta = coletar_resposta_com_teclado()
try:
resp_num = int(resposta)
if abs(resp_num - resp_certa) <= 1:
som_vitoria()
tela_feedback(["CORRETO!","alt={}".format(resp_certa)])
# Identidade complementar
tela_blorbe(["Curiosidade:","sen(x)=cos(90-x)","Sao complementos!","Angulos que somam","90 se trocam!"])
break
else:
som_errado()
tela_feedback(["Errado!","Era: {}".format(resp_certa),"hip*sen","{}*{}".format(hip,sen_v)])
except:
tela_feedback(["Resposta","invalida!"])
tela_radio(["!! INTERCEPTADO !!"])
som_vilao()
tela_tangos(["Tangos:","Impossivel!","Ele conhece a","equivalencia","complementar?!"])
tela_blorbe(["Vamos em","frente!","Proximo desafio!"])
# =============================================
# FASE 3 - TANGENTE (ASTEROIDE ZETA)
# =============================================
def fase_tangente():
scroll_star_wars([
"MISSAO 3","ASTEROIDE ZETA","","Um asteroide","bloqueia a rota!","","Calcule a altura","do obstaculo","usando a","TANGENTE!","","alt = base * tan"
])
tela_blorbe(["Blorbe:","O asteroide","esta a frente!","Preciso saber","sua altura!"])
tela_blorbe(["A base e a","distancia","horizontal","ate o asteroide.","Ja sei isso!"])
tela_blorbe(["A tangente","e o cosseno","e... divisao!","tan=sen/cos","Lado/base!"])
tela_texto(["FORMULA:","alt = base * tan","O tan mede","o lado vertical","sobre o horiz!"])
while True:
ang, base, tan_v, resp_certa = gerar_questao_tangente()
oled.fill(0)
oled.text("base={}".format(base), 0, 0)
oled.text("ang={}g".format(ang), 0, 10)
oled.text("tan={}".format(tan_v), 0, 20)
oled.text("alt=base*tan", 0, 34)
oled.text("# responder", 0, 54)
desenhar_triangulo(50, 62, 30, ang, "tan")
oled.show()
aguardar_hash_sem_piscar()
resposta = coletar_resposta_com_teclado()
try:
resp_num = int(resposta)
if abs(resp_num - resp_certa) <= 1:
som_vitoria()
tela_feedback(["CORRETO!","alt={}".format(resp_certa)])
tela_blorbe(["Curiosidade:","tan=sen/cos","Por isso tan 90g","e infinito!","Cos(90)=0!"])
break
else:
som_errado()
tela_feedback(["Errado!","Era: {}".format(resp_certa),"base*tan","{}*{}".format(base,tan_v)])
except:
tela_feedback(["Resposta","invalida!"])
tela_radio(["!! INTERCEPTADO !!"])
som_vilao()
tela_tangos(["Tangos:","Voces nunca vao","me calcular","em 90 graus!","Hahaha!"])
tela_blorbe(["Sabe o que","acontece com","Tangos em 90g?","Ele explode!","tan(90)=inf!"])
TERNAS = [
(3, 4, 5),
(6, 8, 10),
(5, 12, 13),
(8, 15, 17),
(9, 12, 15),
]
def gerar_questao_pitagoras():
a, b, c = random.choice(TERNAS)
# escala aleatoria para variar os numeros
k = random.choice([1, 2, 3])
a, b, c = a*k, b*k, c*k
tipo = random.randint(1, 3)
if tipo == 1:
# achar hipotenusa
return "HIP", a, b, c, "a={} b={}".format(a,b), "hip=raiz(a2+b2)"
elif tipo == 2:
# achar cateto a
return "CAT", b, c, a, "b={} hip={}".format(b,c), "a=raiz(hip2-b2)"
else:
# achar cateto b
return "CAT", a, c, b, "a={} hip={}".format(a,c), "b=raiz(hip2-a2)"
def fase_pitagoras():
scroll_star_wars([
"MISSAO 2.5","O CODIGO DA NAVE","","Os engenheiros","de Blorbe","usaram um","segredo antigo:","","3 4 5","","O triangulo","mais famoso","do universo!"
])
tela_blorbe(["Blorbe:","Os Egipcios","usavam cordas","com 12 nos","igualmente!"])
tela_blorbe(["Dobravam em","3, 4 e 5","e formavam","90 graus","perfeitos!"])
tela_blorbe(["O casco da","minha nave","usa essa","proporcao!","3-4-5!"])
tela_texto(["PITAGORAS:","a2 + b2 = c2","c = hipotenusa","lado mais","longo!"])
tela_blorbe(["3x3=9","4x4=16","9+16=25","5x5=25","SEMPRE!"])
tela_blorbe(["E se dobrar?","6-8-10","tambem vale!","Qualquer multiplo","funciona!"])
tela_texto(["FORMULA:","hip=raiz(a2+b2)","cat=raiz(hip2-a2)","# para calcular"])
# Tangos tenta atrapalhar
som_vilao()
tela_tangos(["Tangos:","Pitagoras?!","Isso nao me","para! Vou pela","tangente!"])
tela_blorbe(["Ignore ele!","Vamos calcular!"])
acertos = 0
while acertos < 2:
tipo, x, y, resp_certa, enunciado, formula = gerar_questao_pitagoras()
oled.fill(0)
if tipo == "HIP":
oled.text("Ache a hip:", 0, 0)
else:
oled.text("Ache o cateto:", 0, 0)
oled.text(enunciado, 0, 12)
oled.text(formula, 0, 24)
# desenha triangulo retangulo simples
dlin(10, 55, 10, 30, 1)
dlin(10, 55, 50, 55, 1)
dlin(10, 30, 50, 55, 1)
oled.pixel(14, 55, 1); oled.pixel(14, 51, 1); oled.pixel(10, 51, 1)
oled.text("?", 55, 40)
oled.text("B: cola", 0, 44)
oled.text("# responder", 0, 54)
oled.show()
aguardar_hash_sem_piscar()
resposta = coletar_resposta_com_teclado()
try:
resp_num = int(resposta)
if resp_num == resp_certa:
som_vitoria(); acertos += 1
# verifica se e terna 3-4-5
e_terna = any(
sorted([x, y, resp_certa]) == sorted([a*k, b*k, c*k])
for a,b,c in [(3,4,5),(5,12,13),(8,15,17)]
for k in [1,2,3,4,5]
)
if e_terna:
tela_feedback(["CORRETO! ={}".format(resp_certa),"Terna famosa!","Pitagoras","aprovaria!"])
else:
tela_feedback(["CORRETO!","={}".format(resp_certa),"a2+b2=c2","verificado!"])
tela_blorbe(["Curiosidade:","sen2+cos2=1","e Pitagoras","no circulo","de raio 1!"])
else:
som_errado()
tela_feedback(["Errado!","Era: {}".format(resp_certa),formula,"verifique!"])
except:
tela_feedback(["Resposta","invalida!"])
som_vitoria()
tela_blorbe(["Blorbe:","Estrutura da","nave calculada!","Pitagoras nos","guia!"])
som_vilao()
tela_tangos(["Tangos:","Impossivel!","Usaram 3-4-5!","Vou pela","tangente!"])
def fase_central():
scroll_star_wars([
"MISSAO 4","CENTRAL DE COMANDO","","Sistemas criticos","ativados!","","Escolha a formula","certa para cada","situacao!","","1=SEN 2=COS 3=TAN"
])
tela_blorbe(["Blorbe:","A central de","comando!","Aqui uso SEN","COS e TAN!"])
tela_blorbe(["Um acerto","e suficiente","para prosseguir.","Escolha bem!"])
som_tensao()
acertos = 0
tentativas = 0
while acertos < 1:
dados = gerar_questao_central()
tipo,ang,medida,resp_certa,desc,op_certa,nome_op,formula,calc,razao,razao_v = dados
oled.fill(0)
for i, d in enumerate(desc):
oled.text(d, 0, i*10)
oled.text("1=SEN 2=COS", 0, 44)
oled.text("3=TAN", 0, 54)
oled.show()
escolha = aguardar_escolha()
if escolha == op_certa:
som_vitoria(); acertos += 1
tela_feedback(["CORRETO!",nome_op,"{}".format(formula),"={}".format(resp_certa)])
else:
som_errado(); tentativas += 1
tela_feedback(["Errado!","Era: {}".format(nome_op),"{}={}".format(razao,razao_v),"={}".format(resp_certa)])
tela_blorbe(["Central de","comando sob","controle!","Navegando","pela nebulosa!"])
tela_radio(["!! INTERCEPTADO !!"])
som_vilao()
tela_tangos(["Tangos:","Meus drones!","sec! csc! cot!","Ataquem!","AGORA!"])
tela_blorbe(["Sao os inversos!","sec=1/cos","csc=1/sen","cot=1/tan","Ignore-os!"])
# =============================================
# FASE 5 - ANGULO PERDIDO (NEBULOSA DE ORION)
# =============================================
def fase_angulo_perdido():
scroll_star_wars([
"MISSAO 5","NEBULOSA DE ORION","","Os instrumentos","falharam!","","So resta estimar","o angulo pela","razao trigon.","","Qual e o angulo?"
])
tela_blorbe(["Blorbe:","Problema serio!","So tenho os","lados do","triangulo!"])
tela_blorbe(["Preciso achar","o angulo pelo","valor da razao.","Estimativa","de +-5 graus!"])
tela_texto(["LOGICA:","Se sen=0.50","entao ang~30g","Se cos=0.87","entao ang~30g"])
acertos = 0
while acertos < 1:
ang_real, pistas, razao_nome, razao_val = gerar_questao_angulo()
oled.fill(0)
oled.text("{}={}".format(razao_nome, razao_val), 0, 0)
for i, p in enumerate(pistas):
oled.text(p, 0, 12+i*10)
oled.text("Qual angulo? (g)", 0, 44)
oled.text("# responder", 0, 54)
aguardar_hash_sem_piscar()
resposta = coletar_resposta_com_teclado()
try:
resp_num = int(resposta)
if abs(resp_num - ang_real) <= 5:
som_vitoria(); acertos += 1
tela_feedback(["CORRETO!","Era {}g".format(ang_real),"Estimativa OK!"])
else:
som_errado()
tela_feedback(["Errado!","Era ~{}g".format(ang_real),"Tente usar","a tabela!"])
except:
tela_feedback(["Resposta","invalida!"])
tela_blorbe(["Blorbe:","Angulo calculado!","Rota tracada!","Vamos escapar","de Tangos!"])
tela_radio(["!! INTERCEPTADO !!"])
som_vilao()
tela_tangos(["Tangos:","Voce...","Eu vou atacar","em 90 graus!","Prepare-se!"])
tela_blorbe(["Espera...","90 graus?!","tan(90) = ERRO!","Ele se","destruiu!"])
tela_blorbe(["Tangos se","dividiu por","zero!","A trigonometria","nos salvou!"])
# =============================================
# TELA FINAL
# =============================================
def tela_final():
scroll_star_wars([
"MISSAO CONCLUIDA","","Blorbe escapou!","","Voce dominou:","SEN COS TAN","","As razoes","trigonometricas","sao a linguagem","do universo!","","Parabens!","PILOTO TRIGON."
])
oled.fill(0)
oled.text("PARABENS!", texto_centralizado("PARABENS!"), 10)
oled.text("Piloto:", texto_centralizado("Piloto:"), 25)
oled.text("Trigonometrico!", texto_centralizado("Trigonometrico!"), 35)
oled.text("SEN COS TAN", texto_centralizado("SEN COS TAN"), 50)
oled.show(); som_vitoria(); time.sleep(3)
ATAQUES_TANGOS = [
{
'tipo': 'RETANGULO',
'tecla': '1',
'fala': ["Tangos:","Raio ALPHA!","Um angulo","de 90 graus!","Qual escudo?"],
'dica': ["1 angulo reto","de 90 graus!","Como esquina","de predio!","Tecle 1!"],
'pts': [(20,55),(20,20),(60,55)],
'reta': True,
},
{
'tipo': 'ISOSCELES',
'tecla': '2',
'fala': ["Tangos:","Raio BETA!","Dois lados","IGUAIS!","Qual escudo?"],
'dica': ["2 lados iguais","1 base dif.","Como tenda","de acampamento!","Tecle 2!"],
'pts': [(18,55),(50,12),(82,55)],
'reta': False,
},
{
'tipo': 'EQUILATERO',
'tecla': '3',
'fala': ["Tangos:","Raio GAMA!","3 lados","PERFEITOS!","Qual escudo?"],
'dica': ["3 lados iguais","3 angulos","de 60 graus","cada um!","Tecle 3!"],
'pts': [(18,55),(50,10),(82,55)],
'reta': False,
},
{
'tipo': 'ESCALENO',
'tecla': '4',
'fala': ["Tangos:","Raio DELTA!","Todos lados","DIFERENTES!","Qual escudo?"],
'dica': ["Todos lados","diferentes!","Todos angulos","diferentes!","Tecle 4!"],
'pts': [(15,55),(35,18),(85,55)],
'reta': False,
},
]
def som_ataque_escudo():
for f in [150,200,300,400,600]:
buzzer.freq(f); buzzer.duty(400); time.sleep(0.04)
buzzer.duty(0)
def som_escudo_ok():
for f in [600,800,1000,1200,1400]:
buzzer.freq(f); buzzer.duty(512); time.sleep(0.06)
buzzer.duty(0)
def som_dano_nave():
for f in [400,300,200,150,100]:
buzzer.freq(f); buzzer.duty(512); time.sleep(0.09)
buzzer.duty(0); time.sleep(0.02)
def desenhar_tri_escudo(pts, reta=False):
dlin(pts[0][0],pts[0][1],pts[1][0],pts[1][1])
dlin(pts[1][0],pts[1][1],pts[2][0],pts[2][1])
dlin(pts[2][0],pts[2][1],pts[0][0],pts[0][1])
if reta:
mx,my = pts[0]
oled.pixel(mx+5,my,1); oled.pixel(mx+5,my-5,1); oled.pixel(mx,my-5,1)
def menu_escudos_lateral():
dlin(94,0,94,63)
oled.text("1:RET",96,0)
oled.text("2:ISO",96,13)
oled.text("3:EQU",96,26)
oled.text("4:ESC",96,39)
def fase_escudos():
# --- scroll de introducao ---
scroll_star_wars([
"MISSAO 0","ESCUDOS DA NAVE","","Tangos ataca","com raios","triangulares!","","Cada raio tem","uma forma.","O escudo certo","bloqueia tudo!","","Aprenda os tipos!"
])
# --- tutorial cada tipo ---
tela_blorbe(["Blorbe:","Tangos esta","atacando!","Preciso dos","escudos certos!"])
# Retangulo
tela_texto(["ESCUDO 1:","RETANGULO","1 angulo de","90 graus.","Como esquina!"])
oled.fill(0)
desenhar_tri_escudo([(20,55),(20,20),(60,55)], reta=True)
oled.text("RETANGULO",0,0); oled.text("ang=90",65,30)
oled.text("no canto",65,40); oled.text("# ok",80,54)
oled.show(); apertar_bt_next("#"); limpar_e_esperar()
# Isosceles
tela_texto(["ESCUDO 2:","ISOSCELES","2 lados iguais","1 base diferente","Como tenda!"])
oled.fill(0)
desenhar_tri_escudo([(18,55),(50,12),(82,55)])
oled.text("ISOSCELES",0,0); oled.text("2 lados",0,44)
oled.text("iguais",0,54); oled.text("# ok",80,54)
oled.show(); apertar_bt_next("#"); limpar_e_esperar()
# Equilatero
tela_texto(["ESCUDO 3:","EQUILATERO","3 lados iguais","3 angulos","de 60 graus!"])
oled.fill(0)
desenhar_tri_escudo([(18,55),(50,10),(82,55)])
oled.text("EQUILATERO",0,0); oled.text("3x60g",0,44)
oled.text("# ok",80,54)
oled.show(); apertar_bt_next("#"); limpar_e_esperar()
# Escaleno
tela_texto(["ESCUDO 4:","ESCALENO","Todos lados","diferentes!","Todos ang. dif!"])
oled.fill(0)
desenhar_tri_escudo([(15,55),(35,18),(85,55)])
oled.text("ESCALENO",0,0); oled.text("tudo",0,44)
oled.text("diferente",0,54); oled.text("# ok",80,54)
oled.show(); apertar_bt_next("#"); limpar_e_esperar()
# Resumo
tela_texto(["RESUMO:","1=RET ang90","2=ISO 2lad=","3=EQU 3lad=","4=ESC tudo dif"])
# Tangos anuncia ataque
som_vilao()
tela_tangos(["Tangos:","Ha ha ha!","Meus raios","vem ai!","Prepare-se!"])
# --- batalha ---
ordem = list(range(len(ATAQUES_TANGOS)))
for i in range(len(ordem)-1, 0, -1):
j = random.randint(0, i)
ordem[i], ordem[j] = ordem[j], ordem[i]
vida = 3
acertos = 0
for idx in ordem:
atq = ATAQUES_TANGOS[idx]
pts = atq['pts']
tecla_certa = atq['tecla']
tipo_certo = atq['tipo']
# Tangos fala
som_ataque_escudo()
tela_tangos(atq['fala'])
limpar_e_esperar()
# Loop de resposta
respondido = False
frame = 0
while not respondido:
oled.fill(0)
desenhar_tri_escudo(pts, reta=atq['reta'])
menu_escudos_lateral()
oled.text("V:{}".format("*"*vida), 0, 54)
if (frame//6)%2==0: oled.text("!ATIVE!", 20, 0)
oled.show(); frame += 1
tecla = ler_teclado()
if tecla in ["1","2","3","4"]:
respondido = True
if tecla == tecla_certa:
# acerto
som_escudo_ok(); acertos += 1
oled.fill(0)
oled.text("ESCUDO",20,8)
oled.text("ATIVADO!",16,20)
oled.text(tipo_certo,texto_centralizado(tipo_certo),34)
oled.text("BLOQUEOU!",16,46)
oled.show(); time.sleep(1)
som_vilao()
tela_tangos(["Tangos:","Argh!","Esse escudo!","Vou pela","tangente!"])
else:
# erro
vida -= 1
som_dano_nave()
tipo_errado = ["RET","ISO","EQU","ESC"][int(tecla)-1]
oled.fill(0)
oled.text("ESCUDO ERRADO!",0,0)
oled.text("Era:"+tipo_certo[:7],0,12)
for n,l in enumerate(atq['dica'][:3]):
oled.text(l,0,24+n*10)
oled.text("V:{}".format("*"*vida if vida>0 else "---"),0,54)
oled.show(); time.sleep(2.5)
if vida <= 0:
som_errado()
tela_tangos(["Tangos:","Nave destruida!","Ha ha ha!","Vou pela","tangente!"])
fase_escudos(); return
time.sleep(0.05)
# --- vitoria ---
som_vitoria()
oled.fill(0)
oled.text("NAVE SALVA!",10,0)
oled.text("{}/{} bloq.".format(acertos,len(ATAQUES_TANGOS)),10,14)
if acertos == len(ATAQUES_TANGOS):
oled.text("PERFEITO!",20,28)
oled.text("Tangos fugiu",10,40)
oled.text("pela tangente!",0,52)
else:
oled.text("Sobrevivemos!",0,28)
oled.text("Vida:{}".format("*"*vida),10,42)
oled.show(); som_vitoria(); time.sleep(1); som_vitoria(); time.sleep(2)
tela_blorbe(["Blorbe:","Tangos fugiu","de novo...","pela tangente","como sempre!"])
def main():
oled.fill(0); oled.show()
cx_txt_pers(fbblorbe1, fbblorbe2, "Blorbe:")
fase_teste()
fase_escudos()
fase_cosseno()
transicao_calibracao()
fase_seno()
fase_tangente()
fase_pitagoras()
fase_central()
transicao_decodificador()
fase_angulo_perdido()
tela_final()
main()