2023-1-5 14:58:28 [显示全部楼层]
2498浏览
查看: 2498|回复: 5

[M10项目] 行空版使用pygame实现别踩白块游戏

[复制链接]
本帖最后由 NeloKin 于 2023-1-5 14:58 编辑

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



硬件介绍:

  • 行空板UNIHIKER
  • USB免驱扬声器


软件清单:

  • Mind+ Python代码模式





项目文件下载:
下载附件别踩白块_行空.zip

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

代码详解:


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


初始化pygame游戏窗口,初始化参数
  1. pygame.init()  # 初始化pygame
  2. width =240     # 定义宽
  3. height=320     # 定义高
  4. size=(240,320)  # 定义尺寸
  5. screen = pygame.display.set_mode(size) # 创建游戏窗口,尺寸为(240,320)
  6. global start_page   #开始页定义
  7. global game_page    #游戏页定义
  8. start_page = True   #初始化开始页为真
  9. game_page = False   #初始化游戏页为否
复制代码


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

  1. # 将游戏窗口划分为一个个小方格,每个方格的宽为60,高为80,共计4行,4列
  2. ROW=4 # 定义行数,
  3. COL=4 # 定义列数
  4. cell_width=width/COL # 定义格子的宽
  5. cell_height=height/ROW # 定义格子的高
  6. class Point:
  7.     row=0 # 行
  8.     col=0 # 列
  9.     def __init__(self,row,col): # 行 列
  10.         self.row=row
  11.         self.col=col
  12. point_color = (0,0,0)   #块颜色为黑
  13. def rect(point,color):
  14.     left=point.col*cell_width # 定义方格距离左边缘的距离
  15.     top=point.row*cell_height # 定义方格距离上边缘的距离
  16.     pygame.draw.rect(screen,color,(left,top,cell_width,cell_height)) # 在窗口上绘制矩形,颜色为color
复制代码
载入背景音乐,准备文字字体,已经初始黑块排列的生成。

这里使用list类作为黑块的地址存储方式,存储四个point类,表示屏幕上显示的四个黑块,每行一个。初始黑块横坐标位置随机生成。
  1. # 载入背景音乐
  2. pygame.mixer.music.load('sounds/bgm.mp3')
  3. pygame.mixer.music.play(-1)     #循环播放
  4. pygame.mixer.music.set_volume(1)    #设定音量可调整
  5. # 文本准备
  6. scorefont = pygame.font.SysFont('Arial', 40)  # 创建计分器Font字体对象
  7. timerfont = pygame.font.SysFont('Arial', 20)  # 创建计时器Font字体对象
  8. titlefont = pygame.font.Font('chinese.ttf', 40)    # 创建标题Font字体对象
  9. #计时器准备
  10. TIMER1_EVENT = pygame.USEREVENT
  11. #创建初始黑块队列,在0到3内随机,每行一块
  12. lists = [Point(row = 0, col = random.randint(0,COL-1)),
  13.         Point(row = 1, col = random.randint(0,COL-1)),
  14.         Point(row = 2, col = random.randint(0,COL-1)),
  15.         Point(row = 3, col = random.randint(0,COL-1))
  16. ]  
复制代码


定义计时器功能,使用pygame的time库内set——time函数,作为时间事件触发,每次触发减少倒计时,并刷新时间显示。归零后跳转结算界面。
  1. #初始化计时器,设定倒计时秒数
  2. def start_timer1():
  3.     global seconds
  4.     seconds = 60
  5.     pygame.time.set_timer(TIMER1_EVENT, 1000)
  6. #计时器触发时,复写秒数显示,并减少计时秒数。
  7. def on_timer1():
  8.     global seconds
  9.     global game_over
  10.     global game_page
  11.     print (seconds)
  12.     pygame.draw.rect(screen,(255,255,255),(210,0,25,22))
  13.     timer_dis = timerfont.render(str(seconds),True,(255,0,0))
  14.     screen.blit(timer_dis,(210,0))
  15.     pygame.display.flip()
  16.     seconds -= 1
  17.     if seconds < 0:     #若归零,则跳转到结算页面,计时器停止
  18.         pygame.time.set_timer(TIMER1_EVENT, 0)
  19.         game_over = True
  20.         game_page = False
复制代码


定义分割线绘制功能,美化游戏界面。
  1. def draw_line():    #绘制分割线
  2.     pygame.draw.line(screen,(0,0,0),(0,80),(240,80))
  3.     pygame.draw.line(screen,(0,0,0),(0,160),(240,160))
  4.     pygame.draw.line(screen,(0,0,0),(0,240),(240,240))
  5.     pygame.draw.line(screen,(0,0,0),(60,0),(60,320))
  6.     pygame.draw.line(screen,(0,0,0),(120,0),(120,320))
  7.     pygame.draw.line(screen,(0,0,0),(180,0),(180,320))
复制代码

接下来为主程序循环部分,接在while True函数内。


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


游戏界面部分。
初始化参数,绘制初始游戏界面以及初始黑块布局。倒计时开始。
核心逻辑是判断鼠标点击事件,判定是否为最后一行。
若在最后一行,并在黑块区域,则得分+1,刷新黑块位置,蜂鸣器震动反馈。若不在黑块位置,则游戏结束。
(由于行空板使用的电容屏精度较低,容易发生误触或者错误判定,本代码中已默认屏蔽点错结束的分支,若有兴趣者可自行取消注释开启)
  1. if game_page:   #游戏界面
  2.         game_over = False   #游戏结束为否
  3.         start_page = False  #开始界面为否
  4.         screen.fill((255,255,255))  # 填充白色,刷新背景
  5.         Score = 0   #初始化分数
  6.         start_timer1()  #开始计时器
  7.         draw_line()     #分割线绘制
  8.         for sub_list in lists:      #绘制初始黑块
  9.              rect(sub_list,point_color)
  10.         while game_page:
  11.             pygame.display.flip()  # 更新全部显示
  12.         
  13.             for event in pygame.event.get():
  14.                 if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
  15.                     pygame.quit()  # 退出pygame
  16.                 elif event.type == TIMER1_EVENT:    #计时器触发,每秒一次
  17.                     on_timer1() #触发倒计时程序
  18.                 if event.type == pygame.MOUSEBUTTONUP and 240 <= event.pos[1] <= 320:   #判定鼠标点击是否为最后一行
  19.                     
  20.                     if lists[3].col*60 <= event.pos[0] <= lists[3].col*60+60:   #判定鼠标点击位置是否有黑块
  21.                         i = 3
  22.                         for i in range(3,0,-1):
  23.                             lists[i].col = lists[i-1].col   #将每行黑块的列数传递给下一行黑块,实现黑块的下降
  24.                         lists[0].col =  random.randint(0,COL-1)     #最上方黑块在随机列重新生成
  25.                         Score = Score + 1   #分数加一
  26.                         print (Score)
  27.                         #重新绘制游戏画面,改变黑块位置并重绘计时和分数
  28.                         screen.fill((255,255,255))
  29.                         for sub_list in lists:
  30.                             rect(sub_list,point_color)
  31.                         pygame.draw.rect(screen,(255,255,255),(210,0,25,22))
  32.                         timer_dis = timerfont.render(str(seconds),True,(255,0,0))   #计时重绘
  33.                         screen.blit(timer_dis,(210,0))
  34.                         pygame.draw.rect(screen,(255,255,255),(0,0,25,22))
  35.                         Score_dis = timerfont.render(str(Score),True,(255,0,0))     #计分绘制
  36.                         screen.blit(Score_dis,(0,0))
  37.                         buzzer.pitch(988,1)     #蜂鸣器触发
  38.                         draw_line()             #分割线绘制
  39.                         pygame.display.flip()   #显示刷新
  40.                     '''else:    #若按到了白块
  41.                         game_over = True
  42.                         game_page = False'''#跳转到结算页面
复制代码


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


结果展示:












三春牛-创客  初级技神

发表于 2023-1-6 09:18:07

厉害厉害
回复

使用道具 举报

三春牛-创客  初级技神

发表于 2023-1-6 09:19:23

有潜能啊!
回复

使用道具 举报

三春牛-创客  初级技神

发表于 2023-1-6 09:20:30

这个可以加精华了吧
回复

使用道具 举报

三春牛-创客  初级技神

发表于 2023-1-6 09:21:33

赞!                     
回复

使用道具 举报

三春牛-创客  初级技神

发表于 2023-1-6 09:22:51

支持支持!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
关于楼主
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail