524 lines
17 KiB
Python
524 lines
17 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
WS2812B 更多趣味LED特效
|
||
包含物理效果、游戏效果和节日主题特效
|
||
"""
|
||
|
||
import time
|
||
import random
|
||
import math
|
||
import RPi.GPIO as GPIO
|
||
from rpi_ws281x import Color, PixelStrip
|
||
|
||
|
||
class WS2812B_WS281X:
|
||
def __init__(self, led_count=10, brightness=100):
|
||
self.led_count = led_count
|
||
self.brightness = brightness
|
||
|
||
# WS2812B配置
|
||
LED_PIN = 10 # GPIO引脚(SPI模式)
|
||
LED_FREQ_HZ = 800000 # LED信号频率
|
||
LED_DMA = 10 # DMA通道
|
||
LED_INVERT = False # 是否反转信号
|
||
LED_CHANNEL = 0 # PWM通道
|
||
|
||
# 创建PixelStrip对象
|
||
self.strip = PixelStrip(led_count, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, brightness, LED_CHANNEL)
|
||
self.strip.begin()
|
||
|
||
# 初始化后清空
|
||
time.sleep(0.1)
|
||
for i in range(led_count):
|
||
self.strip.setPixelColor(i, Color(0, 0, 0))
|
||
self.strip.show()
|
||
time.sleep(0.1)
|
||
|
||
def show(self, colors):
|
||
"""显示颜色"""
|
||
for i, (r, g, b) in enumerate(colors):
|
||
self.strip.setPixelColor(i, Color(int(r), int(g), int(b)))
|
||
self.strip.show()
|
||
|
||
def cleanup(self):
|
||
"""清理资源"""
|
||
# 清空所有LED
|
||
for i in range(self.led_count):
|
||
self.strip.setPixelColor(i, Color(0, 0, 0))
|
||
self.strip.show()
|
||
|
||
# ===== 物理效果类特效 =====
|
||
|
||
def gravity_bounce(ws, ball_color=(255, 100, 0), cycles=5):
|
||
"""重力弹跳效果"""
|
||
print("重力弹跳效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 弹跳 {cycle + 1}/{cycles}")
|
||
|
||
# 模拟重力弹跳
|
||
height = 0
|
||
velocity = 0
|
||
gravity = 0.5
|
||
bounce_damping = 0.8
|
||
|
||
for _ in range(50):
|
||
velocity += gravity
|
||
height += velocity
|
||
|
||
# 检查是否触底
|
||
if height >= ws.led_count - 1:
|
||
height = ws.led_count - 1
|
||
velocity = -velocity * bounce_damping
|
||
|
||
# 显示球的位置
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
ball_pos = int(height)
|
||
if 0 <= ball_pos < ws.led_count:
|
||
colors[ball_pos] = ball_color
|
||
|
||
# 添加影子效果
|
||
if ball_pos > 0:
|
||
shadow_intensity = max(0, int(50 - abs(height - ball_pos) * 20))
|
||
colors[ball_pos - 1] = (shadow_intensity, shadow_intensity // 2, 0)
|
||
|
||
ws.show(colors)
|
||
time.sleep(0.05)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("重力弹跳效果完成!")
|
||
|
||
def wave_ripple(ws, center_color=(0, 100, 255), cycles=8):
|
||
"""波纹扩散效果"""
|
||
print("波纹扩散效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 波纹 {cycle + 1}/{cycles}")
|
||
|
||
for i in range(ws.led_count):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
|
||
# 从中心向两边扩散
|
||
center = ws.led_count // 2
|
||
distance = abs(i - center)
|
||
|
||
# 在两边对称的位置显示波纹
|
||
if center - distance >= 0:
|
||
intensity = max(0, 255 - distance * 50)
|
||
colors[center - distance] = (
|
||
int(center_color[0] * intensity / 255),
|
||
int(center_color[1] * intensity / 255),
|
||
int(center_color[2] * intensity / 255)
|
||
)
|
||
|
||
if center + distance < ws.led_count and distance > 0:
|
||
intensity = max(0, 255 - distance * 50)
|
||
colors[center + distance] = (
|
||
int(center_color[0] * intensity / 255),
|
||
int(center_color[1] * intensity / 255),
|
||
int(center_color[2] * intensity / 255)
|
||
)
|
||
|
||
ws.show(colors)
|
||
time.sleep(0.1)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("波纹扩散效果完成!")
|
||
|
||
def magnet_effect(ws, metal_color=(150, 150, 150), magnet_color=(255, 0, 0), cycles=6):
|
||
"""磁铁吸引效果"""
|
||
print("磁铁吸引效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 磁铁循环 {cycle + 1}/{cycles}")
|
||
|
||
# 磁铁位置(左右两端)
|
||
magnet_positions = [0, ws.led_count - 1]
|
||
|
||
for frame in range(30):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
|
||
# 显示磁铁
|
||
for pos in magnet_positions:
|
||
colors[pos] = magnet_color
|
||
|
||
# 计算金属粒子位置
|
||
for i in range(3): # 3个金属粒子
|
||
particle_pos = int(4 + 2 * math.sin(frame * 0.3 + i * 2))
|
||
if 0 < particle_pos < ws.led_count - 1:
|
||
colors[particle_pos] = metal_color
|
||
|
||
ws.show(colors)
|
||
time.sleep(0.1)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("磁铁吸引效果完成!")
|
||
|
||
def pendulum_swing(ws, pendulum_color=(255, 255, 0), cycles=10):
|
||
"""钟摆摆动效果"""
|
||
print("钟摆摆动效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 钟摆循环 {cycle + 1}/{cycles}")
|
||
|
||
# 模拟钟摆运动
|
||
for angle in range(-60, 61, 5):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
|
||
# 计算钟摆位置
|
||
center = ws.led_count // 2
|
||
position = int(center + angle / 15)
|
||
|
||
if 0 <= position < ws.led_count:
|
||
colors[position] = pendulum_color
|
||
|
||
# 添加运动模糊效果
|
||
if angle > -60 and position > 0:
|
||
colors[position - 1] = (pendulum_color[0] // 3, pendulum_color[1] // 3, pendulum_color[2] // 3)
|
||
|
||
ws.show(colors)
|
||
time.sleep(0.08)
|
||
|
||
# 反向摆动
|
||
for angle in range(60, -61, -5):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
|
||
center = ws.led_count // 2
|
||
position = int(center + angle / 15)
|
||
|
||
if 0 <= position < ws.led_count:
|
||
colors[position] = pendulum_color
|
||
|
||
if angle < 60 and position < ws.led_count - 1:
|
||
colors[position + 1] = (pendulum_color[0] // 3, pendulum_color[1] // 3, pendulum_color[2] // 3)
|
||
|
||
ws.show(colors)
|
||
time.sleep(0.08)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("钟摆摆动效果完成!")
|
||
|
||
# ===== 游戏效果类特效 =====
|
||
|
||
def snake_game(ws, cycles=3):
|
||
"""贪吃蛇游戏效果"""
|
||
print("贪吃蛇游戏效果开始...")
|
||
|
||
snake_color = (0, 255, 0)
|
||
food_color = (255, 0, 0)
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 贪吃蛇 {cycle + 1}/{cycles}")
|
||
|
||
# 初始化蛇的位置
|
||
snake = [(0, 0), (0, 1), (0, 2)] # 简化为线性移动
|
||
food = random.randint(3, ws.led_count - 1)
|
||
|
||
for step in range(20):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
|
||
# 移动蛇
|
||
if step < 15:
|
||
new_head = (snake[-1][0] + 1) % ws.led_count
|
||
snake.append((new_head, snake[-1][1] + 1))
|
||
snake.pop(0)
|
||
|
||
# 显示蛇
|
||
for i, (pos, _) in enumerate(snake):
|
||
if i == len(snake) - 1: # 蛇头
|
||
colors[pos % ws.led_count] = (0, 150, 0)
|
||
else: # 蛇身
|
||
colors[pos % ws.led_count] = snake_color
|
||
|
||
# 显示食物
|
||
colors[food] = food_color
|
||
|
||
ws.show(colors)
|
||
time.sleep(0.2)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("贪吃蛇游戏效果完成!")
|
||
|
||
def space_invaders(ws, cycles=5):
|
||
"""太空侵略者效果"""
|
||
print("太空侵略者效果开始...")
|
||
|
||
alien_color = (0, 255, 0)
|
||
bullet_color = (255, 255, 0)
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 入侵者 {cycle + 1}/{cycles}")
|
||
|
||
# 外星人移动
|
||
for direction in [1, -1]:
|
||
for step in range(ws.led_count - 2):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
|
||
# 显示外星人
|
||
alien_pos = 3 + step * direction
|
||
if 0 <= alien_pos < ws.led_count:
|
||
colors[alien_pos] = alien_color
|
||
|
||
# 随机子弹
|
||
if random.random() < 0.3:
|
||
bullet_pos = random.randint(0, ws.led_count - 1)
|
||
colors[bullet_pos] = bullet_color
|
||
|
||
ws.show(colors)
|
||
time.sleep(0.15)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("太空侵略者效果完成!")
|
||
|
||
def pong_game(ws, cycles=10):
|
||
"""乒乓球游戏效果"""
|
||
print("乒乓球游戏效果开始...")
|
||
|
||
paddle_color = (255, 255, 255)
|
||
ball_color = (255, 100, 100)
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 乒乓球 {cycle + 1}/{cycles}")
|
||
|
||
# 球的初始位置和速度
|
||
ball_pos = ws.led_count // 2
|
||
ball_velocity = 1
|
||
|
||
for _ in range(30):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
|
||
# 显示球拍
|
||
colors[0] = paddle_color
|
||
colors[ws.led_count - 1] = paddle_color
|
||
|
||
# 显示球
|
||
if 0 <= ball_pos < ws.led_count:
|
||
colors[ball_pos] = ball_color
|
||
|
||
# 移动球
|
||
ball_pos += ball_velocity
|
||
|
||
# 碰撞检测
|
||
if ball_pos <= 0 or ball_pos >= ws.led_count - 1:
|
||
ball_velocity = -ball_velocity
|
||
|
||
ws.show(colors)
|
||
time.sleep(0.1)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("乒乓球游戏效果完成!")
|
||
|
||
def matrix_rain(ws, cycles=8):
|
||
"""黑客帝国数字雨效果"""
|
||
print("黑客帝国数字雨效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 数字雨 {cycle + 1}/{cycles}")
|
||
|
||
for frame in range(20):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
|
||
# 随机生成数字雨
|
||
for i in range(ws.led_count):
|
||
if random.random() < 0.3:
|
||
intensity = random.randint(100, 255)
|
||
colors[i] = (0, intensity, 0)
|
||
elif random.random() < 0.1:
|
||
# 更亮的"头部"
|
||
colors[i] = (100, 255, 100)
|
||
|
||
ws.show(colors)
|
||
time.sleep(0.1)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("黑客帝国数字雨效果完成!")
|
||
|
||
# ===== 节日主题特效 =====
|
||
|
||
def christmas_lights(ws, cycles=8):
|
||
"""圣诞彩灯效果"""
|
||
print("圣诞彩灯效果开始...")
|
||
|
||
colors_list = [
|
||
(255, 0, 0), # 红
|
||
(0, 255, 0), # 绿
|
||
(255, 255, 255), # 白
|
||
(255, 215, 0), # 金
|
||
(0, 0, 255), # 蓝
|
||
]
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 圣诞彩灯 {cycle + 1}/{cycles}")
|
||
|
||
# 随机闪烁
|
||
for i in range(15):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
|
||
# 随机点亮一些LED
|
||
for j in range(ws.led_count):
|
||
if random.random() < 0.4:
|
||
colors[j] = random.choice(colors_list)
|
||
|
||
ws.show(colors)
|
||
time.sleep(0.2)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("圣诞彩灯效果完成!")
|
||
|
||
def fireworks(ws, cycles=6):
|
||
"""烟花爆炸效果"""
|
||
print("烟花爆炸效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 烟花 {cycle + 1}/{cycles}")
|
||
|
||
# 烟花上升
|
||
for i in range(ws.led_count):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
colors[i] = (255, 255, 0) # 黄色上升轨迹
|
||
ws.show(colors)
|
||
time.sleep(0.05)
|
||
|
||
# 爆炸效果
|
||
explosion_colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (255, 0, 255)]
|
||
|
||
for frame in range(15):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
|
||
# 随机爆炸粒子
|
||
for _ in range(random.randint(3, 6)):
|
||
pos = random.randint(0, ws.led_count - 1)
|
||
colors[pos] = random.choice(explosion_colors)
|
||
|
||
ws.show(colors)
|
||
time.sleep(0.1)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("烟花爆炸效果完成!")
|
||
|
||
def valentine_heart(ws, cycles=5):
|
||
"""情人节心跳效果"""
|
||
print("情人节心跳效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 心跳 {cycle + 1}/{cycles}")
|
||
|
||
# 心跳模式
|
||
for beat in range(3):
|
||
colors = [(255, 0, 100)] * ws.led_count # 粉红色
|
||
ws.show(colors)
|
||
time.sleep(0.1)
|
||
|
||
colors = [(150, 0, 50)] * ws.led_count # 暗粉色
|
||
ws.show(colors)
|
||
time.sleep(0.1)
|
||
|
||
# 暂停
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
ws.show(colors)
|
||
time.sleep(0.5)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("情人节心跳效果完成!")
|
||
|
||
def halloween_pumpkin(ws, cycles=8):
|
||
"""万圣节南瓜灯效果"""
|
||
print("万圣节南瓜灯效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 南瓜灯 {cycle + 1}/{cycles}")
|
||
|
||
# 摇曳的橙色光
|
||
for i in range(20):
|
||
colors = [(0, 0, 0)] * ws.led_count
|
||
|
||
for j in range(ws.led_count):
|
||
# 随机亮度变化模拟摇曳
|
||
intensity = random.randint(100, 255)
|
||
colors[j] = (intensity, intensity // 2, 0) # 橙色
|
||
|
||
ws.show(colors)
|
||
time.sleep(0.1)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("万圣节南瓜灯效果完成!")
|
||
|
||
def new_year_countdown(ws, cycles=3):
|
||
"""新年倒计时效果"""
|
||
print("新年倒计时效果开始...")
|
||
|
||
for cycle in range(cycles):
|
||
print(f" 倒计时 {cycle + 1}/{cycles}")
|
||
|
||
# 倒计时数字效果
|
||
for countdown in [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]:
|
||
colors = [(255, 215, 0)] * countdown + [(0, 0, 0)] * (ws.led_count - countdown)
|
||
ws.show(colors)
|
||
time.sleep(0.5)
|
||
|
||
# 新年庆祝
|
||
for i in range(10):
|
||
colors = []
|
||
for j in range(ws.led_count):
|
||
if random.random() < 0.5:
|
||
colors.append((random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
|
||
else:
|
||
colors.append((0, 0, 0))
|
||
ws.show(colors)
|
||
time.sleep(0.1)
|
||
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
print("新年倒计时效果完成!")
|
||
|
||
# ===== 主展示函数 =====
|
||
|
||
def show_fun_effects():
|
||
"""展示所有趣味LED特效"""
|
||
ws = WS2812B_WS281X(led_count=10, brightness=100)
|
||
|
||
try:
|
||
print("🎮 趣味LED特效展示开始!")
|
||
print("=" * 50)
|
||
|
||
# 特效列表
|
||
effects = [
|
||
("物理效果 - 重力弹跳", lambda: gravity_bounce(ws, cycles=3)),
|
||
("物理效果 - 波纹扩散", lambda: wave_ripple(ws, cycles=6)),
|
||
("物理效果 - 磁铁吸引", lambda: magnet_effect(ws, cycles=4)),
|
||
("物理效果 - 钟摆摆动", lambda: pendulum_swing(ws, cycles=6)),
|
||
("游戏效果 - 贪吃蛇", lambda: snake_game(ws, cycles=2)),
|
||
("游戏效果 - 太空侵略者", lambda: space_invaders(ws, cycles=3)),
|
||
("游戏效果 - 乒乓球", lambda: pong_game(ws, cycles=6)),
|
||
("游戏效果 - 黑客帝国", lambda: matrix_rain(ws, cycles=5)),
|
||
("节日效果 - 圣诞彩灯", lambda: christmas_lights(ws, cycles=6)),
|
||
("节日效果 - 烟花爆炸", lambda: fireworks(ws, cycles=4)),
|
||
("节日效果 - 情人心跳", lambda: valentine_heart(ws, cycles=4)),
|
||
("节日效果 - 万圣南瓜", lambda: halloween_pumpkin(ws, cycles=6)),
|
||
("节日效果 - 新年倒计时", lambda: new_year_countdown(ws, cycles=2)),
|
||
]
|
||
|
||
# 按顺序播放每个特效
|
||
for i, (name, effect_func) in enumerate(effects):
|
||
print(f"\n🎭 特效 {i+1}/{len(effects)}: {name}")
|
||
print("-" * 30)
|
||
|
||
effect_func()
|
||
|
||
# 特效之间短暂停顿
|
||
time.sleep(1)
|
||
|
||
print("\n🎉 所有趣味特效播放完成!")
|
||
print("=" * 50)
|
||
|
||
except KeyboardInterrupt:
|
||
print("\n⏹️ 用户中断,停止播放...")
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
except Exception as e:
|
||
print(f"\n❌ 播放出错: {e}")
|
||
ws.show([(0, 0, 0)] * ws.led_count)
|
||
finally:
|
||
ws.cleanup()
|
||
print("🧹 清理完成")
|
||
|
||
if __name__ == "__main__":
|
||
show_fun_effects() |