一、项目介绍
一款基于树莓派RP2040嵌入式学习平台,运用micropython语言所开发的俄罗斯方块小游戏项目,在该平台上基本还原了我们平时所玩到的俄罗斯方块游戏。
二、任务要求
1、设计或移植一款经典的游戏,通过LCD屏显示
2、通过按键和四向摇杆控制游戏的动作。
3、在游戏中要通过蜂鸣器播放背景音乐
三、环境配置
1、软件
Thonny 3.3.13(官方网站:https://thonny.org/)
Thonny是硬禾学堂官方推荐的开发软件,页面简介,功能齐全,容易上手,适合初学。以下是安装配置教学视频:https://www.bilibili.com/video/BV1T44y177a8/?spm_id_from=333.788.recommend_more_video.0
2、硬件
基于树莓派RP2040的嵌入式系统学习平台(官方网站:https://www.eetree.cn/project/detail/698)
该平台专为嵌入式系统学习而设计,可以通过C/C++以及MicroPython编程来学习嵌入式系统的工作原理和应用。
(1)采用树莓派Pico核心芯片RP2040:双核Arm Cortex M0+内核,可以运行到133MHz;264KB内存;性能强大、高度灵活的可编程IO可用于高速数字接口;片内温度传感器、并支持外部4路模拟信号输入,内部ADC采样率高达500Ksps、12位精度;支持MicroPython、C、C++编程。
(2)板上功能:240*240分辨率的彩色IPS LCD,SPI接口,控制器为ST7789;四向摇杆 + 2个轻触按键 + 一个三轴姿态传感器MMA7660用做输入控制;板上外扩2MB Flash,预刷MicroPython的UF2固件;一个红外接收管 + 一个红外发射管;一个三轴姿态传感器MMA7660;一个蜂鸣器;双排16Pin连接器,有SPI、I2C以及2路模拟信号输入;可以使用MicroPython、C、C++编程;USB Type C连接器用于供电、程序下载。
以下是实物图及原理图:
四、开发思路
首先是一些初始化设置,主要是对这块LCD屏幕的驱动以及相关参数设置。之后进入游戏的开始界面,我设置按下A键可以开始游戏。进入游戏之后,随机生成五个类型总共七种的方块掉落,掉落过程中,我们可以操作摇杆来控左右移动以及加速下落,按下按键B可以进行旋转控制。下落过程中,每一次刷新都会判断下方是否有方块阻挡,如果有的话,就将该方块放置;如果没有,则可以继续下落并通过摇杆和按键进行控制。如果方块被放置了,就会判断横向是否有满行的情况,如果有的话,则会消除该行并且加十分;如果没有满行,则继续判断纵向是否有溢出,如果没有溢出,则会继续重新随机生成方块掉落,如此循环,直至判断出纵向有溢出,游戏结束,显示game over界面,之后会显示咱们硬核学堂的logo图片,然后自动进入游戏开始界面。
五、程序实现
1、模块介绍
(1)初始化模块
这里主要是各种库的调用以及函数的声明,最主要的对LCD屏幕的初始化。
以下为部分代码:
import uos
import machine
import st7789 as st7789
from machine import Pin, ADC
import random
import time
import vga2_8x8 as font1
import vga1_16x32 as font2
from time import sleep
import framebuf
from buzzer_music import music
image_file0 = "logo.bin"
f_image = open(image_file0, 'rb')
song ='0 A#4 1 1;4 D#5 1 1;4 D#5 1 1;11 D5 1 1;6 A#4 1 1;14 D#5 1 1;18 A#4 1 1;20 D#5 1 1;22 A#4 1 1;24 D5 1 1;27 D5 1 1;30 D#5 1 1;32 A#4 1 3'
st7789_res = 0
st7789_dc = 1
disp_width = 240
disp_height = 240
spi_sck = machine.Pin(2)
spi_tx = machine.Pin(3)
spi0 = machine.SPI(0,baudrate=400000000, phase=1, polarity=1,sck=spi_sck,mosi=spi_tx)
display = st7789.ST7789(spi0, disp_width,disp_width,
reset=machine.Pin(st7789_res,machine.Pin.OUT),
dc=machine.Pin(st7789_dc,machine.Pin.OUT),
xstart=0,ystart=0,rotation=0)
xAxis = ADC(Pin(28))
yAxis = ADC(Pin(29))
display.fill(st7789.BLACK)
buttonB = Pin(5,Pin.IN, Pin.PULL_UP)
buttonA = Pin(6,Pin.IN, Pin.PULL_UP)
(2)方块绘制
此模块用于绘制五个类型总共七种的方块。在代码中,“1”的意思是代表格子上有方块,就会绘制出一个方块出来;0代表没有方块,所以就不会进行绘制——基于此,我们就可以生成其中方块出来。
以下为部分代码:
boxO = [[1,1],[1,1]]
boxz_1 = [[1,1,0],[0,1,1],[0,0,0]]
boxz_2 = [[0,1,1],[1,1,0],[0,0,0]]
box7_1 = [[1,1,0],[0,1,0],[0,1,0]]
box7_2 = [[0,1,1],[0,1,0],[0,1,0]]
boxT = [[0,1,0],[1,1,1],[0,0,0]]
boxI = [[0,0,0,0,0],[0,0,0,0,0],[1,1,1,1,0],[0,0,0,0,0],[0,0,0,0,0]]
boxes = [boxO,boxz_1,boxz_2,box7_1,box7_2,boxT,boxI]
score = 0
box_column = 4
box_row = 0
global cell
global gameover
gameover=False
cell = 15
box_column = 4
box_row = 0
def newbox():
box_id=random.randint(0,6)
box_org = boxes[box_id]
b = []
for i in range(len(box_org)):
b.append(box_org[i][:])
return b
box=newbox()
(3)方块下落
该模块主要是控制方块自动掉落,原理是在下一行绘制上一行的方块,然后对上一行进行擦出,以此实现下落效果。
以下为部分代码:
def autodown():
global box_row,box_column,box,box_id
leave()
box_row+=1
if checkvalid() == False:
box_row-=1
enter()
clear()
box=newbox()
box_column = 4
box_row = 0
enter()
def drawbox():
global color
display.fill(0x0000)
y=0
for r in g:
x=0
for d in r:
if d==1:
display.rect(x,y,15,15,0x10)
display.fill_rect(x+1,y+1,13,13,color=0xfe89)
x+=cell
y+=cell
(4)摇杆控制
此模块主要实现摇杆控制左右以及加速下落。首先我们对于左右移动以及下落动作分别对应x轴以及y轴设置相应的数值范围,当我们的摇杆摆动到相应范围之后则实现对应的动作。
以下为部分代码:
if buttonB.value()==0:
up()
elif xValue in range(50000,70000):
down()
elif yValue in range(0,20000):
left()
elif yValue in range(50000,70000):
right()
drawbox()
display.fill_rect(181,0,1,240,color=0xffffff)
display.text(font1,"Score",190,80,color=0x64fa)
display.text(font2,str(score),195,100, color=0x7e0)
autodown()
def down():
global box_row
leave()
box_row+=1
if checkvalid() == False:
box_row-=1
enter()
def left():
global box_column
leave()
box_column-=1
if checkvalid() == False:
box_column+=1
enter()
def right():
global box_column
leave()
box_column+=1
if checkvalid() == False:
box_column-=1
enter()
(5)旋转控制
此模块主要实现通过按下B键进行方块的旋转。原理基本同自动下落控制模块,即小方块的生成以及擦除。
以下为部分代码:
def up():
"""
A------- B-------
|1|2|3| |7|4|1|
------- -------
|4|5|6| |8|5|2|
------- -------
|7|8|9| |9|6|3|
------- -------
b[N-j-1][i] = a[i][j]顺时针
b[j][N-i-1] = a[i][j]逆时针
"""
leave()
clockwise()
if checkvalid()==False:
counter_clockwise()
enter()
(6)消除模块
当判断出某一行满行,则消除该行,并在score处加十分。
以下为部分代码:
def clear():
global score,gameover
i = 0
c = 0
while i<16:
if 0 in g[i]:
i+=1
else:
c+=1
del g[i]
g.insert(0,[0]*16)
if c>0:
score += 10*(2**(c-1))
if 1 in g[0]:
gameover = True
(6)音乐模块
游戏背景音乐,我直接用了在教程里编好的节奏,此模块因为时间紧并没有做出相应的探索,而是直接用现成的。之后会对蜂鸣器专门进行“把玩”。
以下为部分代码:
song ='0 A#4 1 1;4 D#5 1 1;4 D#5 1 1;11 D5 1 1;6 A#4 1 1;14 D#5 1 1;18 A#4 1 1;20 D#5 1 1;22 A#4 1 1;24 D5 1 1;27 D5 1 1;30 D#5 1 1;32 A#4 1 3'
def playmusic(mySong,time):
l = 0
time0 = time/40
while l<time0:
l+=1
mySong.tick()
sleep(0.04)
(7)重新开始
游戏失败,则重新绘制开始画面进入游戏。
以下为部分代码:
def restart():
display.fill(0x0000)
display.text(font2, "RP2040 ITERM", 25, 50, color=0x64fa)
display.text(font2, "TETRIS", 70, 105, color=0xe26b)
display.text(font2, "PRESS START", 15, 190, color=0x7e0)
display.text(font2, "A", 112, 190, color=0xffffff)
buttonValueB = buttonB.value()
while True:
buttonValueA = buttonA.value()
if buttonValueA==0:
g = []
for i in range(16):
g.append([0]*12)
enter()
game()
2、游戏主体
游戏主体部分,连接各个模块。
以下为部分代码:
global gamover,song
mySong = music(song,pins=[Pin(23)])
while True:
playmusic(mySong,400)
xValue = xAxis.read_u16()
yValue = yAxis.read_u16()
f=4
if buttonB.value()==0:
up()
elif xValue in range(50000,70000):
down()
elif yValue in range(0,20000):
left()
elif yValue in range(50000,70000):
right()
drawbox()
display.fill_rect(181,0,1,240,color=0xffffff)
display.text(font1,"Score",190,80,color=0x64fa)
display.text(font2,str(score),195,100, color=0x7e0)
autodown()
if gameover==True:
display.fill(0x0000)
display.text(font2,"===GAME===",45,60)
display.text(font2,"===OVER===",45,130)
time.sleep(1)
for column in range(1,240):
buf=f_image.read(480)
display.blit_buffer(buf, 1, column, 240, 1)
time.sleep(1)
restart()
六、实现效果
1、开机界面
2、得分界面
3、GAME OVER界面
4、logo界面
七、后记
很仓促的时间完成了这个项目,也参考了网上的一些案例。但通过参考和查阅,对于嵌入式、micropython等等概念有了更加深入和理解和掌握。这也是我第一次运用micropython语言进行编程开发,所有仓促做出的东西不可避免有些bug,证明自己对于语言的理解还是不够,计划在之后能够通过更多的案例参考以及资料查阅进行更加深入的学习。
树莓派RP2040是一个很好的开发平台,在项目之外还有好多好多功能我并没有用到,这极大激励了我在之后探索的兴趣和动力,并以此来调节略微无趣的生活。
最后,很感谢各位老师耐心的讲解以及资源分享,让我见识到了更加高远的天地!