Add RLCD animations and screensavers
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
# Standalone MicroPython Voice Animation: Kid Companion Robot
|
||||
# Exposes run(text="", frames=...) and runs automatically if executed directly.
|
||||
import time
|
||||
import math
|
||||
|
||||
try:
|
||||
import board_config
|
||||
display = getattr(board_config, 'display_instance', None)
|
||||
except Exception:
|
||||
board_config = None
|
||||
display = None
|
||||
|
||||
def draw_center_text(d, msg, y, w, scale=1, c=1):
|
||||
char_w = 8 * scale
|
||||
x = max(0, (w - len(msg) * char_w) // 2)
|
||||
if hasattr(d, 'text_large') and scale > 1:
|
||||
try:
|
||||
d.text_large(msg, x, y, scale, c)
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
d.text(msg, x, y, c)
|
||||
|
||||
def run(text="", frames=100):
|
||||
if not display:
|
||||
print("board_config.display_instance is not available. Skipping animation.")
|
||||
return
|
||||
|
||||
width = getattr(display, 'width', 400)
|
||||
height = getattr(display, 'height', 300)
|
||||
cx, cy = width // 2, height // 2
|
||||
|
||||
label = text if text else "HELLO BUDDY!"
|
||||
frame = 0
|
||||
|
||||
try:
|
||||
while True:
|
||||
if frames is not None and frames > 0 and frame >= frames:
|
||||
break
|
||||
|
||||
display.clear(0)
|
||||
|
||||
# Robot head main box
|
||||
head_y = cy - 15
|
||||
display.rect(cx - 50, head_y - 40, 100, 80, 1)
|
||||
display.rect(cx - 49, head_y - 39, 98, 78, 1) # thicker
|
||||
|
||||
# Neck
|
||||
display.fill_rect(cx - 10, head_y + 40, 20, 12, 1)
|
||||
|
||||
# Ears wiggling dynamically using sin waves
|
||||
ear_offset = int(5 * math.sin(frame * 0.25))
|
||||
# Left ear
|
||||
display.rect(cx - 62, head_y - 15 + ear_offset, 12, 30, 1)
|
||||
display.line(cx - 62, head_y + ear_offset, cx - 50, head_y, 1)
|
||||
# Right ear
|
||||
display.rect(cx + 50, head_y - 15 - ear_offset, 12, 30, 1)
|
||||
display.line(cx + 62, head_y - ear_offset, cx + 50, head_y, 1)
|
||||
|
||||
# Antenna extending from head top
|
||||
display.line(cx, head_y - 40, cx, head_y - 58, 1)
|
||||
display.line(cx - 1, head_y - 40, cx - 1, head_y - 58, 1)
|
||||
|
||||
# Antenna bulb winks (flashes)
|
||||
bulb_on = (frame // 4) % 2 == 0
|
||||
if bulb_on:
|
||||
display.fill_rect(cx - 6, head_y - 69, 12, 12, 1)
|
||||
else:
|
||||
display.rect(cx - 6, head_y - 69, 12, 12, 1)
|
||||
|
||||
# Eyes
|
||||
eye_y = head_y - 12
|
||||
# Left Eye (always open, cute square with highlight)
|
||||
display.rect(cx - 32, eye_y - 8, 16, 16, 1)
|
||||
display.fill_rect(cx - 28, eye_y - 4, 8, 8, 1)
|
||||
display.fill_rect(cx - 26, eye_y - 2, 3, 3, 0) # highlight
|
||||
|
||||
# Right Eye winks every 12 frames
|
||||
is_winking = (frame // 10) % 2 == 1
|
||||
if is_winking:
|
||||
# Wink line (happy curved line)
|
||||
display.line(cx + 12, eye_y, cx + 20, eye_y + 4, 1)
|
||||
display.line(cx + 20, eye_y + 4, cx + 28, eye_y, 1)
|
||||
else:
|
||||
# Open right eye
|
||||
display.rect(cx + 16, eye_y - 8, 16, 16, 1)
|
||||
display.fill_rect(cx + 20, eye_y - 4, 8, 8, 1)
|
||||
display.fill_rect(cx + 22, eye_y - 2, 3, 3, 0) # highlight
|
||||
|
||||
# Cute happy smile mouth
|
||||
display.line(cx - 16, head_y + 16, cx + 16, head_y + 16, 1)
|
||||
display.line(cx - 16, head_y + 16, cx - 20, head_y + 10, 1)
|
||||
display.line(cx + 16, head_y + 16, cx + 20, head_y + 10, 1)
|
||||
|
||||
# Draw centered text label at the bottom
|
||||
draw_center_text(display, label, height - 30, width, scale=1, c=1)
|
||||
|
||||
display.show()
|
||||
frame += 1
|
||||
|
||||
try:
|
||||
time.sleep_ms(60)
|
||||
except AttributeError:
|
||||
time.sleep(0.06)
|
||||
except KeyboardInterrupt:
|
||||
print("Animation interrupted by user.")
|
||||
|
||||
if __name__ in ('__main__', '__name__'):
|
||||
run()
|
||||
Reference in New Issue
Block a user