用RP2040实现小车游戏
基于RP2040实现小车游戏,通过A,B按键来控制小车左右移动来躲避障碍物,每过一个障碍物就会得一分,碰到障碍物游戏结束。
标签
嵌入式系统
显示
2022寒假在家练
luguoyang
更新2022-03-22
中央民族大学
1016

一、项目介绍

基于RP2040实现小车游戏,通过A,B按键来控制小车左右移动来躲避障碍物,每过一个障碍物就会得一分,碰到障碍物游戏结束。

二、硬件介绍

  • 采用树莓派Pico核心芯片RP2040:

    • 双核Arm Cortex M0+内核,可以运行到133MHz

    • 264KB内存
    • 性能强大、高度灵活的可编程IO可用于高速数字接口

    • 片内温度传感器、并支持外部4路模拟信号输入,内部ADC采样率高达500Ksps、12位精度

    • 支持MicroPython、C、C++编程

  • 板上功能:

    • 240*240分辨率的彩色IPS LCD,SPI接口,控制器为ST7789

    • 四向摇杆 + 2个轻触按键 + 一个三轴姿态传感器MMA7660用做输入控制

    • 板上外扩2MB Flash,预刷MicroPython的UF2固件

    • 一个红外接收管 + 一个红外发射管

    • 一个三轴姿态传感器MMA7660
    • 一个蜂鸣器

    • 双排16Pin连接器,有SPI、I2C以及2路模拟信号输入

    • 可以使用MicroPython、C、C++编程

    • USB Type C连接器用于供电、程序下

三、设计思路

设计流程图如下:

FpMktEYur_-47laJV5-A2R6b0YTf

首先进行硬件的初始化,然后简单的搭建外框架def out_frame(self):,然后分别定义一个小车和障碍物的函数def obstacle_frame(self):并且将小车和障碍物的坐标保存到一个数组中,为接下来的是否发生碰撞提供数据进行判断,通过调用这个函数可以将小车和障碍物显示在屏幕上,然后定义一个函数来移动小车和障碍物,具体就是通过不断的擦除和写入来实现方块的移动,小车移动函数为def car_move(self,yg_direction):其后面的参数用来控制小车移动的方向。障碍物移动函数为:def obstacle_move(self):碰撞检测函数为def car_obstacle(self):

在项目中遇到的一个问题就是障碍物移动到底部时的图像处理,一开始因为没有考虑好,导致直接把底部边框覆盖掉了;还有一个就是小车移动到边缘处的时候的处理,因为一开始先进行的图片渲染,然后才是数据的处理,导致小车移动到边缘处的时候,再按动AB两个键的时候导致无法移动,通过不间断打印含有小车信息的列表,观察数据的变化,最终排除了困难。

主模块如下:

import uos
import machine
import st7789 as st7789
from fonts import vga2_8x8 as font1
from fonts import vga1_16x32 as font2
import random
import framebuf
from time import sleep
from button import button

xAxis = machine.ADC(machine.Pin(28))
yAxis = machine.ADC(machine.Pin(29))

st7789_res = 0
st7789_dc  = 1
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)
print(uos.uname())
spi_sck=machine.Pin(2)
spi_tx=machine.Pin(3)
spi0=machine.SPI(0,baudrate=4000000, phase=1, polarity=1, sck=spi_sck, mosi=spi_tx)
#
#print(spi0)
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)
#car_image=open("/carar.bin", 'rb')
display.fill(st7789.BLACK)
display.text(font2, "Hello!", 72, 10)
display.text(font2, "Player", 72, 40)
display.text(font1, "Press any key to", 56, 100)
display.text(font2, "START", 80, 140)
display.text(font1, "www.luxiansheng.ltd", 44, 200)

#buttton Initialization
key_a=button(6)
key_b=button(5)
key_start=button(7)
key_select=button(8)

def any_key():
    while True:
        sleep(0.02)
        if key_a.value()==True or key_b.value()==True or key_start.value()==True or key_select.value()==True:
            print(key_a.value())
            return True
        else:
            return False
while True:
    display.text(font2, "     ", 80, 140)
    sleep(0.2)
    display.text(font2, "START", 80, 140)
    sleep(0.2)
    keytf=any_key()
    if keytf==True:
        break

class car:
    speed=8
    score=0
    obstacle_rect=[]
    car_rect=[64,176,88,216]
    wobs=0#随机数
    collision=False
    car_speed=8
    def __init__(self,speed=1):
        car.speed=speed
    def out_frame(self):
        for i in range(0,240,8):
            for j in range(0,240,8):
                display.fill_rect(j,i,8,8,st7789.BLACK)
        display.fill_rect(0,0,8,240,st7789.color565(0xff,0,0))
        display.fill_rect(0,0,240,8,st7789.color565(0xff,0,0))
        display.fill_rect(0,232,240,8,st7789.color565(0xff,0,0))
        display.fill_rect(232,0,8,240,st7789.color565(0xff,0,0))
        display.fill_rect(144,0,8,240,st7789.color565(0xff,0,0))
        display.text(font2, "Score", 152, 20)
        display.text(font2,str(car.score),176,52)
        display.text(font2,"Speed",152,84)
        display.text(font2,str(car.speed),176,116)        
        display.text(font2,"Auth",160,148)
        display.text(font2,"L&L",168,180)
    def obstacle_frame(self):
        car.wobs=random.randint(8,104)
        car.obstacle_rect=[8,8,car.wobs,23,car.wobs+39,8,143,23]
        
        
    def obstacle_move(self):
        if car.obstacle_rect[3]>=231 :
            if car.obstacle_rect[1]<232:
                display.fill_rect(car.obstacle_rect[0],car.obstacle_rect[1],car.wobs-8,car.speed,st7789.BLACK)
                display.fill_rect(car.obstacle_rect[4],car.obstacle_rect[5],104-car.wobs,car.speed,st7789.BLACK)
            else: 
                 return -1
        else:
            display.fill_rect(car.obstacle_rect[0],car.obstacle_rect[3]+1,car.wobs-8,car.speed,st7789.YELLOW)
            display.fill_rect(car.obstacle_rect[4],car.obstacle_rect[7]+1,104-car.wobs,car.speed,st7789.YELLOW)
            display.fill_rect(car.obstacle_rect[0],car.obstacle_rect[1],car.wobs-8,car.speed,st7789.BLACK)
            display.fill_rect(car.obstacle_rect[4],car.obstacle_rect[5],104-car.wobs,car.speed,st7789.BLACK)
        for i in range(1,8,2):
            car.obstacle_rect[i]+=car.speed
    def car_move(self,yg_direction):
        if yg_direction>0:
            car.car_rect[0]+=car.car_speed
            car.car_rect[2]+=car.car_speed
            if car.car_rect[0]<16 or car.car_rect[2]>136:
                car.car_rect[0]=120
                car.car_rect[2]=144
            if car.car_rect[0]>=8 and car.car_rect[2]<=144:
                display.fill_rect(car.car_rect[0]-car.car_speed,car.car_rect[1],24,40,st7789.BLACK)
                display.fill_rect(car.car_rect[0],car.car_rect[1],24,40,st7789.GREEN)
                '''display.fill_rect(car.car_rect[2],car.car_rect[1],car.car_speed,40,st7789.GREEN)
                display.fill_rect(car.car_rect[0],car.car_rect[1],car.car_speed,40,st7789.BLACK)
        '''
        elif yg_direction<0:
            car.car_rect[0]-=car.car_speed
            car.car_rect[2]-=car.car_speed
            if car.car_rect[0]<8 or car.car_rect[2]>144:
                car.car_rect[0]=8
                car.car_rect[2]=31
            if car.car_rect[0]>=8 and car.car_rect[2]<=144:
                display.fill_rect(car.car_rect[0]+car.car_speed,car.car_rect[1],24,40,st7789.BLACK)
                display.fill_rect(car.car_rect[0],car.car_rect[1],24,40,st7789.GREEN)
        #print(car.car_rect)
        '''
        if car.car_rect[0]<(8+car.car_speed):
                car.car_rect[0]=8+car.car_speed
                car.car_rect[2]=31+car.car_speed
        if car.car_rect[2]>(144-car.car_speed):
                car.car_rect[0]=120-car.car_speed
                car.car_rect[2]=144-car.car_speed
'''
    def car_obstacle(self):#小车与障碍物碰撞检测
        if car.obstacle_rect[1]<216 and car.obstacle_rect[3]>176:
            if car.car_rect[0]<car.wobs or car.car_rect[0]>(16+car.wobs):
                car.collision=True
if __name__=="__main__":
    pause=False
    ad=car()
    ad.out_frame()
    display.fill_rect(car.car_rect[0],car.car_rect[1],24,40,st7789.GREEN)
    while True:
        if car.collision==True:
            print(4545)
            break
        ad.obstacle_frame()
        display.text(font2,"  ",176,52)
        display.text(font2,str(car.score),176,52)
        while True:
            if car.collision==True:
                break
            ad.car_obstacle()
            sleep(0.02)
            if key_a.value()==True:
                ad.car_move(5)
            if key_b.value()==True:
                ad.car_move(-5)
            ad.obstacle_move()
            #print(car.obstacle_rect)
            if car.obstacle_rect[1]>231:
                car.score+=1
                break
    while True:
        display.text(font2,"GameOver",10,104)
        sleep(0.2)
        display.text(font2,"        ",10,104)

button模块如下:#对按键进行初始化

import time
from machine import Pin

class button:
    def __init__(self, pin, callback=None, trigger=Pin.IRQ_RISING, min_ago=200):
        #print("button init")
        self.callback = callback
             
        self.min_ago = min_ago
        self._next_call = time.ticks_add(time.ticks_ms(), self.min_ago)

        self.pin = Pin(pin, Pin.IN, Pin.PULL_UP)

        self.pin.irq(trigger=trigger, handler=self.debounce_handler)

        self._is_pressed = False

    def call_callback(self, pin):
        #print("call_callback")
        self._is_pressed = True  
        if self.callback is not None:
            self.callback(pin)

    def debounce_handler(self, pin):
        #print("debounce")
        if time.ticks_diff(time.ticks_ms(), self._next_call) > 0:
            self._next_call = time.ticks_add(time.ticks_ms(), self.min_ago)
            self.call_callback(pin)

    def value(self):
        p = self._is_pressed
        self._is_pressed = False
        return p

然后需要导入st7789驱动

最终运行主模块,实现游戏的成功运行。

四、成果展示

1、开始界面如下,按任意键进入游戏,本项目没有加入速度难度等变量的自定义:

FqxRi5q_Al_EF6H_BsVu-ndyIxMk

2、进入游戏后,障碍物会随机刷新,通过AB两个按键来实现小车的左右移动,当触碰到边缘上时,通过对小车列表数据的检测,小车将无法向边缘方向移动,当小车每次通过障碍得分Score上的数据将会加一,如果小车触碰到障碍物,游戏结束。

FhLIYMZYWdahelABCg-6ORp-UhCFFrgCkEVR40z7XlzLkiSt2hL7pRvrFvEjQeUXiEEZiOL3iYqhsuunsSkzFnIa38o-lVrJctHwGx-JRuZNU3yv

此项目只是实现一个比较简单的游戏,还有许多细节需要打磨,例如加入难度的控制,游戏结束跳转到主页面,历史最高分数的记录等等,我会接着去进行优化。

附件下载
项目源码.rar
团队介绍
中央民族大学18级电子卢国洋
团队成员
卢国洋
中央民族大学18级电子信息18040089
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号