2022寒假在家练 - 基于RP2040实现《坦克大战》游戏制作
摘要:本项目依托2022寒假在家练,基于RP2040GameKit平台,实现了坦克大战游戏的制作。本项目通过LCD屏幕、按键和四向摇杆实现了游戏的游玩,并调用蜂鸣器实现了游戏配乐与游戏音效,取得了良好的游戏体验,具有一定的娱乐价值。
项目介绍
本项目依托2022寒假在家练,基于RP2040GameKit平台,实现了坦克大战游戏的制作。本项目通过LCD屏幕、按键和四向摇杆实现了游戏的游玩,并调用蜂鸣器实现了游戏配乐与游戏音效,取得了良好的游戏体验,具有一定的娱乐价值。
项目任务
-
设计或移植一款经典的游戏(硬禾学堂上已经实现的贪吃蛇等游戏除外),通过LCD屏显示,通过按键和四向摇杆控制游戏的动作;
-
在游戏中要通过蜂鸣器播放背景音乐;
设计思路
本项目设计思路为,围绕RP2040GAMEKIT,首先对RP2040的板载硬件进行实验使用,初步掌握板载的IO硬件以及RP2040能够实现的功能与实际性能。再根据硬件的具体功能,实现游戏设计。在设计期间,穿插硬件调研与资料搜集,案例搜集与代码实现两个过程,以辅助硬件实验与游戏设计进行。游戏设计的主要思路如下:
硬件与驱动介绍
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键即可重新开始游戏。玩家可根据自己的需求,选择游戏的开始与结束。
欢迎与重新开始界面图片展示
拓展功能:在游玩过程当中,如玩家觉得游戏较为困难,可按Start键重新载入包含新地图的游戏。
游戏实际内容
本项目设计的游戏为双人对战游戏,由两位玩家进行回合制对战。
游戏规则
每一位玩家通过控制自己的坦克击毁敌方的坦克,率先击毁敌方坦克的一方获得胜利。
游戏操作
每一位玩家,可通过调整炮弹的发射力度与发射角度,进行炮弹发射调节。调节方式是使用摇杆进行上下摇动调节,通过B键可以在发射力度与发射角度之间进行切换。在游戏过程当中,每一位玩家的炮弹发射信息将在各自坦克位置的正上方进行显示,用以玩家参考发射状态。在调节完成后,按A键进行炮弹发射。若击中敌方,则玩家获得胜利。若未击中,则切换为下一位玩家进行操作。
游戏内容图片展示
游戏音乐部分
游戏音乐部分主要分为背景音乐与游戏特效音乐两个部分。
背景音乐
本项目依照游戏场景设计了三种背景音乐,分别为欢迎界面BGM、游戏战斗BGM与游戏结束BGM,背景音乐的旋律如下表格所示:
说明:在对应的场景下,本项目采用重复循环式播放每一段旋律作为背景音乐。
游戏特效音乐
本项目依照游戏功能,设计了两类游戏特效音乐,分别是炮弹发射音效与坦克击毁音效,特效音乐如下表格所示:
说明:特效音乐在玩家进行相应操作后进行播放。
音乐操作
本项目为游戏音乐设立了开关,玩家可在游戏过程当中,使用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)