"""
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Dino Game using Micropython with Raspberry Pi Pico ┃
┃ ┃
┃ Building a Dino game using MicroPython on an SSD1306 OLED ┃
┃ display involves setting up the hardware,initializing the ┃
┃ display and button, and writing the game logic. ┃
┃ ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
"""
from machine import Pin, I2C # 匯入控制腳位與I2C通訊的模組
import ssd1306 # OLED顯示器驅動模組
import time # 時間模組,用來延遲
# 初始化I2C通訊,SCL接GPIO 27,SDA接GPIO 26
i2c = I2C(1, scl=Pin(27), sda=Pin(26))
# 初始化OLED顯示器,解析度128x64,使用剛剛設定的I2C通訊
display = ssd1306.SSD1306_I2C(128, 64, i2c)
# 設定按鈕腳位22,輸入模式,啟用內部上拉電阻(按鈕沒按時腳位為高)
jump_button = Pin(22, Pin.IN, Pin.PULL_UP)
# 恐龍初始X座標(固定)
dino_x = 10
# 恐龍初始Y座標(站在地面)
dino_y = 60
# 恐龍身體寬度和高度
dino_width = 12
dino_height = 6
# 恐龍垂直速度(跳躍用)
dino_velocity = 0
# 是否正在跳躍
jumping = False
# 重力加速度(讓恐龍跳起後會往下掉)
gravity = 1
# 跳躍初速度(負值代表往上跳)
jump_power = -9
# 地面Y座標
ground_level = 60
# 障礙物寬度、高度及初始X座標(從右邊開始)
obstacle_width = 10
obstacle_height = 10
obstacle_x = 128
# 障礙物移動速度
obstacle_speed = 2
# 遊戲分數初始為0
score = 0
# 畫恐龍函式,根據x,y座標畫出身體、腿、尾巴和頭
def draw_dino(x, y):
# 畫身體(12x6像素)
for i in range(dino_width):
for j in range(dino_height):
display.pixel(x + i, y + j, 1)
# 畫左腿(3x3像素)
for i in range(3):
for j in range(3):
display.pixel(x + i, y + dino_height + j, 1)
# 畫右腿(3x3像素)
for i in range(3):
for j in range(3):
display.pixel(x + dino_width - 3 + i, y + dino_height + j, 1)
# 畫尾巴(4x4像素)
for i in range(4):
for j in range(4):
display.pixel(x - 4 + i, y + 2 + j, 1)
# 畫頭(6x6像素)
for i in range(6):
for j in range(6):
display.pixel(x + dino_width - 6 + i, y - 6 + j, 1)
# 畫眼睛(用黑色擦掉部分像素形成眼睛)
for i in range(2):
for j in range(2):
display.pixel(x + dino_width - 4 + i, y - 4 + j, 0)
# 畫障礙物函式(小樹)
def draw_obstacle(x, y):
# 畫樹幹(4x6像素)
for i in range(4):
for j in range(6):
display.pixel(x + 2 + i, y + 4 + j, 1)
# 畫樹葉(12x6像素)
for i in range(12):
for j in range(6):
display.pixel(x - 4 + i, y + j, 1)
# 重設遊戲狀態,恐龍回地面,障礙物回右邊,分數歸零
def reset_game():
global dino_y, dino_velocity, jumping, obstacle_x, score, obstacle_speed
dino_y = ground_level - dino_height
dino_velocity = 0
jumping = False
obstacle_x = 128
score = 0
obstacle_speed = 2
# 顯示遊戲結束畫面
def display_game_over():
display.fill(0) # 清螢幕
display.text("Game Over!", 30, 30)
display.text("Score: {}".format(score), 30, 40)
display.show()
# 遊戲主迴圈
def game_loop():
global dino_y, dino_velocity, jumping, obstacle_x, score, obstacle_speed
while True:
display.fill(0) # 每回合清空螢幕
# 按鍵持續按住時,持續給跳躍初速度,恐龍往上推,停空更久
if jumping:
if jump_button.value() == 0:
# 按鍵按著,保持當前速度與高度,恐龍停空不動
pass
else:
# 放開按鍵,開始受重力影響往下掉
dino_velocity += gravity
dino_y += dino_velocity
# 落回地面判斷
if dino_y >= ground_level - dino_height:
dino_y = ground_level - dino_height
jumping = False
dino_velocity = 0
else:
# 如果沒跳且按鍵按下,開始跳躍
if jump_button.value() == 0:
dino_velocity = jump_power
jumping = True
dino_y += dino_velocity
# 障礙物往左移動
obstacle_x -= obstacle_speed
# 障礙物跑出螢幕左側,重置並加分
if obstacle_x < 0:
obstacle_x = 128
score += 1
# 每5分速度提速
if score % 2 == 0:
obstacle_speed += 2
# 碰撞判斷(矩形碰撞)
if (obstacle_x < dino_x + dino_width and
obstacle_x + obstacle_width > dino_x and
dino_y < ground_level and
dino_y + dino_height > ground_level - obstacle_height):
display_game_over()
while True:
time.sleep(1) # 遊戲停止
# 畫恐龍和障礙物
draw_dino(dino_x, dino_y)
draw_obstacle(obstacle_x, ground_level - obstacle_height)
# 顯示分數
display.text("Score: {}".format(score), 0, 0)
# 更新畫面
display.show()
# 控制遊戲速度
time.sleep(0.05)
# 遊戲開始前重設狀態
reset_game()
# 執行遊戲主迴圈
game_loop()