反射神経ゲーム改良版をWS2815B(NeoPixel)を使って作る
龍野プログラミングクラブはJR本竜野駅2階多目的室(上の写真)で定期開催しています。
タッチタイピングの練習とアルゴロジック
わたしが運営するクラブでは、かならずタッチタイピングを練習します。キーを打つことを、息をするようにできるまで練習します。
タッチタイピングで使うツールは、無料タイピングと寿司打と右手専用タイピングです。
無料タイピング https://manabi.benesse.ne.jp/gakushu/typing
右手専用タイピング https://typing.twi1.me/game/15206
WS2812B(NeoPixel)を7つ使って反射神経ゲームを作る
"""
ここに3行
"""
import _thread
import sys
# ハードウェア設定
"""
ここに6行
"""
# タイミング設定
TIMING = {
"ANIMATION_DELAY": 0.05, # LEDの点灯間隔(秒)
"PAUSE_TIME": 2, # 一時停止時間(秒)
"""ここに1行"""
"DEBOUNCE_TIME": 50 # チャタリング防止時間(ミリ秒)
}
# ゲーム設定
GAME_CONFIG = {
"BLINK_COUNT": 5 # 点滅回数
}
# 色の定義
"""
ここに5行
"""
class LEDController:
"""LEDの制御を行うクラス"""
def __init__(self, pin, num_leds, center_led):
"""LEDコントローラーの初期化"""
self.np = neopixel.NeoPixel(machine.Pin(pin), num_leds)
self.num_leds = num_leds
self.center_led = center_led
def clear(self):
"""すべてのLEDをオフにする"""
for i in range(self.num_leds):
self.np[i] = COLORS["OFF"]
self.np.write()
def set_initial_state(self):
"""初期状態に設定(中央は赤、他は消灯)"""
for i in range(self.num_leds):
self.np[i] = COLORS["RED"] if i == self.center_led else COLORS["OFF"]
self.np.write()
def update_led(self, pos):
"""指定位置のLEDを更新"""
self.clear()
color = COLORS["RED"] if pos == self.center_led else COLORS["BLUE"]
self.np[pos] = color
self.np.write()
def blink(self, times, delay):
"""現在のLED状態を保存して点滅させる"""
# 現在のLED状態を保存
current_state = [self.np[i] for i in range(self.num_leds)]
# 指定回数点滅
for _ in range(times):
# 消灯
self.clear()
time.sleep(delay)
# 点灯(元の状態に戻す)
for i in range(self.num_leds):
self.np[i] = current_state[i]
self.np.write()
time.sleep(delay)
class ButtonHandler:
"""ボタン入力を処理するクラス"""
def __init__(self, pin, debounce_time):
"""ボタンハンドラの初期化"""
self.button = machine.Pin(pin, machine.Pin.IN, machine.Pin.PULL_UP)
self.debounce_time = debounce_time
self.last_press_time = 0
def is_pressed(self):
"""チャタリング防止付きのボタン押下検出"""
if self.button.value() == 0: # ボタンが押された(プルアップなので0)
current_time = time.ticks_ms()
# チャタリング防止
if time.ticks_diff(current_time, self.last_press_time) > self.debounce_time:
self.last_press_time = current_time
return True
return False
class ReflexGame:
"""反射神経ゲームの管理クラス"""
def __init__(self):
"""ゲームの初期化"""
self.led_controller = LEDController(
PIN_CONFIG["LED_PIN"],
PIN_CONFIG["NUM_LEDS"],
PIN_CONFIG["CENTER_LED"]
)
self.button_handler = ButtonHandler(
PIN_CONFIG["BUTTON_PIN"],
TIMING["DEBOUNCE_TIME"]
)
self.running = True
self.paused = False
# アニメーションの順序(0ベースインデックス)
self.sequence = [3, 4, 5, 6, 5, 4, 3, 2, 1, 0, 1, 2]
def handle_button_press(self):
"""ボタン押下時の処理"""
if self.button_handler.is_pressed() and not self.paused:
self.paused = True
time.sleep(TIMING["PAUSE_TIME"])
self.led_controller.blink(GAME_CONFIG["BLINK_COUNT"], TIMING["BLINK_DELAY"])
self.paused = False
return True
return False
def run_animation(self):
"""LEDアニメーションを実行"""
self.led_controller.set_initial_state()
try:
while self.running:
for pos in self.sequence:
if not self.running:
break
if self.paused:
# 一時停止中は待機
while self.paused and self.running:
time.sleep(0.1)
continue
# LEDを更新
self.led_controller.update_led(pos)
# 点灯間隔待機中にボタンチェック
start_time = time.ticks_ms()
while time.ticks_diff(time.ticks_ms(), start_time) < TIMING["ANIMATION_DELAY"] * 1000:
if self.handle_button_press() or not self.running or self.paused:
break
time.sleep(0.01)
except Exception as e:
print(f"アニメーションエラー: {e}")
finally:
if not self.paused:
self.led_controller.clear()
def stop(self):
"""ゲームを停止"""
self.running = False
time.sleep(0.5) # スレッドが終了するのを少し待つ
self.led_controller.clear()
# メイン処理
def main():
game = ReflexGame()
# アニメーションを別スレッドで開始
_thread.start_new_thread(game.run_animation, ())
try:
while True:
# メインスレッドでも定期的にボタンチェック
game.handle_button_press()
time.sleep(0.1)
except KeyboardInterrupt:
game.stop()
print("プログラムを終了します")
"""
ここに2行
"""