基于树莓派RP2040实现游戏“华容道”的移植项目
这里是我参加“硬禾学堂2022寒假在家练”活动所完成的项目,我选择的是设计或移植一款经典游戏——华容道,利用LCD屏显示,通过按键和四线遥感来控制游戏。
标签
嵌入式系统
2022寒假在家练
树莓派RP2040
向死而生
更新2022-03-07
中央民族大学
1032

基于树莓派RP2040实现游戏“华容道”的移植项目

一、项目介绍

     这里是我参加“硬禾学堂2022寒假在家练”活动所完成的项目,我选择的是设计或移植一款经典游戏——华容道,利用LCD屏显示,通过按键和四线遥感来控制游戏。

二、游戏介绍

       经典游戏华容道是古老的中国游戏,以其变化多端、百玩不厌的特点与魔方、独立钻石棋一起被国外智力专家并称为“智力游戏界的三个不可思议”。 “华容道”有一个带二十个小方格的棋盘,代表华容道。棋盘下方有一个两方格边长的出口,是供曹操逃走的。棋盘上共摆有十个大小不一样的棋子,它们分别代表曹操、张飞、赵云、马超、黄忠和关羽,还有四个卒。棋盘上仅有两个小方格空着,玩法就是通过这两个空格移动棋子,用最少的步数把曹操移出华容道

三、思路分析

     在设计华容道游戏时,我将棋盘分为了横向是四个,纵向是五个这样一个四×五的矩阵,共有二十个元素。

FvI_mMUk5t6E_YbiEGjwAgq1Iqr5

       随后呢,我设计了七种棋子,包含曹操、关羽、黄忠、马超、张飞、赵云以及小兵。其中,关羽是一个横向的(在X轴占两个位置,Y轴站一个位置,即一个二×一的矩阵),黄忠、赵云、张飞、马超是纵向的(即一个一×二的矩阵)。

      Fqz3fD51xKu1I0txVdXDYG-pAN4b

       这里我的初始开局设计的是华容道里的经典站位——横刀立马即将曹操防止在1256的位置,黄忠放置在04的位置……(可在代码中进行调整),在棋盘上17、18的位置上,我定义了两个洞(hole),整个棋盘上只有洞可以上下左右地移动,有可能会是一个洞移动,有可能是两个洞同时移动(前一个受后一个地影响)

       在键盘上接收到上下左右地命令后,首先需要判断是否可以移动,如果不能移动,则返回False,然后在main程序中设置蜂鸣器的响声来提示无效。

       那么如果可以移动的话,则将洞和允许移动地方块进行交换。在交换的过程中,如果是兵(1*1矩阵)则直接进行交换。如果是马超等两个色块的纵向矩阵,则需要考虑它的移动方向,纵向移动时,洞需要移动两格,而角色对应的每一个色块只需要移动一格;横向移动时则需要考虑另一个洞是不是在移动路径上,如果在移动路径上,那么就允许移动,两个洞和色块同时进行交换,完成移动。而对于关羽这种两个色块的横向矩阵,那么情况则相反。

       不停地接受命令进行位置的交换,直到最后曹操的位置到达13141718的位置时,则游戏成功,界面出现success图标。

四、软件流程图

   FiqJPLsA_vuJ0b5Z3BRVvqr8aHpB

五、软硬件介绍

     1、学习平台

       采用树莓派Pico核心芯片RP2040,双核ARM Cortex M+内核,可以运行到133MHZ,264KB内存,性能强大,具有高度灵活的可编程IO口,可用于高速数字接口,支持外部4路模拟信号输入,内部采用率高达500Ksps、12位精度,支持MicroPython、C、C++编程

       2、开发语言

       MicroPython是Python 3编程语言的一种精简而有效的实现,其中包括Python标准库的一小部分的子集,并且经过优化可在微控制器和受限环境中运行。MicroPython拥有许多高级功能,例如交互式提示,任意精度整数,闭包,列表解析,生成器,异常处理等。同时它又足够紧凑,可以在256k的代码空间和16k的RAM中运行。MicroPython的目标是与普通Python尽可能兼容,从而使您可以轻松地将代码从桌面传输到微控制器或嵌入式系统。

       3、开发工具

       Thonny 由爱沙尼亚的 Tartu 大学开发,它采用了不同的方法,其调试器是专为学习和教学编程而设计的。该软件基于python内置图形库tkinter开发,体积小巧,界面直观,支持语法着色、代码自动补全、debug等强劲功能,并具备了一个友好的IDE,并提供了几个有用的学习工具,所有这些都打包成一个直观的GUI,可以使人更快的熟悉Python编程语言。

六、重点代码介绍

     1、程序框架

Fq48SUw70DhKSJpS7Pq-YMLZGr_9

     2、main.c

import uos
import machine
import st7789 as st7789
from fonts import vga1_16x32 as font2
from machine import Pin, PWM
import time
from sanguo import HRDChess
spi_sck = machine.Pin(2)
spi_tx = machine.Pin(3)
width = 240
height = 240
res = 0
dc = 1
class DispImage():
    # 初始化
    def __init__(self):
        spi0 = machine.SPI(0, baudrate=4000000, phase=1, polarity=1, sck=spi_sck, mosi=spi_tx)
        self.disp = st7789.ST7789(spi0, width, height, reset=machine.Pin(res, machine.Pin.OUT),
                                  dc=machine.Pin(dc, machine.Pin.OUT), xstart=0, ystart=0, rotation=0)
        self.disp.fill(st7789.CYAN)
        # 载入图片
        self.imagedic = {}
        for role in ['caocao', 'huangzhong', 'zhaoyun', 'zhangfei', 'machao', 'bing', 'guanyu']:
            self.imagedic[role] = open(role + ".bmp", 'rb')
    def readImgToDiso(self, pos):
        # 绘制两个色块
        if chess.canmovehole == 0:
            hx = int(chess.hole1 % 4)  # 转为二维坐标
            hy = int(chess.hole1 / 4)
            self.disp.fill_rect(hx * 60, hy * 48, 60, 48, st7789.GREEN)
            hx = int(chess.hole2 % 4)  # 转为二维坐标
            hy = int(chess.hole2 / 4)
            self.disp.fill_rect(hx * 60, hy * 48, 60, 48, st7789.CYAN)
        else:
            hx = int(chess.hole2 % 4)  # 转为二维坐标
            hy = int(chess.hole2 / 4)
            self.disp.fill_rect(hx * 60, hy * 48, 60, 48, st7789.GREEN)
            hx = int(chess.hole1 % 4)  # 转为二维坐标
            hy = int(chess.hole1 / 4)
            self.disp.fill_rect(hx * 60, hy * 48, 60, 48, st7789.CYAN)

        role = chess.findRoleByPos(pos)
        # print(role)
        if role == None:
            return
        elif role == 'bing':  # 兵
            img = self.imagedic[role]
            hx = int(pos % 4)  # 转为二维坐标
            hy = int(pos / 4)
            img.seek(0)
            for column in range(0, 48):
                buf = img.read(120)
                self.disp.blit_buffer(buf, hx * 60, hy * 48 + column, 60, 1)
            return
        elif role == 'caocao':
            pos = chess.chess[role][0]
            width = 2
            higth = 2
        elif role in ['huangzhong', 'zhaoyun', 'zhangfei', 'machao']:
            pos = chess.chess[role][0]
            width = 1
            higth = 2
        elif role in ['guanyu']:
            pos = chess.chess[role][0]
            width = 2
            higth = 2
        img = self.imagedic[role]
        img.seek(0)
        hx = int(pos % 4)  # 转为二维坐标
        hy = int(pos / 4)
        for column in range(0, higth * 48):
            buf = img.read(width * 60 * 2)
            self.disp.blit_buffer(buf, hx * 60, hy * 48 + column, width * 60, 1)

    #显示胜利字样
    def dispSuccess(self):
        self.disp.text(font2,"SUCCESS!",55,110,color=st7789.RED, background=st7789.CYAN)

pwm = PWM(Pin(23))
pwm.freq(600)
controlH = machine.ADC(3)  # 横向控制
controlV = machine.ADC(2)  # 纵向控制
keyA = machine.Pin(5, machine.Pin.IN)


def keyaction(): 
    adc = controlH.read_u16()
    if keyA.value() == 0:
        return 4
    if adc < 12000:  # 左
        return 2
    if adc > 50000:  # 右
        return 3
    adc = controlV.read_u16()
    if adc < 12000:  # 上
        return 0
    if adc > 50000:  # 下
        return 1
    return 5

    3、sanguo.py

import sys
class HRDChess:
    def __init__(self):
        self.chess = {}

    def reset(self):  
        self.chess = {'caocao': [1, 2, 5, 6], 'huangzhong': [0, 4], 'zhaoyun': [3, 7], 'zhangfei': [8, 12],
                      'guanyu': [9, 10], 'machao': [11, 15], 'bing': [13, 14, 16, 19]}
        self.hole1 = 17  # 两个洞的位置
        self.hole2 = 18
        self.canmovehole = 0  
        self.changebox = [n for n in range(20)]  

    def action(self, act):  
        if act == 4:  # 交换 可移动hole
            self.canmovehole = (self.canmovehole + 1) % 2
            return True,self.hole1
        actecho1 = self.__checkMove(act, self.hole1)
        actecho2 = self.__checkMove(act, self.hole2)        
        if actecho1 == False and actecho2 == False:
            return False,None
        if actecho1 == True and actecho2 == True:
            if self.canmovehole == 0:
                move = self.hole1
            else:
                move = self.hole2
        elif actecho1 == False and actecho2 == True:
            move = self.hole2
            self.canmovehole = 1
        else:
            move = self.hole1
            self.canmovehole = 0

        newpos=self.__moveChess(act, move)
        return True,newpos

七、项目结果及展示

     1、开始界面

Fnpn_79stxLDxaB5nAlv_JZVbcEh

     2、游戏中

Fm1AXCyZNw2Abw9K5FB4YmEHSQgn

     3、游戏结束

FvTquCcM1z7Hbs18XllZ2v4KOKex

八、未来展望

     当前设计的游戏只有横刀立马这一关,在未来的学习及研究中,可以再进行丰富优化,改变初始位置,设置不同难度的多种游戏关卡,从而提高游戏的可玩性。

 

    

 

附件下载
Huarong Road.zip
游戏完整代码
团队介绍
中央民族大学信息工程学院电子信息工程系
团队成员
马轩
中央民族大学信息工程学院电子信息工程系学生,学号18011366
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号