NeloKin 发表于 2023-1-5 14:58:28

行空版使用pygame实现别踩白块游戏

本帖最后由 NeloKin 于 2023-1-5 14:58 编辑

项目背景:
行空板UNIHIKER,作为一个带有LCD触控屏,自带linux环境和python库的设备,非常适合开发一些有关触控类的小游戏。作为一个节奏反应类游戏爱好者,我对“别踩白块”这款游戏十分喜爱,然而这家游戏的制作公司随后在游戏里加入了大量的广告,让我苦不堪言。借着这个机会,我将使用pygame库在行空板上重新复现这一经典游戏,帮助广大被无孔不入的广告恶心到的玩家。
别踩白块,游戏正如他的名字所示,我们只需要不断踩着黑色方块前进即可,画面分为4行4列,每一行都只有一个黑色色块,玩家的任务就是按对他。本项目复刻了游戏的禅模式,在规定的时间内尽可能点击最多的黑块来取得高分。注意千万别点错了哦,点到白块可就直接游戏结束了。


硬件介绍:


[*]行空板UNIHIKER
[*]USB免驱扬声器


软件清单:


[*]Mind+ Python代码模式





项目文件下载:


由于背景音乐过大,无法上传,各位可以选择自己喜欢的bgm,改名为bgm.mp3后添加入sounds文件夹即可。

代码详解:


本项目使用pygame库实现。由于需要随机变量,计时器和蜂鸣器,还需添加time,random,pinpong等库。
初始化传感器,设定蜂鸣器频率
import pygame# 导入pygame库
import random# 导入random库
import numpy as np# 导入numpy库
import time# 导入time库
from pinpong.extension.unihiker import *#导入pinpong库(蜂鸣器使用)
from pinpong.board import Board,Pin
Board().begin() #初始化,选择板型和端口号,不输入则进行自动识别
buzzer.set_tempo(8,220) #设定蜂鸣器为8/8拍,BPM为220

初始化pygame游戏窗口,初始化参数
pygame.init()# 初始化pygame
width =240   # 定义宽
height=320   # 定义高
size=(240,320)# 定义尺寸
screen = pygame.display.set_mode(size) # 创建游戏窗口,尺寸为(240,320)

global start_page   #开始页定义
global game_page    #游戏页定义
start_page = True   #初始化开始页为真
game_page = False   #初始化游戏页为否


将游戏窗口划分为一个个小方格,每个方格的宽为60,高为80,共计4行,4列。创建point类表示方块,rect方法绘制方块

# 将游戏窗口划分为一个个小方格,每个方格的宽为60,高为80,共计4行,4列
ROW=4 # 定义行数,
COL=4 # 定义列数
cell_width=width/COL # 定义格子的宽
cell_height=height/ROW # 定义格子的高

class Point:
    row=0 # 行
    col=0 # 列
    def __init__(self,row,col): # 行 列
      self.row=row
      self.col=col

point_color = (0,0,0)   #块颜色为黑

def rect(point,color):
    left=point.col*cell_width # 定义方格距离左边缘的距离
    top=point.row*cell_height # 定义方格距离上边缘的距离
    pygame.draw.rect(screen,color,(left,top,cell_width,cell_height)) # 在窗口上绘制矩形,颜色为color载入背景音乐,准备文字字体,已经初始黑块排列的生成。
这里使用list类作为黑块的地址存储方式,存储四个point类,表示屏幕上显示的四个黑块,每行一个。初始黑块横坐标位置随机生成。
# 载入背景音乐
pygame.mixer.music.load('sounds/bgm.mp3')
pygame.mixer.music.play(-1)   #循环播放
pygame.mixer.music.set_volume(1)    #设定音量可调整
# 文本准备
scorefont = pygame.font.SysFont('Arial', 40)# 创建计分器Font字体对象
timerfont = pygame.font.SysFont('Arial', 20)# 创建计时器Font字体对象
titlefont = pygame.font.Font('chinese.ttf', 40)    # 创建标题Font字体对象
#计时器准备
TIMER1_EVENT = pygame.USEREVENT

#创建初始黑块队列,在0到3内随机,每行一块
lists = [Point(row = 0, col = random.randint(0,COL-1)),
      Point(row = 1, col = random.randint(0,COL-1)),
      Point(row = 2, col = random.randint(0,COL-1)),
      Point(row = 3, col = random.randint(0,COL-1))
]

定义计时器功能,使用pygame的time库内set——time函数,作为时间事件触发,每次触发减少倒计时,并刷新时间显示。归零后跳转结算界面。
#初始化计时器,设定倒计时秒数
def start_timer1():
    global seconds
    seconds = 60
    pygame.time.set_timer(TIMER1_EVENT, 1000)

#计时器触发时,复写秒数显示,并减少计时秒数。
def on_timer1():
    global seconds
    global game_over
    global game_page
    print (seconds)
    pygame.draw.rect(screen,(255,255,255),(210,0,25,22))
    timer_dis = timerfont.render(str(seconds),True,(255,0,0))
    screen.blit(timer_dis,(210,0))
    pygame.display.flip()
    seconds -= 1
    if seconds < 0:   #若归零,则跳转到结算页面,计时器停止
      pygame.time.set_timer(TIMER1_EVENT, 0)
      game_over = True
      game_page = False

定义分割线绘制功能,美化游戏界面。
def draw_line():    #绘制分割线
    pygame.draw.line(screen,(0,0,0),(0,80),(240,80))
    pygame.draw.line(screen,(0,0,0),(0,160),(240,160))
    pygame.draw.line(screen,(0,0,0),(0,240),(240,240))
    pygame.draw.line(screen,(0,0,0),(60,0),(60,320))
    pygame.draw.line(screen,(0,0,0),(120,0),(120,320))
    pygame.draw.line(screen,(0,0,0),(180,0),(180,320))
接下来为主程序循环部分,接在while True函数内。

开始界面部分:加载背景,加载标题,加载开始游戏图片。若鼠标移动到开始游戏图片,替换同字异色图片,点击跳转至游戏界面。
while start_page: # 当进入开始页面
      for event in pygame.event.get():# 遍历所有事件
            if event.type == pygame.QUIT:# 如果单击关闭窗口,则退出
                pygame.quit()# 退出pygame
            bg = pygame.image.load("pic/bg.png").convert_alpha()    #载入背景图片
            bg = pygame.transform.scale(bg, (240, 320))             #修改背景图片大小,以匹配屏幕
            title1 = titlefont.render('别踩', True, (0, 0, 0))
            title2 = titlefont.render('白块', True, (255, 255, 255))    #生成双色标题
            screen.blit(bg,(0,0))   #绘制背景
            screen.blit(title1, (40, 40))
            screen.blit(title2, (120, 40))#绘制标题
            screen.blit(pygame.image.load("pic/start-5.png"), (30, 190))# 在(30,190)显示图片start-5.png
            pygame.display.update()   #显示开始界面到屏幕
            
            
            
            global t_x, t_y # 定义两个全局变量t_x, t_y
            t_x, t_y = pygame.mouse.get_pos() # 获取鼠标的x和y坐标位,存储到变量t_x, t_y中
            if 30 <= t_x <= 200 and 190 <= t_y <= 250:# 18*50 # 如果鼠标移动到“开始游戏”的图片范围内
                screen.blit(pygame.image.load("pic/start-6.png"),(30, 190))# 在(30,190)切换图片为start-6.png
            if event.type == pygame.MOUSEBUTTONUP and 30 <= t_x <= 200 and 190 <= t_y <= 250: # 如果鼠标被释放且横纵坐标在“开始游戏”图片的范围内
                game_page = True    # 定义游戏页面状态为True,进入游戏页面
                start_page = False# 定义开始页面状态为False,退出开始页面   
      pygame.display.flip()# 更新全部显示

游戏界面部分。
初始化参数,绘制初始游戏界面以及初始黑块布局。倒计时开始。
核心逻辑是判断鼠标点击事件,判定是否为最后一行。
若在最后一行,并在黑块区域,则得分+1,刷新黑块位置,蜂鸣器震动反馈。若不在黑块位置,则游戏结束。
(由于行空板使用的电容屏精度较低,容易发生误触或者错误判定,本代码中已默认屏蔽点错结束的分支,若有兴趣者可自行取消注释开启)
if game_page:   #游戏界面
      game_over = False   #游戏结束为否
      start_page = False#开始界面为否
      screen.fill((255,255,255))# 填充白色,刷新背景
      Score = 0   #初始化分数
      start_timer1()#开始计时器
      draw_line()   #分割线绘制
      for sub_list in lists:      #绘制初始黑块
             rect(sub_list,point_color)
      while game_page:
            pygame.display.flip()# 更新全部显示
      
            for event in pygame.event.get():
                if event.type == pygame.QUIT:# 如果单击关闭窗口,则退出
                  pygame.quit()# 退出pygame
                elif event.type == TIMER1_EVENT:    #计时器触发,每秒一次
                  on_timer1() #触发倒计时程序
                if event.type == pygame.MOUSEBUTTONUP and 240 <= event.pos <= 320:   #判定鼠标点击是否为最后一行
                  
                  if lists.col*60 <= event.pos <= lists.col*60+60:   #判定鼠标点击位置是否有黑块
                        i = 3
                        for i in range(3,0,-1):
                            lists.col = lists.col   #将每行黑块的列数传递给下一行黑块,实现黑块的下降

                        lists.col =random.randint(0,COL-1)   #最上方黑块在随机列重新生成
                        Score = Score + 1   #分数加一
                        print (Score)
                        #重新绘制游戏画面,改变黑块位置并重绘计时和分数
                        screen.fill((255,255,255))
                        for sub_list in lists:
                            rect(sub_list,point_color)
                        pygame.draw.rect(screen,(255,255,255),(210,0,25,22))
                        timer_dis = timerfont.render(str(seconds),True,(255,0,0))   #计时重绘
                        screen.blit(timer_dis,(210,0))
                        pygame.draw.rect(screen,(255,255,255),(0,0,25,22))
                        Score_dis = timerfont.render(str(Score),True,(255,0,0))   #计分绘制
                        screen.blit(Score_dis,(0,0))
                        buzzer.pitch(988,1)   #蜂鸣器触发
                        draw_line()             #分割线绘制
                        pygame.display.flip()   #显示刷新
                  '''else:    #若按到了白块
                        game_over = True
                        game_page = False'''#跳转到结算页面

结算界面部分:
当游戏跳出游戏界面后,显示最终得分,并显示重新开始标题。
若判定到鼠标点击标题部分,则跳转回游戏部分,重新计时计分。
if game_over:   #结算页面
            screen.fill((255,255,255))#覆盖背景
            Score_fin = scorefont.render("Score:"+ str(Score),True,(255,0,0))
            screen.blit(Score_fin,(25,150))   #显示最终得分
            retry = titlefont.render('重新开始?', True, (0, 0, 0))
            screen.blit(retry,(40,200))   #绘制重新开始标题
            pygame.display.flip()   显示刷新
            while game_over:
               for event in pygame.event.get():
                        if event.type == pygame.QUIT:# 如果单击关闭窗口,则退出
                            pygame.quit()# 退出pygame
                        if event.type == pygame.MOUSEBUTTONUP and 40 <= event.pos <= 200 and 190 <= event.pos <= 240: # 如果鼠标被释放且横纵坐标在“重新开始”标题的范围内
                            game_page = True    #重新返回游戏界面
                            game_over = False

结果展示:

https://www.bilibili.com/video/BV1tR4y1m7aD/?vd_source=d849a6095658607c43e2380b2aa938b6









三春牛-创客 发表于 2023-1-6 09:18:07

厉害厉害

三春牛-创客 发表于 2023-1-6 09:19:23

有潜能啊!{:6_213:}

三春牛-创客 发表于 2023-1-6 09:20:30

这个可以加精华了吧

三春牛-创客 发表于 2023-1-6 09:21:33

赞!                     

三春牛-创客 发表于 2023-1-6 09:22:51

支持支持!

Xiaoyan 发表于 5 天前


支持支持!{:6_213:}
页: [1]
查看完整版本: 行空版使用pygame实现别踩白块游戏