很多人在刚开始学习编程的时候,都会有一个很简单但很有趣的想法:能不能自己做一个小游戏?当代码不再只是打印几行文字,而是能够做出一个可以点击、可以互动、甚至可以玩的程序时,那种成就感是非常强的。
这篇文章主要想分享一下,我用 Python + pygame 实现《别踩白块》小游戏的过程。整体代码不算多,但从界面、交互到游戏状态切换,做下来还是挺有意思的。
下面就从环境准备开始,一步一步实现这个《别踩白块》小游戏。
安装 pygame 很简单,直接使用 pip 即可。如果使用 Anaconda 管理 Python 环境,也可以先激活自己的虚拟环境,再执行安装命令。import pygameimport randomimport syspygame.init() # 初始化 pygame 库的所有模块
W, H = 400, 600 # 窗口宽高COLS = 4 # 一排的方块数量CELL_W = W // COLS # 一个方块的宽度 “//” 向下取整像素不能为小数ROW_H = 150 # 一个方块的高度screen = pygame.display.set_mode((W, H)) # 窗口初始化pygame.display.set_caption("别踩白块")clock = pygame.time.Clock() # 游戏计时器,控制帧率FPSfont = pygame.font.SysFont("simhei", 36) # 字体设置# 用到的颜色RGBWHITE = (255, 255, 255)BLACK = (0, 0, 0)GRAY = (200, 200, 200)RED = (220, 50, 50)state = "start" # 游戏状态 "start、play、over" 初始为"start"rows = []speed = 5 # 方块移动速度score = 0 # 得分# 数据列表,存的数据结构如下# 开始和重新开始按钮start_btn = pygame.Rect(140, 320, 100, 50)again_btn = pygame.Rect(145, 340, 120, 50)
# 这部分为注释{"y": 150, "black": 2, "clicked": False} → 字典y → 这一行在屏幕上的高度black → 黑块在第几列clicked → 黑块有没有被点击pygame.Rect(x, y, width, height)x → 左上角的横坐标y → 左上角的纵坐标width → 宽度height → 高度
# 创建一行新的方块数据def new_row(y): return {"y": y, "black": random.randint(0, COLS - 1), "clicked": False}
# 这部分为注释y:纵坐标位置random.randint(0, COLS - 1):随机生成0-3随机数False:初始黑块未被点击
# 游戏恢复到初始状态def reset(): global rows, speed, score # 声明全局变量 rows = [new_row(-i * ROW_H) for i inrange(5)] speed = 5 score = 0
# 获取游戏未被点击的做后一行def get_lowest_row(): r = None maxy = -9999 for row in rows: if not row["clicked"] and row["y"] > maxy: maxy = row["y"] r = row return r
# 开始界面def draw_start(): screen.fill(WHITE) # 清空屏幕,设置白色 title = font.render("别踩白块", True, BLACK) # 绘制别踩白块文字图像,标题 pygame.draw.rect(screen, BLACK, start_btn) # 绘制矩形按钮 text = font.render("开始", True, WHITE) # 绘制开始文字图像 # 放置图像位置到屏幕上 screen.blit(title, (120, 200)) screen.blit(text, (155, 325)) pygame.display.flip() # 更新屏幕,刷新显示
# 游戏界面def draw_game(): screen.fill(WHITE) for row in rows: for c in range(COLS): rect = pygame.Rect(c * CELL_W, row["y"], CELL_W, ROW_H) # 计算一行方块位置 color = BLACK if c == row["black"] and not row["clicked"] else WHITE # 设置方块颜色 pygame.draw.rect(screen, color, rect) # 绘制方块 pygame.draw.rect(screen, GRAY, rect, 2) # 绘制线宽 s = font.render(f"分数:{score}", True, RED) # 分数设置 screen.blit(s, (10, 10)) # 左上角 pygame.display.flip()
# 结束界面def draw_over(): screen.fill(WHITE) over = font.render("游戏结束", True, RED) pygame.draw.rect(screen, BLACK, again_btn) again = font.render("重来", True, WHITE) screen.blit(over, (130, 220)) screen.blit(again, (170, 350)) s = font.render(f"分数:{score}", True, BLACK) screen.blit(s, (150, 280)) pygame.display.flip()
while True: clock.tick(60) # 设置画面为60帧 for event in pygame.event.get(): # 监听所有鼠标键盘事件 if event.type == pygame.QUIT: # QUIT:右上角× pygame.quit() # 关闭pygame 的所有模块 sys.exit() # 退出整个py程序 # 判断游戏状态 if state == "start": # MOUSEBUTTONDOWN 按下鼠标 if event.type == pygame.MOUSEBUTTONDOWN: # 监听指针是否在开始按钮的框内 if start_btn.collidepoint(event.pos): reset() state = "play" elif state == "play": if event.type == pygame.MOUSEBUTTONDOWN: mx, my = event.pos # 鼠标坐标 col = mx // CELL_W row = get_lowest_row() if row and row["y"] <= my <= row["y"] + ROW_H: if col == row["black"]: row["clicked"] = True score += 1 speed = 5 + score * 0.1 # 游戏加速 else: state = "over" else: state = "over" elif state == "over": if event.type == pygame.MOUSEBUTTONDOWN: if again_btn.collidepoint(event.pos): reset() state = "play" # 循环如此 if state == "play": for row in rows: row["y"] += speed for row in rows: if row["y"] >= H: if not row["clicked"]: state = "over" else: top = min(r["y"] for r in rows) row["y"] = top - ROW_H row["black"] = random.randint(0, COLS - 1) row["clicked"] = False draw_game() elif state == "start": draw_start() elif state == "over": draw_over()
这次就先把这个简单版的《别踩白块》小游戏做到这里。虽然整体代码量不算多,但从界面搭建到交互逻辑,再到游戏状态切换,已经把一个小游戏的基本结构串了起来。
自己动手把一个想法真正写成可以运行的程序,还是很有成就感的。后面如果有时间,我也会继续在这个基础上补充一些功能,比如音效、最高分记录,或者更完整一点的界面效果。也希望能和大家一起,在这个公众号里记录更多实现过程和成长收获。
文章里用到的 Python 源码已经同步整理好了,这里一并放出来,方便直接下载参考。
文件名:别踩白块.py
链接: https://pan.baidu.com/s/1GVPJ8qRTWSGbvnIqaZV0eQ?pwd=fkdx