pimoroni-pico/micropython/examples/galactic_unicorn/lava_lamp.py

152 wiersze
3.9 KiB
Python

import time
import random
import math
from galactic import GalacticUnicorn
from picographics import PicoGraphics, DISPLAY_GALACTIC_UNICORN as DISPLAY
'''
A 70s-tastic, procedural rainbow lava lamp.
You can adjust the brightness with LUX + and -.
'''
gu = GalacticUnicorn()
graphics = PicoGraphics(DISPLAY)
blob_count = 10
class Blob():
def __init__(self):
self.x = float(random.randint(0, width - 1))
self.y = float(random.randint(0, height - 1))
self.r = (float(random.randint(0, 40)) / 10.0) + 5.0
self.dx = (float(random.randint(0, 2)) / 10.0) - 0.1
self.dy = (float(random.randint(0, 2)) / 10.0) - 0.05 # positive bias
@micropython.native # noqa: F821
def setup_portrait():
global width, height, liquid, blobs
width = GalacticUnicorn.HEIGHT
height = GalacticUnicorn.WIDTH
liquid = [[0.0 for y in range(height)] for x in range(width)]
blobs = [Blob() for i in range(blob_count)]
hue = 0.0
@micropython.native # noqa: F821
def from_hsv(h, s, v):
i = math.floor(h * 6.0)
f = h * 6.0 - i
v *= 255.0
p = v * (1.0 - s)
q = v * (1.0 - f * s)
t = v * (1.0 - (1.0 - f) * s)
i = int(i) % 6
if i == 0:
return graphics.create_pen(int(v), int(t), int(p))
if i == 1:
return graphics.create_pen(int(q), int(v), int(p))
if i == 2:
return graphics.create_pen(int(p), int(v), int(t))
if i == 3:
return graphics.create_pen(int(p), int(q), int(v))
if i == 4:
return graphics.create_pen(int(t), int(p), int(v))
if i == 5:
return graphics.create_pen(int(v), int(p), int(q))
@micropython.native # noqa: F821
def update_liquid():
for y in range(height):
for x in range(width):
liquid[x][y] = 0.0
for blob in blobs:
r_sq = blob.r * blob.r
blob_y_range = range(max(math.floor(blob.y - blob.r), 0),
min(math.ceil(blob.y + blob.r), height))
blob_x_range = range(max(math.floor(blob.x - blob.r), 0),
min(math.ceil(blob.x + blob.r), width))
for y in blob_y_range:
for x in blob_x_range:
x_diff = x - blob.x
y_diff = y - blob.y
d_sq = x_diff * x_diff + y_diff * y_diff
if d_sq <= r_sq:
liquid[x][y] += 1.0 - (d_sq / r_sq)
@micropython.native # noqa: F821
def move_blobs():
for blob in blobs:
blob.x += blob.dx
blob.y += blob.dy
if blob.x < 0.0 or blob.x >= float(width):
blob.dx = 0.0 - blob.dx
if blob.y < 0.0 or blob.y >= float(height):
blob.dy = 0.0 - blob.dy
@micropython.native # noqa: F821
def draw_portrait():
global hue
hue += 0.001
dark = from_hsv(hue, 1.0, 0.3)
mid = from_hsv(hue, 1.0, 0.6)
bright = from_hsv(hue, 1.0, 1.0)
for y in range(height):
for x in range(width):
v = liquid[x][y]
# select a colour for this pixel based on how much
# "blobfluence" there is at this position in the liquid
if v >= 1.5:
graphics.set_pen(bright)
elif v >= 1.25:
graphics.set_pen(mid)
elif v >= 1.0:
graphics.set_pen(dark)
else:
graphics.set_pen(0)
graphics.pixel(y, x)
gu.update(graphics)
setup_portrait()
gu.set_brightness(0.5)
while True:
if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_UP):
gu.adjust_brightness(+0.01)
if gu.is_pressed(GalacticUnicorn.SWITCH_BRIGHTNESS_DOWN):
gu.adjust_brightness(-0.01)
if gu.is_pressed(GalacticUnicorn.SWITCH_A):
setup_portrait()
start = time.ticks_ms()
update_liquid()
move_blobs()
draw_portrait()
# pause for a moment (important or the USB serial device will fail)
time.sleep(0.001)
print("total took: {} ms".format(time.ticks_ms() - start))