基于RP2040实现坦克大战游戏制作
本项目依托2022寒假在家练,基于RP2040GameKit平台,实现了坦克大战游戏的制作。本项目通过LCD屏幕、按键和四向摇杆实现了游戏的游玩,并调用蜂鸣器实现了游戏配乐与游戏音效,取得了良好的游戏体验,具有一定的娱乐价值。
标签
嵌入式系统
MicroPython
RP2040
2022寒假在家练
Iccccy
更新2022-03-03
北京理工大学
827

内容介绍

2022寒假在家练 - 基于RP2040实现《坦克大战》游戏制作

摘要:本项目依托2022寒假在家练,基于RP2040GameKit平台,实现了坦克大战游戏的制作。本项目通过LCD屏幕、按键和四向摇杆实现了游戏的游玩,并调用蜂鸣器实现了游戏配乐与游戏音效,取得了良好的游戏体验,具有一定的娱乐价值。

项目介绍

本项目依托2022寒假在家练,基于RP2040GameKit平台,实现了坦克大战游戏的制作。本项目通过LCD屏幕、按键和四向摇杆实现了游戏的游玩,并调用蜂鸣器实现了游戏配乐与游戏音效,取得了良好的游戏体验,具有一定的娱乐价值。

项目任务

  1. 设计或移植一款经典的游戏(硬禾学堂上已经实现的贪吃蛇等游戏除外),通过LCD屏显示,通过按键和四向摇杆控制游戏的动作;

  2. 在游戏中要通过蜂鸣器播放背景音乐;

设计思路

本项目设计思路为,围绕RP2040GAMEKIT,首先对RP2040的板载硬件进行实验使用,初步掌握板载的IO硬件以及RP2040能够实现的功能与实际性能。再根据硬件的具体功能,实现游戏设计。在设计期间,穿插硬件调研与资料搜集,案例搜集与代码实现两个过程,以辅助硬件实验与游戏设计进行。游戏设计的主要思路如下:

FmiNLPEU2LtURRwCpnteTUGlZRwk

硬件与驱动介绍

RP2040GAMEKIT是一款嵌入式系统的学习平台,其包含的主要特点如下:

采用树莓派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连接器用于供电、程序下载

硬件驱动:

  • 屏幕驱动:ST7789 LCD驱动(含两类:C语言库驱动(刷新屏幕);python库驱动(激活屏幕))

  • 按键驱动:my_input.py

  • 蜂鸣器驱动:buzzer_music.py

游戏功能及图片展示

本项目实现的主要功能如下:

欢迎与重新开始界面

本项目实现人性化的游戏设计,为游戏设计了开始欢迎界面,按Start键可进入游戏。在一方获得胜利之后,会进入游戏获胜界面,即重新开始界面,按B键即可重新开始游戏。玩家可根据自己的需求,选择游戏的开始与结束。

欢迎与重新开始界面图片展示

Fn7-eOBzurlJCeIznEhVpjvWwka1

Fqv7YOsXXDG-8OZ8OKu7KPPy-lfY

拓展功能:在游玩过程当中,如玩家觉得游戏较为困难,可按Start键重新载入包含新地图的游戏。

游戏实际内容

本项目设计的游戏为双人对战游戏,由两位玩家进行回合制对战。

游戏规则

每一位玩家通过控制自己的坦克击毁敌方的坦克,率先击毁敌方坦克的一方获得胜利。

游戏操作

每一位玩家,可通过调整炮弹的发射力度与发射角度,进行炮弹发射调节。调节方式是使用摇杆进行上下摇动调节,通过B键可以在发射力度与发射角度之间进行切换。在游戏过程当中,每一位玩家的炮弹发射信息将在各自坦克位置的正上方进行显示,用以玩家参考发射状态。在调节完成后,按A键进行炮弹发射。若击中敌方,则玩家获得胜利。若未击中,则切换为下一位玩家进行操作。

游戏内容图片展示

FpbvtseAgaD8z8094kRrO55aIghN

游戏音乐部分

游戏音乐部分主要分为背景音乐与游戏特效音乐两个部分。

背景音乐

本项目依照游戏场景设计了三种背景音乐,分别为欢迎界面BGM、游戏战斗BGM与游戏结束BGM,背景音乐的旋律如下表格所示:

FrsDRr6L8KAE_Rew2X7J-iaWPRpb

说明:在对应的场景下,本项目采用重复循环式播放每一段旋律作为背景音乐。

游戏特效音乐

本项目依照游戏功能,设计了两类游戏特效音乐,分别是炮弹发射音效与坦克击毁音效,特效音乐如下表格所示:

Flobz6YiTcTKooIqn594uOYJycqO

说明:特效音乐在玩家进行相应操作后进行播放。

音乐操作

本项目为游戏音乐设立了开关,玩家可在游戏过程当中,使用Select键进行游戏音乐的开关。

主要代码段及其说明

本项目主要代码段如下,说明见代码段注释。

游戏主控代码

游戏逻辑

def run_game():
     
     while True:
         global key_mode, game_state,WinPage
           
         #坦克主体绘制
         if game_state not in ['game_over_1','game_over_2']:
             tank1.draw ()
             tank2.draw ()
         #地图背景绘制
         if game_state=='start':
             display.fill(SKY_COLOR)
             ground.draw()
             game_state='player1'
         #炮弹动画绘制
         if (game_state == "player1fire" or game_state == "player2fire"):
             shell.draw()
             utime.sleep(0.1)
         #炮弹发射参数栏绘制
         if (game_state == "player1" or game_state == "player1fire"):
             display.text(font_text,"Player 1", 10, 10,TEXT_COLOR)
             if (key_mode == "power"):
                 display.text(font_text,"Power:{:>3d}".format(tank1.get_gun_power())+"%", 10, 20,TEXT_COLOR_ACTIVE)
             else:
                 display.text(font_text,"Power:{:>3d}".format(tank1.get_gun_power())+"%", 10, 20,TEXT_COLOR)
             if (key_mode == "angle"):
                 display.text(font_text,"Angle:{:>3d}".format(tank1.get_gun_angle())+' ', 10, 30,TEXT_COLOR_ACTIVE)
 ​
             else:
                 display.text(font_text,"Angle:{:>3d}".format(tank1.get_gun_angle())+' ', 10, 30,TEXT_COLOR)
         if (game_state == "player2" or game_state == "player2fire"):
             display.text(font_text,"Player 2", 150, 10,TEXT_COLOR)
             if (key_mode == "power"):
                 display.text(font_text,"Power:{:>3d}".format(tank2.get_gun_power())+"%", 150, 20,TEXT_COLOR_ACTIVE)
             else:
                 display.text(font_text,"Power:{:>3d}".format(tank2.get_gun_power())+"%", 150, 20,TEXT_COLOR)
 ​
             if (key_mode == "angle"):
                 display.text(font_text,"Angle:{:>3d}".format(tank2.get_gun_angle())+' ', 150, 30,TEXT_COLOR_ACTIVE)
 ​
             else:
                 display.text(font_text,"Angle:{:>3d}".format(tank2.get_gun_angle())+' ', 150, 30,TEXT_COLOR)
                 
         if (game_state == "game_over_1" and WinPage):
             display.fill(st7789.BLACK)
             display.text(font_text_big,"Game Over", 50, 20,TEXT_COLOR)
             display.text(font_text_big,"Player 1", 60, 80,CELE_COLOR)
             display.text(font_text_big,"Wins!", 80, 110,CELE_COLOR)
             display.text(font_text_big,"PRESS B", 60, 175,TEXT_COLOR)
             display.text(font_text_big,"TO CONTINUE.", 30, 200,TEXT_COLOR)
             WinPage=0
         if (game_state == "game_over_2" and WinPage):
             display.fill(st7789.BLACK)
             display.text(font_text_big,"Game Over", 50, 20,TEXT_COLOR)
             display.text(font_text_big,"Player 2", 60, 80,CELE_COLOR)
             display.text(font_text_big,"Wins!", 80, 110,CELE_COLOR)
             display.text(font_text_big,"PRESS B", 60, 175,TEXT_COLOR)
             display.text(font_text_big,"TO CONTINUE.", 30, 200,TEXT_COLOR)
             WinPage=0
 ​
 ​
         #炮弹发射流程实现
         if (game_state == 'player1'):
             player1_fired = player_keyboard("left")
 ​
             if (player1_fired == True):
                 #发射过程实现
                 gun_positions = tank1.calc_gun_positions()
                 start_shell_pos = (gun_positions[3][0],gun_positions[3][1]+2)
                 shell.set_start_position(start_shell_pos)
                 shell.set_current_position(start_shell_pos)
                 global key_mode, game_state
                 game_state = 'player1fire'
                 musicPlay.shotSoundPlay()
                 print(game_state)
                 shell.set_angle(math.radians (tank1.get_gun_angle()))
                 shell.set_power(tank1.get_gun_power() / 40)
                 shell.set_time(0)
         if (game_state == 'player1fire'):
        #发射后游戏逻辑实现
             shell.update_shell_position ("left")
             #检测射击状态
             shell_value = detect_hit("left")
             #坦克状态
             if (shell_value >= 20):
                 game_state = 'game_over_1'
             elif (shell_value >= 10):
                 key_mode = "angle"
                 game_state = 'player2'
         #player2逻辑同player1  
         if (game_state == 'player2'):
             player2_fired = player_keyboard("right")
             if (player2_fired == True):
                 gun_positions = tank2.calc_gun_positions ()
                 start_shell_pos = (gun_positions[3][0],gun_positions[3][1]+2)
                 shell.set_start_position(start_shell_pos)
                 shell.set_current_position(start_shell_pos)
                 game_state = 'player2fire'
                 musicPlay.shotSoundPlay()
                 shell.set_angle(math.radians (tank2.get_gun_angle()))
                 shell.set_power(tank2.get_gun_power() / 40)
                 shell.set_time(0)
         if (game_state == 'player2fire'):
             shell.update_shell_position ("right")
             shell_value = detect_hit("right")
             if (shell_value >= 20):
                 game_state = 'game_over_2'
             elif (shell_value >= 10):
                 game_state = 'player1'
                 key_mode = "angle"
         #游戏结束界面
         if (game_state == 'game_over_1' or game_state == 'game_over_2'):
             global bgmTimer
             bgmTimer.deinit()
             if (my_input.B()) :
                 # Reset position of tanks and terrain
                 setup()
             musicPlay.overPlay()
         #地图重载入
         if my_input.Start():
             setup()
         #音效开关
         if (my_input.Select()==1):
             musicPlay.switch()
 

炮弹逻辑检测

def detect_hit (left_right):
     #获取炮弹位置
     (shell_x, shell_y) = shell.get_current_position()
     
     #设置击中区域
     if (left_right == "left"):      
         shell_x += 2
     else:
         shell_x -= 2
     shell_y += 2
     offset_position = (math.floor(shell_x), math.floor(shell_y))
     
     #检测炮弹位置(炮弹绘制)
     if (shell_x > width or shell_x <= 0 or shell_y >= height):
         shell.shell_hide()
         return 10
     if (shell_y < 1):
         if (shell_y < 0-height):
             shell.shell_hide()
             return 10
         shell.shell_hide()
         return 1
         
     #计算后一帧位置
     shell_x=offset_position[0]
     shell_y=offset_position[1]
     tank1_pos=tank1.position
     tank2_pos=tank2.position
     land_pos=ground.get_land_height()
     if (shell_y >= land_pos[shell_x]):
         shell.shell_hide()
         return 11
     
     xscale=15
     y_up_scale=0
     y_down_scale=15
     
     #击中逻辑
     if (left_right == 'left' and tank2_pos[0]+3<=shell_x <= tank2_pos[0]+xscale and tank2_pos[1]-y_down_scale<=shell_y <= tank2_pos[1]+y_up_scale):
         musicPlay.shotedSoundPlay()
         return 20
     if (left_right == 'right' and tank1_pos[0]<=shell_x <= tank1_pos[0]+xscale-3 and tank1_pos[1]-y_down_scale<=shell_y <= tank1_pos[1]+y_up_scale):
         musicPlay.shotedSoundPlay()
         return 20
     
     return 0

地图背景实现

class Land:
     
     def __init__ (self, display, ground_color):
         self.display = display
         self.ground_color = ground_color
         self.screen_size = (240, 240)
         self.setup()
         
     def setup(self):
         
         
         self.land_y_positions = [0] *240
         
         #随机地图生成
         left_tank_x_position = random.randint (10,int(self.screen_size[0]/2)-30)
         right_tank_x_position = random.randint (int(self.screen_size[0]/2)+30,self.screen_size[0]-40)
         
         self.tank1_position = (left_tank_x_position,0)
         self.tank2_position = (right_tank_x_position,0)
         
         current_land_x = 0
         next_land_x = 0 + LAND_CHUNK_SIZE
         current_land_y = random.randint (50,240-20)
         self.land_y_positions[current_land_x] = current_land_y
         while (current_land_x < self.screen_size[0]):
             if (current_land_x == left_tank_x_position):
                 self.tank1_position = (current_land_x, int(current_land_y))
                 for i in range (0, LAND_TANK_SIZE):
                     self.land_y_positions[current_land_x] = int(current_land_y)
                     current_land_x += 1
                 continue
             elif (current_land_x == right_tank_x_position):
                 self.tank2_position = (current_land_x, int(current_land_y))
                 for i in range (0, LAND_TANK_SIZE):
                     self.land_y_positions[current_land_x] = int(current_land_y)
                     current_land_x += 1
                 continue
             
             # 坦克位置生成
             if (current_land_x < left_tank_x_position and current_land_x + LAND_CHUNK_SIZE >= left_tank_x_position):
                 next_land_x = left_tank_x_position
             elif (current_land_x < right_tank_x_position and current_land_x + LAND_CHUNK_SIZE >= right_tank_x_position):
                 next_land_x = right_tank_x_position
             elif (current_land_x + LAND_CHUNK_SIZE > self.screen_size[0]):
                 next_land_x = self.screen_size[0] 
             else:
                 next_land_x = current_land_x + LAND_CHUNK_SIZE
                 
             next_land_y = current_land_y + random.randint(0-LAND_MAX_CHG,LAND_MAX_CHG)
             if (next_land_y > self.screen_size[1]):   
                 next_land_y = self.screen_size[1]
             if (next_land_y < LAND_MIN_Y):
                 next_land_y = LAND_MIN_Y
 ​
             if (next_land_y == current_land_y or next_land_x == current_land_x):
                 y_delta = 0
             else:
                 y_delta = (next_land_y - current_land_y) / (next_land_x - current_land_x)
             for i in range (current_land_x, next_land_x):
                 current_land_y += y_delta
                 self.land_y_positions[current_land_x] = int(current_land_y)
                 current_land_x += 1
             
     #坦克位置返回
     def get_tank1_position(self):
         return self.tank1_position
         
     def get_tank2_position(self):
         return self.tank2_position
     #位置高度获取
     def get_land_height(self):
         return self.land_y_positions
     #地图绘制
     def draw (self):
         current_land_x = 0
         for this_pos in self.land_y_positions:
             for this_y in range (self.land_y_positions[current_land_x], self.screen_size[1]):
                 self.display.pixel(current_land_x, int(this_y),self.ground_color)
             current_land_x += 1

坦克对象实现

class Tank:
     
     def __init__(self, display, left_right, tank_color,background_color):
         self.display = display
         self.left_right = left_right
         self.tank_color = tank_color
         self.background_color=background_color
         self.position = (0,0)
         #初始角度设置
         if (left_right == "left"):
             self.gun_angle = 10
         else :
             self.gun_angle = 50
         #初始力度设置
         self.gun_power = 40
         self.post_gun_position=self.calc_gun_positions()
     #设置位置  
     def set_position (self, position):
         self.position = position
     #获取位置
     def get_position (self):
         return self.position
     #设置炮管角度
     def set_gun_angle (self, angle):
         self.gun_angle = angle
     #改变炮管角度
     def change_gun_angle (self, amount):
         self.gun_angle += amount
         if self.gun_angle > 85:
             self.gun_angle = 85
         if self.gun_angle < -20:
             self.gun_angle = -20
     #获取炮管角度  
     def get_gun_angle (self):
         return self.gun_angle
     #设置力度    
     def set_gun_power (self, power):
         self.gun_power = power
     #改变力度  
     def change_gun_power (self, amount):
         self.gun_power += amount
         if self.gun_power > 100:
             self.gun_power = 100
         if self.gun_power < 10:
             self.gun_power = 10
     #获取力度
     def get_gun_power (self):
         return self.gun_power
         
     
 ​
     #绘制坦克
     def draw (self):
 ​
         # 履带
         self.display.hline(self.position[0]+6, self.position[1]-10, 20,self.tank_color)
         self.display.hline(self.position[0]+5, self.position[1]-9, 22,self.tank_color)
         self.display.hline(self.position[0]+4, self.position[1]-8, 24,self.tank_color)
         self.display.hline(self.position[0]+3, self.position[1]-7, 26,self.tank_color)
         self.display.hline(self.position[0]+2, self.position[1]-6, 28,self.tank_color)
         self.display.hline(self.position[0]+1, self.position[1]-5, 30,self.tank_color)
         self.display.hline(self.position[0]+2, self.position[1]-4, 28,self.tank_color)
         self.display.hline(self.position[0]+3, self.position[1]-3, 26,self.tank_color)
         self.display.hline(self.position[0]+4, self.position[1]-2, 24,self.tank_color)
         self.display.hline(self.position[0]+5, self.position[1]-1, 22,self.tank_color)
         self.display.hline(self.position[0]+6, self.position[1], 20,self.tank_color)
         
         # 主体
         self.display.rect(self.position[0]+7, self.position[1]-13, 18, 3,self.tank_color)
 ​
         self.display.hline(self.position[0]+8, self.position[1]-14, 16,self.tank_color)
         self.display.hline(self.position[0]+6, self.position[1]-15, 20,self.tank_color)
         self.display.hline(self.position[0]+8, self.position[1]-16, 16,self.tank_color)
 ​
         # 炮管
         self.erase_gun(self.post_gun_position)
         self.draw_gun(self.calc_gun_positions())
         self.post_gun_position=self.calc_gun_positions()
 ​
     #擦除炮管
     def erase_gun(self, gun_positions):
         if (self.left_right == "left"):
             start_x = gun_positions[1][0]
             start_y = gun_positions[1][1]
             end_x = gun_positions[2][0]
             end_y = gun_positions[2][1]
         else :
             start_x = gun_positions[2][0]
             start_y = gun_positions[2][1]
             end_x = gun_positions[1][0]
             end_y = gun_positions[1][1]
       
         if (end_y == start_y or end_x == start_x):
             y_delta = 0
         else:
             y_delta = (end_y - start_y) / (end_x - start_x)
         current_x = int(start_x)
         current_y = int(start_y)
         for x in range (start_x, end_x):
             for y_offset in range (0, GUN_DIAMETER):
               
                 
                 self.display.pixel(current_x, int(current_y+y_offset),self.background_color)
             current_x += 1
             current_y += y_delta
     #绘制炮管        
     def draw_gun(self, gun_positions):
         if (self.left_right == "left"):
             start_x = gun_positions[1][0]
             start_y = gun_positions[1][1]
             end_x = gun_positions[2][0]
             end_y = gun_positions[2][1]
         else :
             start_x = gun_positions[2][0]
             start_y = gun_positions[2][1]
             end_x = gun_positions[1][0]
             end_y = gun_positions[1][1]
     
         if (end_y == start_y or end_x == start_x):
             y_delta = 0
         else:
             y_delta = (end_y - start_y) / (end_x - start_x)
         current_x = int(start_x)
         current_y = int(start_y)
         for x in range (start_x, end_x):
             for y_offset in range (0, GUN_DIAMETER):
                 self.display.pixel(current_x, int(current_y+y_offset),self.tank_color)
             current_x += 1
             current_y += y_delta
         
     #计算炮管位置
     def calc_gun_positions (self):
        (xpos, ypos) = self.position
         if (self.left_right == "right"):
             gun_start_pos_top = (xpos+6, ypos-15)
         else:
             gun_start_pos_top = (xpos+26, ypos-15)
         relative_angle = self.gun_angle
         if (self.left_right == "right"):
             relative_angle = 180 - self.gun_angle
         angle_rads = relative_angle * (math.pi / 180)
         
         gun_vector = (math.cos(angle_rads), math.sin(angle_rads) * -1)
         
         
         if (self.left_right == "right"):
             temp_angle_rads = math.radians(relative_angle - 90)
         else:
             temp_angle_rads = math.radians(relative_angle + 90)
         temp_vector = (math.cos(temp_angle_rads), math.sin(temp_angle_rads) * -1)
 ​
         
         gun_start_pos_bottom = (gun_start_pos_top[0] + temp_vector[0] * GUN_DIAMETER, gun_start_pos_top[1] + temp_vector[1] * GUN_DIAMETER)
         
         gun_positions = [
             gun_start_pos_bottom,
             gun_start_pos_top,
            (gun_start_pos_top[0] + gun_vector[0] * GUN_LENGTH, gun_start_pos_top[1] + gun_vector[1] * GUN_LENGTH),
            (gun_start_pos_bottom[0] + gun_vector[0] * GUN_LENGTH, gun_start_pos_bottom[1] + gun_vector[1] * GUN_LENGTH),
        ]
         
         return gun_positions

 

炮弹对象实现

class Shell:
     
     def __init__ (self, display, shell_color,background_color):
         self.display = display
         self.shell_color = shell_color
         self.background_color = background_color
         self.start_position = (0,0)
         self.current_position = (0,0)
         self.power = 1
         self.angle = 0
         self.time = 0
         self.post_position=self.current_position
         self.shell_size=2
         
     def set_start_position(self, position):
         self.start_position = position
  
     def get_start_position(self):
         return self.start_position
         
     def set_current_position(self, position):
         self.current_position = position
         
     def get_current_position(self):
         return self.current_position
         
     def set_angle(self, angle):
         self.angle = angle
         
     def set_power(self, power):
         self.power = power
     
     def set_time(self, time):
         self.time = time
     #绘制炮弹  
     def draw (self):
         (xpos, ypos) = self.current_position
         (postXpos,postYpos)=self.post_position
         self.display.rect(int(postXpos),int(postYpos),self.shell_size,self.shell_size,self.background_color)
         self.display.rect(int(xpos), int(ypos), self.shell_size, self.shell_size,self.shell_color)
         self.post_position=self.current_position
     #隐藏炮弹轨迹    
     def shell_hide(self):
         (postXpos,postYpos)=self.post_position
         self.display.rect(int(postXpos),int(postYpos),self.shell_size,self.shell_size,self.background_color)
     #更新炮弹位置    
     def update_shell_position (self, left_right):
         
         init_velocity_y = self.power * math.sin(self.angle)
         
        
         if (left_right == 'left'):
             init_velocity_x = self.power * math.cos(self.angle)
         else:
             init_velocity_x = self.power * math.cos(math.pi - self.angle)
             
         #设置重力参数
         GRAVITY_CONSTANT = 0.008
         #设置距离敏感程度
         DISTANCE_CONSTANT = 1.5
         #设置风阻系数
         wind_value = 1
         
         shell_x = self.start_position[0] + init_velocity_x * self.time * DISTANCE_CONSTANT
         shell_y = self.start_position[1] + -1 * ((init_velocity_y * self.time) - (0.5 * GRAVITY_CONSTANT * self.time * self.time * wind_value))
         
         self.current_position = (shell_x, shell_y)
            
         self.time += 4

键盘操控实现

def player_keyboard(left_right):
     global key_mode
     
     #控制切换
     if (my_input.B()==1) :
         if key_mode == "angle":
             key_mode = "power"
         else:
             key_mode = "angle"
     utime.sleep(0.01)
     
     #炮弹发射
     if (my_input.A()==1) :
         return True
     utime.sleep(0.1)
     # 炮管角度调整
     adjustAngle=3
     if (my_input.y()==-1) :
         if (key_mode == "angle" and left_right == 'left'):
             tank1.change_gun_angle(adjustAngle)
         elif (key_mode == "angle" and left_right == 'right'):
             tank2.change_gun_angle(adjustAngle)
         elif (key_mode == "power" and left_right == 'left'):
             tank1.change_gun_power(adjustAngle)
         elif (key_mode == "power" and left_right == 'right'):
             tank2.change_gun_power(adjustAngle)
     # 炮管能量调整
     if (my_input.y()==1) :
         if (key_mode == "angle" and left_right == 'left'):
             tank1.change_gun_angle(-adjustAngle)
         elif (key_mode == "angle" and left_right == 'right'):
             tank2.change_gun_angle(-adjustAngle)
         elif (key_mode == "power" and left_right == 'left'):
             tank1.change_gun_power(-adjustAngle)
         elif (key_mode == "power" and left_right == 'right'):
             tank2.change_gun_power(-adjustAngle)
 ​
     return False

音效对象实现

class musicPlay:
     def __init__(self):
         self.play=1
         self.welcomeMusic="0 A#6 1 43;1 C#7 1 43;2 B6 1 43;3 D7 1 43;4 A#6 1 43;5 C#7 1 43;6 B6 1 43;7 G6 1 43;8 B6 1 43;9 C#7 1 43;10 A6 1 43;11 D7 1 43"
 ​
         self.backGroundMusic="0 C5 1 43;1 A#4 1 43;3 G4 1 43;4 C5 1 43;7 G4 1 43;8 C5 1 43;10 A#4 1 43;11 G4 1 43;12 A4 1 43;13 B4 1 43;14 A#4 1 43;15 G#4 1 43;15 G4 1 43;6 A4 1 43"
 ​
         self.shotedSound="0 D3 1 43"
 ​
         self.shotSound="0 C3 1 43"
 ​
         self.overMusic="0 D#5 1 43;0 C#5 1 43;2 D#5 1 43;2 C#5 1 43;1 F5 1 43;3 D5 1 43;4 D#5 1 43;4 C#5 1 43;6 D#5 1 43;6 C#5 1 43;5 A#4 1 43;7 E5 1 43;8 C#5 1 43;8 D#5 1 43;9 A5 1 43;10 C#5 1 43;10 D#5 1 43;11 F#5 1 43"
         
         self.welcomeMusicPlay=music(self.welcomeMusic,pins=[Pin(23)])
         self.backGroundMusicPlay = music(self.backGroundMusic, pins=[Pin(23)])
         self.overMusicPlay = music (self.overMusic,pins=[Pin(23)])
     #游戏背景音乐    
     def bgmPlay(self):
         if self.play:
             self.backGroundMusicPlay.tick()
     #欢迎界面音乐
     def welPlay(self):
         if self.play:
             self.welcomeMusicPlay.tick()
             sleep(0.1)
     #游戏结束界面音乐
     def overPlay(self):
         if self.play:
             self.overMusicPlay.tick()
             sleep(0.1)
     #炮弹发射音效
     def shotSoundPlay(self):
         if self.play:
             sound=music(self.shotSound,pins=[Pin(23)])
             sound.tick()
             sleep(0.1)
             sound.stop()
     #坦克击毁音效
     def shotedSoundPlay(self):
         if self.play:
             sound=music(self.shotedSound,pins=[Pin(23)])
             sound.tick()
             sleep(0.1)
             sound.stop()
     #音乐停止
     def stop(self):
         self.welcomeMusicPlay.stop()
     #音效开关
     def switch(self):
         if self.play:
             self.play=0
         else:
             self.play=1
         self.stop()

遇到的主要难题及解决方法

问题1:屏幕刷新速度慢,画面游戏画面播放不流畅

解决:更换带有ST7789 LCD驱动C语言驱动的MicroPython固件

问题2:炮弹轨迹与炮管移动轨迹的残留

解决: 使用背景色对上一帧轨迹进行填充

问题3:炮弹击中逻辑检测

解决:设计坦克的击中区域,对炮弹的每一帧进行计算,判断是否到达击中区域。

参考资料

russhughes/st7789_mpy: Fast MicroPython driver for ST7789 display module written in C (github.com)

EETree-git/RP2040_Game_Kit: 基于树莓派RP2040的游戏机 (github.com)

Creating a game for Raspberry Pi Pico Display Pack (Tank Game) - Electronic and software projects from Penguintutor.com

基于树莓派RP2040的嵌入式系统学习平台 - 电子森林 (eetree.cn)

Raspberry Pi Documentation - MicroPython

附件下载

release.zip
实现代码与固件
使用固件.zip
开发游戏使用的固件
游戏代码.zip
游戏代码

团队介绍

团队是一支只有一个人的小白团队~

评论

0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号