行空版使用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
厉害厉害 有潜能啊!{:6_213:} 这个可以加精华了吧 赞! 支持支持!
支持支持!{:6_213:}
页:
[1]