基于树莓派RP2040的嵌入式系统学习平台完成复古打砖块小游戏移植
本项目是用基于树莓派RP2040的嵌入式系统学习平台完成的打方块小游戏移植,用到了电子森林提供的库函数和驱动,通过microPython编程实现了基本功能,主要参考了电子森林提供的贪吃蛇小游戏例程
标签
嵌入式系统
显示
2022寒假在家练
Next
更新2022-03-03
北京理工大学
741

内容介绍

项目介绍

我做的项目是用基于树莓派RP2040的嵌入式系统学习平台完成的打方块小游戏移植,用到了电子森林提供的库函数和驱动,通过microPython编程实现了基本功能,主要参考了电子森林提供的贪吃蛇小游戏例程,学到了许多图像化信息显示的知识。

 

设计思路

游戏开始后,球会自己运动,同时我们可以通过控制摇杆来实现球拍的左右运动,根据摇杆位移不同,球拍移动速度不同,当球接触到球拍或墙面或方块,球的运动方向会发生相应变化,如果碰到了方块,方块就会消失,所有方块都消失后游戏胜利,如果球碰到了地面则游戏失败。通过按键A控制BGM的开和关,图中没有画出。

游戏程序流程图如下所示

FsHaksFA1gd07JBx4oKS0Es8xhPm

硬件介绍

RP2040 是 Raspberry Pi 的首款微控制器。它为微控制器领域带来了我们高性能、低成本和易用性的标志性价值。在我们用到的树莓派Pico中,我所做的项目主要用到了SPI接口,控制器为ST778240*240分辨率的彩色IPS LCD,用四向摇杆控制球拍的运动,用轻触按键作为bgm的开关控制按键。

 

实现的功能及图片展示

本游戏是打方块小游戏,玩家通过控制摇杆来实现球拍左右移动,摇杆偏离中心越远,球拍运动速度越快;球会在屏幕中自由运动,当碰到方块或墙壁或球拍时会反弹,如果球碰到了方块,方块就会被打掉,在屏幕上消失,同时分数会增加100,玩家需要控制球拍移动来接球,当所有的方块都被打掉后,游戏就会胜利,停几秒后重新开始;如果没有接住球,让球落到了地上,就会被判为失败,停几秒游戏重新开始。

 

碰撞前后对比:

Fru6tXtNcibljo9THc3rRT3zFzpX

FkpSnVNpjv6_Yc9gIK58uMxmUDge

分数记录:

Fj-piFfa8DcmcOjUd1W2cpnzcBX8

游戏胜利:

FhhmvaPZzSRhQdidY26lp53P1lQS

游戏失败:

FrsLvJT2a4IR9bYBjsIJVUswyQFv

图片能展示内容有限,具体游戏过程在视频中体现

 

主要代码讲解

屏幕初始化

st7789_res = 0
st7789_dc  = 1
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)
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)
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)
display.fill(st7789.BLACK)

此部分内容在电子森林的课上有讲解,贪吃蛇例程也有具体使用,所以只要搬过来稍加改动就可以使用了。

 

球拍类

class Ballpat():
    def __init__(self, pat_length = 40, pat_width = 15, pat_x = disp_width/2, pat_y = disp_height - 20, step = 1):
        self.pat_length = int(pat_length)
        self.pat_width = int(pat_width)
        self.pat_x = int(pat_x)
        self.pat_y = int(pat_y)
        self.step = int(step)
        display.fill_rect(self.pat_x, self.pat_y, self.pat_length, self.pat_width, st7789.BLUE)
            
    def dir_select(self):
        yValue = yAxis.read_u16()
        if yValue <= 25000:
            yStatus = "up"
            if yValue >= 15000: self.step = 2
            elif yValue >= 5000: self.step = 4
            else: self.step = 6
            if self.pat_x - self.step >= 0:
                display.fill_rect(self.pat_x + self.pat_length - self.step, self.pat_y, self.step, self.pat_width, st7789.BLACK)
                self.pat_x = self.pat_x - self.step
                display.fill_rect(self.pat_x, self.pat_y, self.step, self.pat_width, st7789.BLUE)
        elif yValue >= 35000:
            yStatus = "down"
            if yValue <= 45000: self.step = 2
            elif yValue <= 55000: self.step = 4
            else: self.step = 6
            if self.pat_x + self.pat_length + self.step < disp_width:
                display.fill_rect(self.pat_x, self.pat_y, self.step, self.pat_width, st7789.BLACK)
                self.pat_x = self.pat_x + self.step
                display.fill_rect(self.pat_x + self.pat_length - self.step, self.pat_y, self.step, self.pat_width, st7789.BLUE)    
    

这部分内容主要是通过摇杆来控制球拍的移动,在球拍初始化时,可以设定它的长宽和位置,通过st7789的fill_rect函数来填充一个方块,表示球拍的形状。当推动摇杆时,相应的电位计会根据推动的程度送出不同的数值,以此作为球拍速度的判断依据,让球拍每次移动0到3个像素点,这样就实现了球拍的速度调节。

 

砖类

class Brick():
    def __init__(self, *args, **kw):
        self.brick_color = st7789.GREEN
        self.brick_number = 6
        self.brick_list = [[1,1,1],[1,1,1]]
        self.brick_location = [[[40,40], [120,40], [200,40]],[[40,80], [120,80], [200,80]],[[40, 120],[120,120],[200,120]]]
        self.brick_length = 30
        self.brick_width = 15
        self.brick_refresh()
        display.line(1, 20, 240, 20, st7789.WHITE)

砖即为可以被小球破坏的方块,在一局游戏中需要有多个砖,我们为其创立了两个列表,一个是brick_location用来记录砖的位置,另一个是brick_list用来记录该砖是否被打掉了,没打掉记为1反之记为0,没打掉的砖需要在屏幕显示,打掉了的砖就不在屏幕显示了,这部分内容在初始化时完成。

def brick_refresh(self):
       for i in range(len(self.brick_list)):
            for j in range(len(self.brick_list[i])):
                if self.brick_list[i][j] == 1:
                    display.fill_rect(self.brick_location[i][j][0], self.brick_location[i][j][1], self.brick_length, self.brick_width, self.brick_color) 
                else:
                    display.fill_rect(self.brick_location[i][j][0], self.brick_location[i][j][1], self.brick_length, self.brick_width, st7789.BLACK)

   

写了一个brick_refresh函数用于在屏幕实时画出砖。brick_list中为1的砖块画在屏幕上,为0则不画。

def win_judge(self):
        global win_flag
        if self.brick_number == 0:
            win_flag = 1
 

win_judge函数用来判断输赢,当砖被打没了,win_flag置为1.

 

球类

class Ball():
    def __init__(self, ball_x = 20, ball_y = 200, ball_r = 3):
        self.ball_x = ball_x
        self.ball_y = ball_y
        self.ball_r = ball_r
        self.dir_angle = [1, -1]
        self.score = 0
        outtextxy(20, 1, "SCORE: " + str(self.score))
    
    def move(self):
        display.fill_rect(self.ball_x - self.ball_r, self.ball_y - self.ball_r, 2 * self.ball_r, 2 * self.ball_r, st7789.BLACK)
        self.ball_x += self.dir_angle[0]
        self.ball_y += self.dir_angle[1]
        display.fill_rect(self.ball_x - self.ball_r, self.ball_y - self.ball_r, 2 * self.ball_r, 2 * self.ball_r, st7789.RED)
           

球在x和y轴都有正负两个运动方向,球在每次运动时都要在x轴和y轴根据各自的运动方向进行位移,数组dir_angle表示运动方向,dir_angle[0]是x轴方向,dir_angle[1]是y轴方向,1位正向,-1为负向。

def wall_ball_collide(self):    
        if self.ball_x - self.ball_r <= 1 or self.ball_x + self.ball_r >= 240:
            self.dir_angle[0] *= -1
        if self.ball_y - self.ball_r <= 21 or self.ball_y + self.ball_r >= 240:
            self.dir_angle[1] *= -1     

wall_ball_collide函数用来判断球是否碰到墙壁(边界),只要碰到墙壁球的运动方向会发生相应的改变,就是说,如果碰到左右墙壁球的x轴运动方向翻转,碰到上下墙壁y轴运动方向翻转。

    def brick_ball_collide(self):
        global brick
        for i in range(len(brick.brick_list)):
            for j in range(len(brick.brick_list[i])):
                if brick.brick_list[i][j] == 1:
                    collide_sign_x = 0
                    collide_sign_y = 0
                    
                    if self.ball_x < brick.brick_location[i][j][0]:
                        collide_point_x = brick.brick_location[i][j][0]
                        collide_sign_x = 1
                    elif self.ball_x > brick.brick_location[i][j][0] + brick.brick_length:
                        collide_point_x = brick.brick_location[i][j][0] + brick.brick_length
                        collide_sign_x = 2
                    else:
                        collide_point_x = self.ball_x
                        collide_sign_x = 3
                    
                    if self.ball_y < brick.brick_location[i][j][1]:
                        collide_point_y = brick.brick_location[i][j][1]
                        collide_sign_y = 1
                    elif self.ball_y > brick.brick_location[i][j][1] + brick.brick_width:
                        collide_point_y = brick.brick_location[i][j][1] + brick.brick_width
                        collide_sign_y = 2
                    else:
                        collide_point_y = self.ball_y
                        collide_sign_y = 3
                    
                    distanceb = (collide_point_y - self.ball_y) * (collide_point_y - self.ball_y) + (collide_point_x - self.ball_x) * (collide_point_x - self.ball_x)
                    if distanceb < self.ball_r * self.ball_r:
                        brick.brick_list[i][j] = 0
                        brick.brick_refresh()
                        brick.brick_number -= 1
                        brick.win_judge()
                        self.score += 100
                        outtextxy(20, 1, "SCORE: " + str(self.score))
                        if collide_sign_y == 3: self.dir_angle[0] *= -1
                        elif collide_sign_x == 3: self.dir_angle[1] *= -1
                        elif (collide_sign_x == 2 and collide_sign_y == 1 or \
                        collide_sign_x == 1 and collide_sign_y == 1)\
                        and self.dir_angle[1] == -1:
                            self.dir_angle[0] *= -1
                        elif (collide_sign_x == 1 and collide_sign_y == 2 or \
                        collide_sign_x == 2 and collide_sign_y == 2)\
                        and self.dir_angle[1] == 1:
                            self.dir_angle[0] *= -1
                        elif (collide_sign_x == 1 and collide_sign_y == 1 or \
                        collide_sign_x == 1 and collide_sign_y == 2)\
                        and self.dir_angle[0] == -1:
                            self.dir_angle[1] *= -1
                        elif (collide_sign_x == 2 and collide_sign_y == 1 or \
                        collide_sign_x == 2 and collide_sign_y == 2)\
                        and self.dir_angle[0] == 1:
                            self.dir_angle[1] *= -1
                        else:
                            self.dir_angle[0] *= -1
                            self.dir_angle[1] *= -1
                            

以上一段代码是brick_ball_collide函数,用来判断球碰到砖块后球的运动方向,思路是这样的,遍历brick_list中每一个值为1(没被打掉)的砖块,判断球和当前砖块的相对位置:collide_sign区分x轴和y轴碰撞,collide_point记录碰撞点坐标,如果球在砖左侧,collide_sign_x置为1,collide_point_x记为砖左侧x坐标,如果球在砖右侧,collide_sign_x置为2,collide_point_x记为砖右侧x坐标,否则collide_sign_x置为3,collide_point_x记为球x坐标,;如果球在砖上侧,collide_sign_y置为1,collide_point_y记为砖上侧y坐标,如果球在砖下侧,collide_sign_y置为2,collide_point_y记为砖下侧y坐标,否则collide_sign_y置为3,collide_point_y记为球y坐标。

之后我们用distanceb = (collide_point_y - self.ball_y) * (collide_point_y - self.ball_y) + (collide_point_x - self.ball_x) * (collide_point_x - self.ball_x)来计算球心和砖块碰撞点的相对距离的平方,当distanceb小于球的半径的平方时,碰撞点就已经在球内部了,此时可以改变球的运动方向了,代码中根据collide_sign_x,collide_sign_y和球原本的运动方向dir_angle判断球在碰撞后的运动方向,说明比较含混,为了方便理解我画图表示:

FkVx07BMFzO9Ree-h2qmYCFMDVzS

上图中显示了在方块的不同位置,当球以不同的方向入射时其反射方向也会不同,即为以上代码表示的意思。

    def ball_pat_ball_collide(self):
        global ballpat
        collide_sign_x = 0
        collide_sign_y = 0
        if self.ball_x < ballpat.pat_x:
            collide_point_x = ballpat.pat_x
            collide_sign_x = 1
        elif self.ball_x > ballpat.pat_x + ballpat.pat_length:
            collide_point_x = ballpat.pat_x + ballpat.pat_length
            collide_sign_x = 2
        else:   
            collide_point_x = self.ball_x
            collide_sign_x = 3
        
        if self.ball_y < ballpat.pat_y:
            collide_point_y = ballpat.pat_y 
            collide_sign_y = 1
        elif self.ball_y > ballpat.pat_y + ballpat.pat_width:
            collide_point_y = ballpat.pat_y + ballpat.pat_width
            collide_sign_y = 2
        else:   
            collide_point_y = self.ball_y
            collide_sign_y = 3
            
        distanceb = (collide_point_y - self.ball_y) * (collide_point_y - self.ball_y) + (collide_point_x - self.ball_x) * (collide_point_x - self.ball_x)
        if distanceb <= self.ball_r * self.ball_r:
            if collide_sign_y == 3: self.dir_angle[0] *= -1
            elif collide_sign_x == 3: self.dir_angle[1] *= -1
            elif (collide_sign_x == 2 and collide_sign_y == 1 or \
            collide_sign_x == 1 and collide_sign_y == 1)\
            and self.dir_angle[1] == -1:
                self.dir_angle[0] *= -1
            elif (collide_sign_x == 1 and collide_sign_y == 2 or \
            collide_sign_x == 2 and collide_sign_y == 2)\
            and self.dir_angle[1] == 1:
                self.dir_angle[0] *= -1
            elif (collide_sign_x == 1 and collide_sign_y == 1 or \
            collide_sign_x == 1 and collide_sign_y == 2)\
            and self.dir_angle[0] == -1:
                self.dir_angle[1] *= -1
            elif (collide_sign_x == 2 and collide_sign_y == 1 or \
            collide_sign_x == 2 and collide_sign_y == 2)\
            and self.dir_angle[0] == 1:
                self.dir_angle[1] *= -1
            else:
                self.dir_angle[0] *= -1
                self.dir_angle[1] *= -1
    

上图中的ball_pat_ball_collide函数是用来判断球拍和球碰撞后球的反弹方向的,原理就是把球拍当成砖块来处理,和上一个函数思路相同。

 

音乐类

class p_music(music):
    song1 = '0 A5 2 26 0.6299212574958801;2 B5 2 26 0.6299212574958801;4 C6 6 26 0.6299212574958801;10 B5 2 26 0.6299212574958801;12 C6 4 26 0.6299212574958801;16 E6 4 26 0.6299212574958801;20 B5 8 26 0.6299212574958801;32 E5 4 26 0.6299212574958801;36 A5 6 26 0.6299212574958801;42 G5 2 26 0.6299212574958801;44 A5 4 26 0.6299212574958801;48 C6 4 26 0.6299212574958801;52 G5 8 26 0.6299212574958801;64 F5 2 26 0.6299212574958801;66 E5 2 26 0.6299212574958801;68 F5 6 26 0.6299212574958801;74 E5 2 26 0.6299212574958801;76 F5 4 26 0.6299212574958801;80 C6 4 26 0.6299212574958801;84 E5 8 26 0.6299212574958801;94 C6 2 26 0.6299212574958801;96 C6 2 26 0.6299212574958801;98 C6 2 26 0.6299212574958801;100 B5 6 26 0.6299212574958801;106 F#5 2 26 0.6299212574958801;108 F#5 4 26 0.6299212574958801;112 B5 4 26 0.6299212574958801;116 B5 8 26 0.6299212574958801;128 A5 2 26 0.6299212574958801;130 B5 2 26 0.6299212574958801;132 C6 6 26 0.6299212574958801;138 B5 2 26 0.6299212574958801;140 C6 4 26 0.6299212574958801;144 E6 4 26 0.6299212574958801;148 B5 8 26 0.6299212574958801;160 E5 2 26 0.6299212574958801;162 E5 2 26 0.6299212574958801;164 A5 6 26 0.6299212574958801;170 G5 2 26 0.6299212574958801;172 A5 4 26 0.6299212574958801;176 C6 4 26 0.6299212574958801;180 G5 8 26 0.6299212574958801;192 E5 4 26 0.6299212574958801;196 F5 4 26 0.6299212574958801;200 C6 2 26 0.6299212574958801;202 B5 2 26 0.6299212574958801;204 B5 4 26 0.6299212574958801;208 C6 4 26 0.6299212574958801;212 D6 4 26 0.6299212574958801;216 E6 2 26 0.6299212574958801;218 C6 2 26 0.6299212574958801;220 C6 8 26 0.6299212574958801;228 C6 2 26 0.6299212574958801;230 B5 2 26 0.6299212574958801;232 A5 4 26 0.6299212574958801;236 B5 4 26 0.6299212574958801;240 G#5 4 26 0.6299212574958801;244 A5 11 26 0.6299212574958801;256 C6 2 26 0.6299212574958801;258 D6 2 26 0.6299212574958801;260 E6 6 26 0.6299212574958801;266 D6 2 26 0.6299212574958801;268 E6 4 26 0.6299212574958801;272 G6 4 26 0.6299212574958801;276 D6 8 26 0.6299212574958801;288 G5 2 26 0.6299212574958801;290 G5 2 26 0.6299212574958801;292 C6 6 26 0.6299212574958801;298 B5 2 26 0.6299212574958801;300 C6 4 26 0.6299212574958801;304 E6 4 26 0.6299212574958801;308 E6 11 26 0.6299212574958801;324 A5 2 26 0.6299212574958801;326 B5 2 26 0.6299212574958801;328 C6 4 26 0.6299212574958801;332 B5 2 26 0.6299212574958801;334 C6 2 26 0.6299212574958801;336 D6 4 26 0.6299212574958801;340 C6 6 26 0.6299212574958801;346 G5 2 26 0.6299212574958801;348 G5 8 26 0.6299212574958801;356 F6 4 26 0.6299212574958801;360 E6 4 26 0.6299212574958801;364 D6 4 26 0.6299212574958801;368 C6 4 26 0.6299212574958801;372 E6 15 26 0.6299212574958801;388 E6 11 26 0.6299212574958801;400 E6 4 26 0.6299212574958801;404 A6 8 26 0.6299212574958801;412 G6 8 26 0.6299212574958801;420 E6 4 26 0.6299212574958801;424 D6 2 26 0.6299212574958801;426 C6 2 26 0.6299212574958801;428 C6 8 26 0.6299212574958801;436 D6 4 26 0.6299212574958801;440 C6 2 26 0.6299212574958801;442 D6 2 26 0.6299212574958801;444 D6 4 26 0.6299212574958801;448 G6 4 26 0.6299212574958801;452 E6 11 26 0.6299212574958801;464 E6 4 26 0.6299212574958801;468 A6 8 26 0.6299212574958801;476 G6 8 26 0.6299212574958801;484 E6 4 26 0.6299212574958801;488 D6 2 26 0.6299212574958801;490 C6 2 26 0.6299212574958801;492 C6 8 26 0.6299212574958801;500 D6 4 26 0.6299212574958801;504 C6 2 26 0.6299212574958801;506 D6 2 26 0.6299212574958801;508 D6 4 26 0.6299212574958801;512 B5 4 26 0.6299212574958801;516 A5 11 26 0.6299212574958801;528 A5 2 26 0.6299212574958801;530 B5 2 26 0.6299212574958801;532 C6 6 26 0.6299212574958801;538 B5 2 26 0.6299212574958801;540 C6 4 26 0.6299212574958801;544 E6 4 26 0.6299212574958801;548 B5 8 26 0.6299212574958801;560 E5 4 26 0.6299212574958801;564 A5 6 26 0.6299212574958801;570 G5 2 26 0.6299212574958801;572 A5 4 26 0.6299212574958801;576 C6 4 26 0.6299212574958801;580 G5 8 26 0.6299212574958801;592 F5 2 26 0.6299212574958801;594 E5 2 26 0.6299212574958801;596 F5 6 26 0.6299212574958801;602 E5 2 26 0.6299212574958801;604 F5 4 26 0.6299212574958801;608 C6 4 26 0.6299212574958801;612 E5 8 26 0.6299212574958801;622 C6 2 26 0.6299212574958801;624 C6 2 26 0.6299212574958801;626 C6 2 26 0.6299212574958801;628 B5 6 26 0.6299212574958801;634 F#5 2 26 0.6299212574958801;636 F#5 4 26 0.6299212574958801;640 B5 4 26 0.6299212574958801;644 B5 8 26 0.6299212574958801;656 A5 2 26 0.6299212574958801;658 B5 2 26 0.6299212574958801;660 C6 6 26 0.6299212574958801;666 B5 2 26 0.6299212574958801;668 C6 4 26 0.6299212574958801;672 E6 4 26 0.6299212574958801;676 B5 8 26 0.6299212574958801;688 E5 2 26 0.6299212574958801;690 E5 2 26 0.6299212574958801;692 A5 6 26 0.6299212574958801;698 G5 2 26 0.6299212574958801;700 A5 4 26 0.6299212574958801;704 C6 4 26 0.6299212574958801;708 G5 8 26 0.6299212574958801;720 E5 4 26 0.6299212574958801;724 F5 4 26 0.6299212574958801;728 C6 2 26 0.6299212574958801;730 B5 2 26 0.6299212574958801;732 B5 4 26 0.6299212574958801;736 C6 4 26 0.6299212574958801;740 D6 4 26 0.6299212574958801;744 E6 2 26 0.6299212574958801;746 C6 2 26 0.6299212574958801;748 C6 8 26 0.6299212574958801;756 C6 2 26 0.6299212574958801;758 B5 2 26 0.6299212574958801;760 A5 4 26 0.6299212574958801;764 B5 4 26 0.6299212574958801;768 G#5 4 26 0.6299212574958801;772 A5 11 26 0.6299212574958801'
    song0 = '0 E5 2 14;4 B4 2 14;6 C5 2 14;8 D5 2 14;10 E5 1 14;11 D5 1 14;12 C5 2 14;14 B4 2 14;16 A4 2 14;20 A4 2 14;22 C5 2 14;24 E5 2 14;28 D5 2 14;30 C5 2 14;32 B4 2 14;38 C5 2 14;40 D5 2 14;44 E5 2 14;48 C5 2 14;52 A4 2 14;56 A4 2 14;64 D5 2 14;68 F5 2 14;70 A5 2 14;74 G5 2 14;76 F5 2 14;78 E5 2 14;84 C5 2 14;86 E5 2 14;90 D5 2 14;92 C5 2 14;94 B4 2 14;98 B4 2 14;100 C5 2 14;102 D5 2 14;106 E5 2 14;110 C5 2 14;114 A4 2 14;118 A4 2 14;248 E5 8 14;256 C5 8 14;264 D5 8 14;272 B4 8 14;280 C5 8 14;288 A4 8 14;296 G#4 8 14;304 B4 8 14;313 E5 8 14;321 C5 8 14;329 D5 8 14;337 B4 4 14;341 B4 4 14;345 C5 4 14;349 E5 4 14;353 A5 8 14;361 G#5 8 14;248 C5 8 14;256 A4 8 14;264 B4 8 14;272 G#4 8 14;280 A4 8 14;288 E4 8 14;0 B4 2 14;4 G#4 2 14;6 A4 2 14;8 B4 2 14;12 A4 2 14;14 G#4 2 14;28 B4 2 14;30 A4 2 14;32 G#4 4 14;40 B4 2 14;38 A4 2 14;44 C5 2 14;52 E4 2 14;64 F4 2 14;94 G#4 2 14;100 A4 2 14;102 B4 2 14;106 C5 2 14;110 A4 2 14;114 E4 2 14;114 E4 2 14;118 E4 2 14;98 G#4 2 14;296 E4 8 14;304 G#4 8 14;313 C5 8 14;321 A4 8 14;329 B4 8 14;337 G#4 4 14;341 G#4 4 14;345 A4 4 14;349 C5 4 14;353 E5 8 14;353 E5 8 14;361 E5 8 14;48 A4 2 14;56 E4 2 14;68 D5 2 14;70 F5 2 14;74 E5 2 14;76 D5 2 14;80 E5 2 14;78 C5 2 14;80 C5 2 14;22 A4 2 14;24 C5 2 14;84 A4 2 14;86 C5 2 14;92 A4 2 14;90 B4 2 14;0 E5 2 14;4 B4 2 14;6 C5 2 14;8 D5 2 14;10 E5 1 14;11 D5 1 14;12 C5 2 14;14 B4 2 14;16 A4 2 14;20 A4 2 14;22 C5 2 14;24 E5 2 14;28 D5 2 14;30 C5 2 14;32 B4 2 14;38 C5 2 14;40 D5 2 14;44 E5 2 14;48 C5 2 14;52 A4 2 14;56 A4 2 14;64 D5 2 14;68 F5 2 14;70 A5 2 14;74 G5 2 14;76 F5 2 14;78 E5 2 14;84 C5 2 14;86 E5 2 14;90 D5 2 14;92 C5 2 14;94 B4 2 14;98 B4 2 14;100 C5 2 14;102 D5 2 14;106 E5 2 14;110 C5 2 14;114 A4 2 14;118 A4 2 14;0 B4 2 14;4 G#4 2 14;6 A4 2 14;8 B4 2 14;12 A4 2 14;14 G#4 2 14;28 B4 2 14;30 A4 2 14;32 G#4 4 14;40 B4 2 14;38 A4 2 14;44 C5 2 14;52 E4 2 14;64 F4 2 14;94 G#4 2 14;100 A4 2 14;102 B4 2 14;106 C5 2 14;110 A4 2 14;114 E4 2 14;114 E4 2 14;118 E4 2 14;98 G#4 2 14;48 A4 2 14;56 E4 2 14;68 D5 2 14;70 F5 2 14;74 E5 2 14;76 D5 2 14;80 E5 2 14;78 C5 2 14;80 C5 2 14;22 A4 2 14;24 C5 2 14;84 A4 2 14;86 C5 2 14;92 A4 2 14;90 B4 2 14;124 E5 2 14;128 B4 2 14;130 C5 2 14;132 D5 2 14;134 E5 1 14;135 D5 1 14;136 C5 2 14;138 B4 2 14;140 A4 2 14;144 A4 2 14;146 C5 2 14;148 E5 2 14;152 D5 2 14;154 C5 2 14;156 B4 2 14;162 C5 2 14;164 D5 2 14;168 E5 2 14;172 C5 2 14;176 A4 2 14;180 A4 2 14;188 D5 2 14;192 F5 2 14;194 A5 2 14;198 G5 2 14;200 F5 2 14;202 E5 2 14;208 C5 2 14;210 E5 2 14;214 D5 2 14;216 C5 2 14;218 B4 2 14;222 B4 2 14;224 C5 2 14;226 D5 2 14;230 E5 2 14;234 C5 2 14;238 A4 2 14;242 A4 2 14;124 B4 2 14;128 G#4 2 14;130 A4 2 14;132 B4 2 14;136 A4 2 14;138 G#4 2 14;152 B4 2 14;154 A4 2 14;156 G#4 4 14;164 B4 2 14;162 A4 2 14;168 C5 2 14;176 E4 2 14;188 F4 2 14;218 G#4 2 14;224 A4 2 14;226 B4 2 14;230 C5 2 14;234 A4 2 14;238 E4 2 14;238 E4 2 14;242 E4 2 14;222 G#4 2 14;172 A4 2 14;180 E4 2 14;192 D5 2 14;194 F5 2 14;198 E5 2 14;200 D5 2 14;204 E5 2 14;202 C5 2 14;204 C5 2 14;146 A4 2 14;148 C5 2 14;208 A4 2 14;210 C5 2 14;216 A4 2 14;214 B4 2 14;124 E5 2 14;128 B4 2 14;130 C5 2 14;132 D5 2 14;134 E5 1 14;135 D5 1 14;136 C5 2 14;138 B4 2 14;140 A4 2 14;144 A4 2 14;146 C5 2 14;148 E5 2 14;152 D5 2 14;154 C5 2 14;156 B4 2 14;162 C5 2 14;164 D5 2 14;168 E5 2 14;172 C5 2 14;176 A4 2 14;180 A4 2 14;188 D5 2 14;192 F5 2 14;194 A5 2 14;198 G5 2 14;200 F5 2 14;202 E5 2 14;208 C5 2 14;210 E5 2 14;214 D5 2 14;216 C5 2 14;218 B4 2 14;222 B4 2 14;224 C5 2 14;226 D5 2 14;230 E5 2 14;234 C5 2 14;238 A4 2 14;242 A4 2 14;124 B4 2 14;128 G#4 2 14;130 A4 2 14;132 B4 2 14;136 A4 2 14;138 G#4 2 14;152 B4 2 14;154 A4 2 14;156 G#4 4 14;164 B4 2 14;162 A4 2 14;168 C5 2 14;176 E4 2 14;188 F4 2 14;218 G#4 2 14;224 A4 2 14;226 B4 2 14;230 C5 2 14;234 A4 2 14;238 E4 2 14;238 E4 2 14;242 E4 2 14;222 G#4 2 14;172 A4 2 14;180 E4 2 14;192 D5 2 14;194 F5 2 14;198 E5 2 14;200 D5 2 14;204 E5 2 14;202 C5 2 14;204 C5 2 14;146 A4 2 14;148 C5 2 14;208 A4 2 14;210 C5 2 14;216 A4 2 14;214 B4 2 14;248 C5 2 13;252 C5 2 13;254 E5 2 13;250 E5 2 13;256 C5 2 13;260 C5 2 13;258 A4 2 13;262 A4 2 13;264 D5 2 13;268 D5 2 13;266 B4 2 13;270 B4 2 13;272 G#4 2 13;276 G#4 2 13;274 B4 2 13;278 B4 2 13;280 A4 2 13;284 A4 2 13;282 C5 2 13;286 C5 2 13;347 C5 2 13;351 C5 2 13;313 C5 2 13;317 C5 2 13;319 E5 2 13;315 E5 2 13;321 C5 2 13;325 C5 2 13;323 A4 2 13;327 A4 2 13;329 D5 2 13;333 D5 2 13;331 B4 2 13;335 B4 2 13;337 G#4 2 13;341 G#4 2 13;339 B4 2 13;343 B4 2 13;345 A4 2 13;349 A4 2 13;349 E5 2 13;353 E5 2 13;355 A5 2 13;359 A5 2 13;357 E5 2 13;361 E5 2 13;363 G#5 2 13;367 G#5 2 13;365 E5 2 14;292 A4 2 13;288 A4 2 13;294 E4 2 13;290 E4 2 13;300 G#4 2 13;296 G#4 2 13;302 E4 2 13;298 E4 2 13;308 G#4 2 13;304 G#4 2 13;310 B4 2 13;306 B4 2 13'
    def __init__(self, songString='0 D4 8 0', looping=True, tempo=3, duty=2512, pin=None, pins=[Pin(0)]):
        super().__init__(songString, looping, tempo, duty, pin, pins)
        self.pause = False

    def toggle_pause(self):
        self.pause = not self.pause
        if self.pause:
            print("mute\n")
            self.mute()
        else:
            print("unmute\n")
            self.unmute()
    
    def mute(self):
        for pwm in self.pwms:
            pwm.duty_u16(0)
    def unmute(self):
        for pwm in self.pwms:
            pwm.duty_u16(self.duty)

    def tick(self):
        if self.pause:
            pass
        else:
            super().tick()
     

上图的音乐类移植自贪吃蛇游戏,我们需要写一个协程bgm_progress,不断调用p_music中的tick()函数。同时main函数也要写成协程,在main中用create_task把bgm_progress打包运行,如下图所示。

async def bgm_process():
    global bgm
    while True:
        await asyncio.sleep_ms(100)
        bgm.tick()

async def main():
    bgm1 = asyncio.create_task(bgm_process())
    while True:
        await asyncio.sleep_ms(10)
        ballpat.dir_select()
        ball.progress()
        game_over_judge()
    
asyncio.run(main())

 

胜利失败判断

def game_over_judge():
    global brick,ballpat,ball ,fail_flag, win_flag
    if fail_flag == 1:
        outtextxy(10, 20, "GAME OVER")
    if win_flag == 1:
        outtextxy(10, 20, "YOU WIN")
    if fail_flag == 1 or win_flag == 1:
        utime.sleep(3)
        display.fill(st7789.BLACK)
        brick.__init__()
        ballpat.__init__()
        ball.__init__()
        fail_flag = 0
        win_flag = 0

定义全局变量fail_flag和win_flag来判断失败或胜利,显示相关信息,并初始化和重新开始游戏。

 

遇到的难题和解决方法

球与砖块或球拍碰撞后的反弹问题

如果处理不好,会出现违反物理现象的反弹,起初我想通过为每个坐标点都设定一个和球接触的判断,但这显然是不可能的,因为坐标点就是像素点,数量太庞大,根本不可行。于是我采用对球和每个砖块遍历进行判断,这样工作量就小了很多,具体的解决方案在代码说明中解释了,主要是需要考虑球和砖块的相对位置和球本来的运动方向。

 

音乐问题

音乐实际上需要用协程的知识,要产生和谐的音乐,需要让bgm每0.1s执行一次tick(),而在这0.1s内程序不能只是等待bgm执行tick()而不进行其他操作,所以必须采用协程,将bgm的tick()循环写在一个协程bgm_progress中,main也要写成协程来调用create_task创立bgm_progress任务,这样才能让程序在bgm执行tick()的间隔时间也能运行,从而达到玩游戏和播放bgm同时进行的效果。

 

未来的计划和建议

总体来说我对硬禾学堂这次的项目是非常满意的,在做项目的过程中,我提升了实践的能力,丰富了开发经验,掌握了许多新的知识,认识了有趣的老师和朋友,完成了学校对学分的要求。同时我希望硬禾学堂在今后的项目中更注重品控,因为我的摇杆在x轴出现了漂移问题,导致我只能使用y轴,而群里也有一些同学的设备存在小问题。未来我会继续参加硬禾学堂在家一起练的项目,希望硬禾学堂能越做越好。

 

源代码

import uos
import machine
from machine import Pin, ADC
import st7789 as st7789
import vga2_8x8 as font
from fonts import vga2_8x8 as font1
from fonts import vga1_16x32 as font2
import random
import framebuf
import utime
import uasyncio as asyncio
from board import game_kit
from buzzer_music import music
from button import button

st7789_res = 0
st7789_dc  = 1
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)
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)
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)
display.fill(st7789.BLACK)

xAxis = ADC(Pin(29))
yAxis = ADC(Pin(28))
#button = Pin(16,Pin.IN, Pin.PULL_UP)   
fail_flag = 0
win_flag = 0

def outtextxy(x, y, c):
    display.text(font, c, x*8, y*8, st7789.RED, st7789.BLACK)
    
class Ballpat():
    def __init__(self, pat_length = 40, pat_width = 15, pat_x = disp_width/2, pat_y = disp_height - 20, step = 1):
        self.pat_length = int(pat_length)
        self.pat_width = int(pat_width)
        self.pat_x = int(pat_x)
        self.pat_y = int(pat_y)
        self.step = int(step)
        display.fill_rect(self.pat_x, self.pat_y, self.pat_length, self.pat_width, st7789.BLUE)
            
    def dir_select(self):
        yValue = yAxis.read_u16()
        if yValue <= 25000:
            yStatus = "up"
            if yValue >= 15000: self.step = 2
            elif yValue >= 5000: self.step = 4
            else: self.step = 6
            if self.pat_x - self.step >= 0:
                display.fill_rect(self.pat_x + self.pat_length - self.step, self.pat_y, self.step, self.pat_width, st7789.BLACK)
                self.pat_x = self.pat_x - self.step
                display.fill_rect(self.pat_x, self.pat_y, self.step, self.pat_width, st7789.BLUE)
        elif yValue >= 35000:
            yStatus = "down"
            if yValue <= 45000: self.step = 2
            elif yValue <= 55000: self.step = 4
            else: self.step = 6
            if self.pat_x + self.pat_length + self.step < disp_width:
                display.fill_rect(self.pat_x, self.pat_y, self.step, self.pat_width, st7789.BLACK)
                self.pat_x = self.pat_x + self.step
                display.fill_rect(self.pat_x + self.pat_length - self.step, self.pat_y, self.step, self.pat_width, st7789.BLUE)    
    
class Ball():
    def __init__(self, ball_x = 20, ball_y = 200, ball_r = 3):
        self.ball_x = ball_x
        self.ball_y = ball_y
        self.ball_r = ball_r
        self.dir_angle = [1, -1]
        self.score = 0
        outtextxy(20, 1, "SCORE: " + str(self.score))
    
    def move(self):
        display.fill_rect(self.ball_x - self.ball_r, self.ball_y - self.ball_r, 2 * self.ball_r, 2 * self.ball_r, st7789.BLACK)
        self.ball_x += self.dir_angle[0]
        self.ball_y += self.dir_angle[1]
        display.fill_rect(self.ball_x - self.ball_r, self.ball_y - self.ball_r, 2 * self.ball_r, 2 * self.ball_r, st7789.RED)
             
    def progress(self):
        self.wall_ball_collide()
        self.brick_ball_collide()
        self.ball_pat_ball_collide()
        self.move()  
        self.fail_judge()
        
    def wall_ball_collide(self):    
        if self.ball_x - self.ball_r <= 1 or self.ball_x + self.ball_r >= 240:
            self.dir_angle[0] *= -1
        if self.ball_y - self.ball_r <= 21 or self.ball_y + self.ball_r >= 240:
            self.dir_angle[1] *= -1     
            
    def brick_ball_collide(self):
        global brick
        for i in range(len(brick.brick_list)):
            for j in range(len(brick.brick_list[i])):
                if brick.brick_list[i][j] == 1:
                    collide_sign_x = 0
                    collide_sign_y = 0
                    
                    if self.ball_x < brick.brick_location[i][j][0]:
                        collide_point_x = brick.brick_location[i][j][0]
                        collide_sign_x = 1
                    elif self.ball_x > brick.brick_location[i][j][0] + brick.brick_length:
                        collide_point_x = brick.brick_location[i][j][0] + brick.brick_length
                        collide_sign_x = 2
                    else:
                        collide_point_x = self.ball_x
                        collide_sign_x = 3
                    
                    if self.ball_y < brick.brick_location[i][j][1]:
                        collide_point_y = brick.brick_location[i][j][1]
                        collide_sign_y = 1
                    elif self.ball_y > brick.brick_location[i][j][1] + brick.brick_width:
                        collide_point_y = brick.brick_location[i][j][1] + brick.brick_width
                        collide_sign_y = 2
                    else:
                        collide_point_y = self.ball_y
                        collide_sign_y = 3
                    
                    distanceb = (collide_point_y - self.ball_y) * (collide_point_y - self.ball_y) + (collide_point_x - self.ball_x) * (collide_point_x - self.ball_x)
                    if distanceb < self.ball_r * self.ball_r:
                        brick.brick_list[i][j] = 0
                        brick.brick_refresh()
                        brick.brick_number -= 1
                        brick.win_judge()
                        self.score += 100
                        outtextxy(20, 1, "SCORE: " + str(self.score))
                        if collide_sign_y == 3: self.dir_angle[0] *= -1
                        elif collide_sign_x == 3: self.dir_angle[1] *= -1
                        elif (collide_sign_x == 2 and collide_sign_y == 1 or \
                        collide_sign_x == 1 and collide_sign_y == 1)\
                        and self.dir_angle[1] == -1:
                            self.dir_angle[0] *= -1
                        elif (collide_sign_x == 1 and collide_sign_y == 2 or \
                        collide_sign_x == 2 and collide_sign_y == 2)\
                        and self.dir_angle[1] == 1:
                            self.dir_angle[0] *= -1
                        elif (collide_sign_x == 1 and collide_sign_y == 1 or \
                        collide_sign_x == 1 and collide_sign_y == 2)\
                        and self.dir_angle[0] == -1:
                            self.dir_angle[1] *= -1
                        elif (collide_sign_x == 2 and collide_sign_y == 1 or \
                        collide_sign_x == 2 and collide_sign_y == 2)\
                        and self.dir_angle[0] == 1:
                            self.dir_angle[1] *= -1
                        else:
                            self.dir_angle[0] *= -1
                            self.dir_angle[1] *= -1
                            
                      
    def ball_pat_ball_collide(self):
        global ballpat
        collide_sign_x = 0
        collide_sign_y = 0
        if self.ball_x < ballpat.pat_x:
            collide_point_x = ballpat.pat_x
            collide_sign_x = 1
        elif self.ball_x > ballpat.pat_x + ballpat.pat_length:
            collide_point_x = ballpat.pat_x + ballpat.pat_length
            collide_sign_x = 2
        else:   
            collide_point_x = self.ball_x
            collide_sign_x = 3
        
        if self.ball_y < ballpat.pat_y:
            collide_point_y = ballpat.pat_y 
            collide_sign_y = 1
        elif self.ball_y > ballpat.pat_y + ballpat.pat_width:
            collide_point_y = ballpat.pat_y + ballpat.pat_width
            collide_sign_y = 2
        else:   
            collide_point_y = self.ball_y
            collide_sign_y = 3
            
        distanceb = (collide_point_y - self.ball_y) * (collide_point_y - self.ball_y) + (collide_point_x - self.ball_x) * (collide_point_x - self.ball_x)
        if distanceb <= self.ball_r * self.ball_r:
            if collide_sign_y == 3: self.dir_angle[0] *= -1
            elif collide_sign_x == 3: self.dir_angle[1] *= -1
            elif (collide_sign_x == 2 and collide_sign_y == 1 or \
            collide_sign_x == 1 and collide_sign_y == 1)\
            and self.dir_angle[1] == -1:
                self.dir_angle[0] *= -1
            elif (collide_sign_x == 1 and collide_sign_y == 2 or \
            collide_sign_x == 2 and collide_sign_y == 2)\
            and self.dir_angle[1] == 1:
                self.dir_angle[0] *= -1
            elif (collide_sign_x == 1 and collide_sign_y == 1 or \
            collide_sign_x == 1 and collide_sign_y == 2)\
            and self.dir_angle[0] == -1:
                self.dir_angle[1] *= -1
            elif (collide_sign_x == 2 and collide_sign_y == 1 or \
            collide_sign_x == 2 and collide_sign_y == 2)\
            and self.dir_angle[0] == 1:
                self.dir_angle[1] *= -1
            else:
                self.dir_angle[0] *= -1
                self.dir_angle[1] *= -1
    
    def fail_judge(self):
        global fail_flag
        if self.ball_y + self.ball_r >= 240:
            fail_flag = 1
            
                
class Brick():
    def __init__(self, *args, **kw):
        self.brick_color = st7789.GREEN
        self.brick_number = 6
        self.brick_list = [[1,1,1],[1,1,1]]
        self.brick_location = [[[40,40], [120,40], [200,40]],[[40,80], [120,80], [200,80]],[[40, 120],[120,120],[200,120]]]
        self.brick_length = 30
        self.brick_width = 15
        self.brick_refresh()
        display.line(1, 20, 240, 20, st7789.WHITE)
    
    def brick_refresh(self):
       for i in range(len(self.brick_list)):
            for j in range(len(self.brick_list[i])):
                if self.brick_list[i][j] == 1:
                    display.fill_rect(self.brick_location[i][j][0], self.brick_location[i][j][1], self.brick_length, self.brick_width, self.brick_color) 
                else:
                    display.fill_rect(self.brick_location[i][j][0], self.brick_location[i][j][1], self.brick_length, self.brick_width, st7789.BLACK)

    def win_judge(self):
        global win_flag
        if self.brick_number == 0:
            win_flag = 1
 
class p_music(music):
    song1 = '0 A5 2 26 0.6299212574958801;2 B5 2 26 0.6299212574958801;4 C6 6 26 0.6299212574958801;10 B5 2 26 0.6299212574958801;12 C6 4 26 0.6299212574958801;16 E6 4 26 0.6299212574958801;20 B5 8 26 0.6299212574958801;32 E5 4 26 0.6299212574958801;36 A5 6 26 0.6299212574958801;42 G5 2 26 0.6299212574958801;44 A5 4 26 0.6299212574958801;48 C6 4 26 0.6299212574958801;52 G5 8 26 0.6299212574958801;64 F5 2 26 0.6299212574958801;66 E5 2 26 0.6299212574958801;68 F5 6 26 0.6299212574958801;74 E5 2 26 0.6299212574958801;76 F5 4 26 0.6299212574958801;80 C6 4 26 0.6299212574958801;84 E5 8 26 0.6299212574958801;94 C6 2 26 0.6299212574958801;96 C6 2 26 0.6299212574958801;98 C6 2 26 0.6299212574958801;100 B5 6 26 0.6299212574958801;106 F#5 2 26 0.6299212574958801;108 F#5 4 26 0.6299212574958801;112 B5 4 26 0.6299212574958801;116 B5 8 26 0.6299212574958801;128 A5 2 26 0.6299212574958801;130 B5 2 26 0.6299212574958801;132 C6 6 26 0.6299212574958801;138 B5 2 26 0.6299212574958801;140 C6 4 26 0.6299212574958801;144 E6 4 26 0.6299212574958801;148 B5 8 26 0.6299212574958801;160 E5 2 26 0.6299212574958801;162 E5 2 26 0.6299212574958801;164 A5 6 26 0.6299212574958801;170 G5 2 26 0.6299212574958801;172 A5 4 26 0.6299212574958801;176 C6 4 26 0.6299212574958801;180 G5 8 26 0.6299212574958801;192 E5 4 26 0.6299212574958801;196 F5 4 26 0.6299212574958801;200 C6 2 26 0.6299212574958801;202 B5 2 26 0.6299212574958801;204 B5 4 26 0.6299212574958801;208 C6 4 26 0.6299212574958801;212 D6 4 26 0.6299212574958801;216 E6 2 26 0.6299212574958801;218 C6 2 26 0.6299212574958801;220 C6 8 26 0.6299212574958801;228 C6 2 26 0.6299212574958801;230 B5 2 26 0.6299212574958801;232 A5 4 26 0.6299212574958801;236 B5 4 26 0.6299212574958801;240 G#5 4 26 0.6299212574958801;244 A5 11 26 0.6299212574958801;256 C6 2 26 0.6299212574958801;258 D6 2 26 0.6299212574958801;260 E6 6 26 0.6299212574958801;266 D6 2 26 0.6299212574958801;268 E6 4 26 0.6299212574958801;272 G6 4 26 0.6299212574958801;276 D6 8 26 0.6299212574958801;288 G5 2 26 0.6299212574958801;290 G5 2 26 0.6299212574958801;292 C6 6 26 0.6299212574958801;298 B5 2 26 0.6299212574958801;300 C6 4 26 0.6299212574958801;304 E6 4 26 0.6299212574958801;308 E6 11 26 0.6299212574958801;324 A5 2 26 0.6299212574958801;326 B5 2 26 0.6299212574958801;328 C6 4 26 0.6299212574958801;332 B5 2 26 0.6299212574958801;334 C6 2 26 0.6299212574958801;336 D6 4 26 0.6299212574958801;340 C6 6 26 0.6299212574958801;346 G5 2 26 0.6299212574958801;348 G5 8 26 0.6299212574958801;356 F6 4 26 0.6299212574958801;360 E6 4 26 0.6299212574958801;364 D6 4 26 0.6299212574958801;368 C6 4 26 0.6299212574958801;372 E6 15 26 0.6299212574958801;388 E6 11 26 0.6299212574958801;400 E6 4 26 0.6299212574958801;404 A6 8 26 0.6299212574958801;412 G6 8 26 0.6299212574958801;420 E6 4 26 0.6299212574958801;424 D6 2 26 0.6299212574958801;426 C6 2 26 0.6299212574958801;428 C6 8 26 0.6299212574958801;436 D6 4 26 0.6299212574958801;440 C6 2 26 0.6299212574958801;442 D6 2 26 0.6299212574958801;444 D6 4 26 0.6299212574958801;448 G6 4 26 0.6299212574958801;452 E6 11 26 0.6299212574958801;464 E6 4 26 0.6299212574958801;468 A6 8 26 0.6299212574958801;476 G6 8 26 0.6299212574958801;484 E6 4 26 0.6299212574958801;488 D6 2 26 0.6299212574958801;490 C6 2 26 0.6299212574958801;492 C6 8 26 0.6299212574958801;500 D6 4 26 0.6299212574958801;504 C6 2 26 0.6299212574958801;506 D6 2 26 0.6299212574958801;508 D6 4 26 0.6299212574958801;512 B5 4 26 0.6299212574958801;516 A5 11 26 0.6299212574958801;528 A5 2 26 0.6299212574958801;530 B5 2 26 0.6299212574958801;532 C6 6 26 0.6299212574958801;538 B5 2 26 0.6299212574958801;540 C6 4 26 0.6299212574958801;544 E6 4 26 0.6299212574958801;548 B5 8 26 0.6299212574958801;560 E5 4 26 0.6299212574958801;564 A5 6 26 0.6299212574958801;570 G5 2 26 0.6299212574958801;572 A5 4 26 0.6299212574958801;576 C6 4 26 0.6299212574958801;580 G5 8 26 0.6299212574958801;592 F5 2 26 0.6299212574958801;594 E5 2 26 0.6299212574958801;596 F5 6 26 0.6299212574958801;602 E5 2 26 0.6299212574958801;604 F5 4 26 0.6299212574958801;608 C6 4 26 0.6299212574958801;612 E5 8 26 0.6299212574958801;622 C6 2 26 0.6299212574958801;624 C6 2 26 0.6299212574958801;626 C6 2 26 0.6299212574958801;628 B5 6 26 0.6299212574958801;634 F#5 2 26 0.6299212574958801;636 F#5 4 26 0.6299212574958801;640 B5 4 26 0.6299212574958801;644 B5 8 26 0.6299212574958801;656 A5 2 26 0.6299212574958801;658 B5 2 26 0.6299212574958801;660 C6 6 26 0.6299212574958801;666 B5 2 26 0.6299212574958801;668 C6 4 26 0.6299212574958801;672 E6 4 26 0.6299212574958801;676 B5 8 26 0.6299212574958801;688 E5 2 26 0.6299212574958801;690 E5 2 26 0.6299212574958801;692 A5 6 26 0.6299212574958801;698 G5 2 26 0.6299212574958801;700 A5 4 26 0.6299212574958801;704 C6 4 26 0.6299212574958801;708 G5 8 26 0.6299212574958801;720 E5 4 26 0.6299212574958801;724 F5 4 26 0.6299212574958801;728 C6 2 26 0.6299212574958801;730 B5 2 26 0.6299212574958801;732 B5 4 26 0.6299212574958801;736 C6 4 26 0.6299212574958801;740 D6 4 26 0.6299212574958801;744 E6 2 26 0.6299212574958801;746 C6 2 26 0.6299212574958801;748 C6 8 26 0.6299212574958801;756 C6 2 26 0.6299212574958801;758 B5 2 26 0.6299212574958801;760 A5 4 26 0.6299212574958801;764 B5 4 26 0.6299212574958801;768 G#5 4 26 0.6299212574958801;772 A5 11 26 0.6299212574958801'
    song0 = '0 E5 2 14;4 B4 2 14;6 C5 2 14;8 D5 2 14;10 E5 1 14;11 D5 1 14;12 C5 2 14;14 B4 2 14;16 A4 2 14;20 A4 2 14;22 C5 2 14;24 E5 2 14;28 D5 2 14;30 C5 2 14;32 B4 2 14;38 C5 2 14;40 D5 2 14;44 E5 2 14;48 C5 2 14;52 A4 2 14;56 A4 2 14;64 D5 2 14;68 F5 2 14;70 A5 2 14;74 G5 2 14;76 F5 2 14;78 E5 2 14;84 C5 2 14;86 E5 2 14;90 D5 2 14;92 C5 2 14;94 B4 2 14;98 B4 2 14;100 C5 2 14;102 D5 2 14;106 E5 2 14;110 C5 2 14;114 A4 2 14;118 A4 2 14;248 E5 8 14;256 C5 8 14;264 D5 8 14;272 B4 8 14;280 C5 8 14;288 A4 8 14;296 G#4 8 14;304 B4 8 14;313 E5 8 14;321 C5 8 14;329 D5 8 14;337 B4 4 14;341 B4 4 14;345 C5 4 14;349 E5 4 14;353 A5 8 14;361 G#5 8 14;248 C5 8 14;256 A4 8 14;264 B4 8 14;272 G#4 8 14;280 A4 8 14;288 E4 8 14;0 B4 2 14;4 G#4 2 14;6 A4 2 14;8 B4 2 14;12 A4 2 14;14 G#4 2 14;28 B4 2 14;30 A4 2 14;32 G#4 4 14;40 B4 2 14;38 A4 2 14;44 C5 2 14;52 E4 2 14;64 F4 2 14;94 G#4 2 14;100 A4 2 14;102 B4 2 14;106 C5 2 14;110 A4 2 14;114 E4 2 14;114 E4 2 14;118 E4 2 14;98 G#4 2 14;296 E4 8 14;304 G#4 8 14;313 C5 8 14;321 A4 8 14;329 B4 8 14;337 G#4 4 14;341 G#4 4 14;345 A4 4 14;349 C5 4 14;353 E5 8 14;353 E5 8 14;361 E5 8 14;48 A4 2 14;56 E4 2 14;68 D5 2 14;70 F5 2 14;74 E5 2 14;76 D5 2 14;80 E5 2 14;78 C5 2 14;80 C5 2 14;22 A4 2 14;24 C5 2 14;84 A4 2 14;86 C5 2 14;92 A4 2 14;90 B4 2 14;0 E5 2 14;4 B4 2 14;6 C5 2 14;8 D5 2 14;10 E5 1 14;11 D5 1 14;12 C5 2 14;14 B4 2 14;16 A4 2 14;20 A4 2 14;22 C5 2 14;24 E5 2 14;28 D5 2 14;30 C5 2 14;32 B4 2 14;38 C5 2 14;40 D5 2 14;44 E5 2 14;48 C5 2 14;52 A4 2 14;56 A4 2 14;64 D5 2 14;68 F5 2 14;70 A5 2 14;74 G5 2 14;76 F5 2 14;78 E5 2 14;84 C5 2 14;86 E5 2 14;90 D5 2 14;92 C5 2 14;94 B4 2 14;98 B4 2 14;100 C5 2 14;102 D5 2 14;106 E5 2 14;110 C5 2 14;114 A4 2 14;118 A4 2 14;0 B4 2 14;4 G#4 2 14;6 A4 2 14;8 B4 2 14;12 A4 2 14;14 G#4 2 14;28 B4 2 14;30 A4 2 14;32 G#4 4 14;40 B4 2 14;38 A4 2 14;44 C5 2 14;52 E4 2 14;64 F4 2 14;94 G#4 2 14;100 A4 2 14;102 B4 2 14;106 C5 2 14;110 A4 2 14;114 E4 2 14;114 E4 2 14;118 E4 2 14;98 G#4 2 14;48 A4 2 14;56 E4 2 14;68 D5 2 14;70 F5 2 14;74 E5 2 14;76 D5 2 14;80 E5 2 14;78 C5 2 14;80 C5 2 14;22 A4 2 14;24 C5 2 14;84 A4 2 14;86 C5 2 14;92 A4 2 14;90 B4 2 14;124 E5 2 14;128 B4 2 14;130 C5 2 14;132 D5 2 14;134 E5 1 14;135 D5 1 14;136 C5 2 14;138 B4 2 14;140 A4 2 14;144 A4 2 14;146 C5 2 14;148 E5 2 14;152 D5 2 14;154 C5 2 14;156 B4 2 14;162 C5 2 14;164 D5 2 14;168 E5 2 14;172 C5 2 14;176 A4 2 14;180 A4 2 14;188 D5 2 14;192 F5 2 14;194 A5 2 14;198 G5 2 14;200 F5 2 14;202 E5 2 14;208 C5 2 14;210 E5 2 14;214 D5 2 14;216 C5 2 14;218 B4 2 14;222 B4 2 14;224 C5 2 14;226 D5 2 14;230 E5 2 14;234 C5 2 14;238 A4 2 14;242 A4 2 14;124 B4 2 14;128 G#4 2 14;130 A4 2 14;132 B4 2 14;136 A4 2 14;138 G#4 2 14;152 B4 2 14;154 A4 2 14;156 G#4 4 14;164 B4 2 14;162 A4 2 14;168 C5 2 14;176 E4 2 14;188 F4 2 14;218 G#4 2 14;224 A4 2 14;226 B4 2 14;230 C5 2 14;234 A4 2 14;238 E4 2 14;238 E4 2 14;242 E4 2 14;222 G#4 2 14;172 A4 2 14;180 E4 2 14;192 D5 2 14;194 F5 2 14;198 E5 2 14;200 D5 2 14;204 E5 2 14;202 C5 2 14;204 C5 2 14;146 A4 2 14;148 C5 2 14;208 A4 2 14;210 C5 2 14;216 A4 2 14;214 B4 2 14;124 E5 2 14;128 B4 2 14;130 C5 2 14;132 D5 2 14;134 E5 1 14;135 D5 1 14;136 C5 2 14;138 B4 2 14;140 A4 2 14;144 A4 2 14;146 C5 2 14;148 E5 2 14;152 D5 2 14;154 C5 2 14;156 B4 2 14;162 C5 2 14;164 D5 2 14;168 E5 2 14;172 C5 2 14;176 A4 2 14;180 A4 2 14;188 D5 2 14;192 F5 2 14;194 A5 2 14;198 G5 2 14;200 F5 2 14;202 E5 2 14;208 C5 2 14;210 E5 2 14;214 D5 2 14;216 C5 2 14;218 B4 2 14;222 B4 2 14;224 C5 2 14;226 D5 2 14;230 E5 2 14;234 C5 2 14;238 A4 2 14;242 A4 2 14;124 B4 2 14;128 G#4 2 14;130 A4 2 14;132 B4 2 14;136 A4 2 14;138 G#4 2 14;152 B4 2 14;154 A4 2 14;156 G#4 4 14;164 B4 2 14;162 A4 2 14;168 C5 2 14;176 E4 2 14;188 F4 2 14;218 G#4 2 14;224 A4 2 14;226 B4 2 14;230 C5 2 14;234 A4 2 14;238 E4 2 14;238 E4 2 14;242 E4 2 14;222 G#4 2 14;172 A4 2 14;180 E4 2 14;192 D5 2 14;194 F5 2 14;198 E5 2 14;200 D5 2 14;204 E5 2 14;202 C5 2 14;204 C5 2 14;146 A4 2 14;148 C5 2 14;208 A4 2 14;210 C5 2 14;216 A4 2 14;214 B4 2 14;248 C5 2 13;252 C5 2 13;254 E5 2 13;250 E5 2 13;256 C5 2 13;260 C5 2 13;258 A4 2 13;262 A4 2 13;264 D5 2 13;268 D5 2 13;266 B4 2 13;270 B4 2 13;272 G#4 2 13;276 G#4 2 13;274 B4 2 13;278 B4 2 13;280 A4 2 13;284 A4 2 13;282 C5 2 13;286 C5 2 13;347 C5 2 13;351 C5 2 13;313 C5 2 13;317 C5 2 13;319 E5 2 13;315 E5 2 13;321 C5 2 13;325 C5 2 13;323 A4 2 13;327 A4 2 13;329 D5 2 13;333 D5 2 13;331 B4 2 13;335 B4 2 13;337 G#4 2 13;341 G#4 2 13;339 B4 2 13;343 B4 2 13;345 A4 2 13;349 A4 2 13;349 E5 2 13;353 E5 2 13;355 A5 2 13;359 A5 2 13;357 E5 2 13;361 E5 2 13;363 G#5 2 13;367 G#5 2 13;365 E5 2 14;292 A4 2 13;288 A4 2 13;294 E4 2 13;290 E4 2 13;300 G#4 2 13;296 G#4 2 13;302 E4 2 13;298 E4 2 13;308 G#4 2 13;304 G#4 2 13;310 B4 2 13;306 B4 2 13'
    def __init__(self, songString='0 D4 8 0', looping=True, tempo=3, duty=2512, pin=None, pins=[Pin(0)]):
        super().__init__(songString, looping, tempo, duty, pin, pins)
        self.pause = False

    def toggle_pause(self):
        self.pause = not self.pause
        if self.pause:
            print("mute\n")
            self.mute()
        else:
            print("unmute\n")
            self.unmute()
    
    def mute(self):
        for pwm in self.pwms:
            pwm.duty_u16(0)
    def unmute(self):
        for pwm in self.pwms:
            pwm.duty_u16(self.duty)

    def tick(self):
        if self.pause:
            pass
        else:
            super().tick()
     
bgm = p_music(p_music.song0, tempo=1, duty=500, pins=[
    Pin(game_kit.buzzer, Pin.OUT)])  
    
def k1_callback(p):
    global bgm
    print("k1 pressed")
    bgm.toggle_pause()   

k1 = button(game_kit.key_a, k1_callback)

async def bgm_process():
    global bgm
    while True:
        await asyncio.sleep_ms(100)
        bgm.tick()
        
# async def process():
    # global bgm
    # bgm1 = asyncio.create_task(bgm_process())
    # await asyncio.sleep_ms(100)
    
# asyncio.run(process())

def game_over_judge():
    global brick,ballpat,ball ,fail_flag, win_flag
    if fail_flag == 1:
        outtextxy(10, 20, "GAME OVER")
    if win_flag == 1:
        outtextxy(10, 20, "YOU WIN")
    if fail_flag == 1 or win_flag == 1:
        utime.sleep(3)
        display.fill(st7789.BLACK)
        brick.__init__()
        ballpat.__init__()
        ball.__init__()
        fail_flag = 0
        win_flag = 0

brick = Brick()      
ball = Ball()
ballpat = Ballpat()

async def main():
    bgm1 = asyncio.create_task(bgm_process())
    while True:
        await asyncio.sleep_ms(10)
        ballpat.dir_select()
        ball.progress()
        game_over_judge()
    
asyncio.run(main())

 

附件下载

blockgame.zip
blockgame.py是游戏执行文件,其余的文件都传到游戏机里面

团队介绍

北京理工大学张立润
团队成员
张立润
北京理工大学

评论

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