使用Pygame制作“吃豆人”游戏

本篇博客展示如何使用 Python + Pygame 编写一个简易版的“吃豆人(Pac-Man)” 风格游戏。这里我们暂且命名为 Py-Man。玩家需要控制主角在一个网格地图里移动、吃掉散布在各处的豆子,并躲避在地图中巡逻的幽灵。此示例可帮助你理解网格地图角色移动敌人随机移动碰撞与得分等常见2D游戏开发技巧。


1. 前言

吃豆人(Pac-Man) 自 1980 年诞生以来,一直是街机游戏史上的里程碑作品。它的核心玩法是:

  • 玩家控制吃豆人(Pac-Man),在迷宫状的地图里收集豆子;
  • 幽灵(Ghost)会在地图中巡逻,玩家要设法规避幽灵追击;
  • 当豆子吃光或玩家被幽灵抓到,游戏结束。

本篇中,我们编写一个缩小且精简的“吃豆人”原型示例,重点演示:

  • 地图使用网格表示:不同数字代表墙壁、豆子、幽灵、可行走区域等;
  • 玩家(Pac-Man)的移动:基于方向键上下左右移动,每次移动一格;
  • 幽灵的随机行动:每帧可能随机选择一个方向前进(如遇墙则停留或换方向);
  • 碰撞和得分:吃完全部豆子即胜利,若与幽灵坐标重叠则游戏失败。

2. 开发环境

  1. Python 3.x
  2. Pygame 库:若未安装可通过
    pip install pygame
    
  3. 支持图形界面的操作系统:Windows、macOS 或绝大多数 Linux 均可。

在确保 import pygame 没有报错后,即可开始项目的开发。


3. 游戏设计思路

  1. 网格地图(MAP)

    • 使用一个二维列表来表示地图;
    • 为简化,我们定义:
      • 1 表示墙壁,不可通过;
      • 2 表示幽灵初始位置;
      • 3 表示豆子,需要被吃掉;
      • 4 表示玩家初始位置;
      • 0 表示空地,可以行走。
    • 当然,实际 Pac-Man 会有更复杂的地图布局,这里只做示例。
  2. 玩家

    • 存储玩家的网格坐标 (row, col)
    • 通过键盘上下左右控制每次移动一格;
    • 若目标位置是墙壁则保持不动,否则进入该格;
    • 如果在有豆子的格子上,就吃掉该豆子并加分。
  3. 幽灵

    • 地图可含多个幽灵;
    • 每帧随机选择一个方向移动,如果该方向是墙壁或出界,则不移动或重新选择;
    • 当玩家和幽灵坐标重叠时,游戏失败。
  4. 得分与胜利

    • 每当玩家吃掉一颗豆子(3),得分增加 1,并将该格子改为 0;
    • 如果全部豆子都被吃光,游戏胜利。
  5. 游戏循环

    • 处理键盘事件与幽灵的随机移动;
    • 更新玩家与幽灵位置;
    • 检测玩家是否吃到豆子、是否与幽灵碰撞;
    • 如果游戏结束或胜利,则跳转到结束场景。

4. 完整示例代码

将以下代码保存为 py_man.py 并执行。你可根据需要自定义地图大小、关卡布局、移动速度、幽灵 AI 等来拓展本示例。

import pygame
import sys
import random# 初始化 Pygame
pygame.init()# -----------------------
# 全局配置
# -----------------------
TILE_SIZE = 40     # 每个格子的像素大小
FPS = 8            # 帧率(适当降低 以便看清幽灵移动)
WHITE = (255, 255, 255)
BLACK = (0,   0,   0)
BLUE  = (0,   0, 255)
GREEN = (0, 200,   0)
RED   = (255,   0,  0)
YELLOW= (255, 255, 0)
GRAY  = (100, 100, 100)# 地图定义:1-墙,2-幽灵,3-豆子,4-玩家位置,0-空地
GAME_MAP = [[1,1,1,1,1,1,1,1,1,1],[1,4,3,3,0,3,3,3,3,1],[1,3,1,1,3,1,1,1,0,1],[1,3,1,2,3,1,2,3,3,1],[1,3,3,3,3,3,3,1,3,1],[1,0,1,3,1,3,1,3,3,1],[1,3,1,3,1,3,1,3,3,1],[1,3,3,3,3,3,3,3,3,1],[1,3,3,1,3,0,3,3,3,1],[1,1,1,1,1,1,1,1,1,1],
]ROWS = len(GAME_MAP)
COLS = len(GAME_MAP[0])SCREEN_WIDTH = COLS * TILE_SIZE
SCREEN_HEIGHT = ROWS * TILE_SIZEscreen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Py-Man 简易吃豆人")
clock = pygame.time.Clock()
font = pygame.font.SysFont("arial", 32)# -----------------------
# 玩家类
# -----------------------
class Player:def __init__(self, row, col):self.row = rowself.col = colself.score = 0def move(self, dr, dc):new_row = self.row + drnew_col = self.col + dcif 0 <= new_row < ROWS and 0 <= new_col < COLS:# 如果不是墙(1),则可移动if GAME_MAP[new_row][new_col] != 1:self.row = new_rowself.col = new_col@propertydef x(self):return self.col * TILE_SIZE@propertydef y(self):return self.row * TILE_SIZE# -----------------------
# 幽灵类
# -----------------------
class Ghost:def __init__(self, row, col):self.row = rowself.col = coldef update(self):# 随机尝试一个方向移动(上下左右)directions = [(-1,0), (1,0), (0,-1), (0,1)]dr, dc = random.choice(directions)new_row = self.row + drnew_col = self.col + dc# 如果新位置不是墙,且在地图内,则移动if 0 <= new_row < ROWS and 0 <= new_col < COLS:if GAME_MAP[new_row][new_col] != 1:self.row = new_rowself.col = new_col@propertydef x(self):return self.col * TILE_SIZE@propertydef y(self):return self.row * TILE_SIZE# -----------------------
# 工具函数:初始化游戏对象
# -----------------------
def init_game():player = Noneghosts = []for r in range(ROWS):for c in range(COLS):cell = GAME_MAP[r][c]if cell == 4:  # 玩家player = Player(r, c)# 恢复成空地GAME_MAP[r][c] = 0elif cell == 2:  # 幽灵ghosts.append(Ghost(r, c))# 恢复成空地GAME_MAP[r][c] = 0return player, ghosts# -----------------------
# 主游戏逻辑
# -----------------------
def main():player, ghosts = init_game()running = True# 统计剩余豆子数total_beans = sum(row.count(3) for row in GAME_MAP)while running:clock.tick(FPS)# 1) 事件处理for event in pygame.event.get():if event.type == pygame.QUIT:running = False# 2) 键盘输入(上下左右)keys = pygame.key.get_pressed()if keys[pygame.K_UP]:player.move(-1, 0)elif keys[pygame.K_DOWN]:player.move(1, 0)elif keys[pygame.K_LEFT]:player.move(0, -1)elif keys[pygame.K_RIGHT]:player.move(0, 1)# 玩家若踩到豆子(3),吃掉并得分if GAME_MAP[player.row][player.col] == 3:GAME_MAP[player.row][player.col] = 0player.score += 1# 若吃完所有豆子 -> 胜利if player.score == total_beans:running = Falsegame_over(won=True, score=player.score)continue# 幽灵随机移动for g in ghosts:g.update()# 检测玩家是否与幽灵相碰for g in ghosts:if g.row == player.row and g.col == player.col:# 玩家失败running = Falsegame_over(won=False, score=player.score)break# 3) 绘制场景screen.fill(BLACK)# 绘制地图for r in range(ROWS):for c in range(COLS):tile = GAME_MAP[r][c]x = c * TILE_SIZEy = r * TILE_SIZEif tile == 1:  pygame.draw.rect(screen, BLUE, (x, y, TILE_SIZE, TILE_SIZE))  # 墙elif tile == 3:  pygame.draw.circle(screen, YELLOW, (x + TILE_SIZE//2, y + TILE_SIZE//2), TILE_SIZE//6)  # 豆子else:# 通路 or 空地pygame.draw.rect(screen, GRAY, (x, y, TILE_SIZE, TILE_SIZE))# 绘制玩家 (绿色圆)pygame.draw.circle(screen, GREEN, (player.x + TILE_SIZE//2, player.y + TILE_SIZE//2), TILE_SIZE//2 - 4)# 绘制幽灵 (红色方块)for g in ghosts:pygame.draw.rect(screen, RED, (g.x+5, g.y+5, TILE_SIZE-10, TILE_SIZE-10))# 分数score_surf = font.render(f"Score: {player.score}", True, WHITE)screen.blit(score_surf, (10, 10))pygame.display.flip()pygame.quit()sys.exit()def game_over(won, score):screen.fill(BLACK)if won:msg = f"恭喜,你吃掉所有豆子!得分: {score}"else:msg = f"被幽灵抓住了!得分: {score}"label = font.render(msg, True, WHITE)rect = label.get_rect(center=(SCREEN_WIDTH//2, SCREEN_HEIGHT//2))screen.blit(label, rect)pygame.display.flip()pygame.time.wait(3000)  # 等待3秒再退出if __name__ == "__main__":main()

代码说明

  1. 地图 GAME_MAP

    • 用一个二维列表存储地图信息,示例尺寸 10×10:
      • 1(蓝色方块)表示墙壁;
      • 3(黄色小圆)表示豆子;
      • 24 仅用于初始位置记录,随后会被设为 0
    • 你可以自行扩展地图,或使用文件读取的方式加载更大规模的关卡。
  2. 玩家与幽灵

    • 玩家每帧检测上下左右键,若不是墙就移动。并且若所在格子是豆子就得分、把该格子变成空地;
    • 幽灵update() 里随机选择一个方向移动,如果遭遇墙壁则保持原地或尝试别的方向。
    • 玩家坐标幽灵坐标一致,则判定失败。
  3. 得分与胜利

    • 统计地图中豆子的总数 total_beans
    • 如果玩家吃掉的豆子数与 total_beans 相等,则判定胜利;
    • 碰到幽灵则立即失败。
  4. 绘制

    • 墙壁用蓝色矩形,豆子用黄色小圆,空地用灰色背景
    • 玩家用绿色圆,幽灵用红色小方块
    • 你可以替换为更精美的贴图或动画帧,让游戏看起来更加逼真。

5. 运行效果

image.png


6. 总结

通过本篇示例,你已掌握了一个简化“吃豆人” 原型所需的关键实现,你可以在此基础上,结合你对 Pac-Man 的灵感或其他创意,一步步将这个简易示例打磨成更完备、更具乐趣的 2D 游戏。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/12157.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu磁盘扩容

ubuntu磁盘扩容 描述先在虚拟机设置里面扩容进入Ubuntu 配置使用命令行工具parted进行分区输出如下完成 描述 执行命令,查看 fs 类型是什么 lsblk -o NAME,FSTYPE,MOUNTPOINT将60G扩容到100G&#xff0c;其中有些操作我也不知道什么意思&#xff0c;反正就是成功了&#xff0…

redis底层数据结构

底层数据结构 了解下这些咱常用的数据其底层实现是啥 在提到使用哪类数据结构之前&#xff0c;先来了解下redis底层到底有多少种数据结构 1&#xff0c;sds动态字符串 概念与由来 redis是一种使用C语言编写的nosql&#xff0c;redis存储的key数据均为string结构&#xff0…

ChatGPT怎么回事?

纯属发现&#xff0c;调侃一下~ 这段时间deepseek不是特别火吗&#xff0c;尤其是它的推理功能&#xff0c;突发奇想&#xff0c;想用deepseek回答一些问题&#xff0c;回答一个问题之后就回复服务器繁忙&#xff08;估计还在被攻击吧~_~&#xff09; 然后就转向了GPT&#xf…

趣味Python100例初学者练习01

1. 1 抓交通肇事犯 一辆卡车违反交通规则&#xff0c;撞人后逃跑。现场有三人目击该事件&#xff0c;但都没有记住车号&#xff0c;只记下了车号的一些特征。甲说&#xff1a;牌照的前两位数字是相同的&#xff1b;乙说&#xff1a;牌照的后两位数字是相同的&#xff0c;但与前…

2024-我的学习成长之路

因为热爱&#xff0c;无畏山海

蓝桥杯备考:高精度算法之除法

我们除法的高精度其实也不完全是高精度&#xff0c;而是一个高精度作被除数除以一个低精度 模拟我们的小学除法 由于题目中我们的除数最大是1e9&#xff0c;当它真正是1e9的时候&#xff0c;t是有可能超过1e9的&#xff0c;所以要用long long

Maven jar 包下载失败问题处理

Maven jar 包下载失败问题处理 1.配置好国内的Maven源2.重新下载3. 其他问题 1.配置好国内的Maven源 打开⾃⼰的 Idea 检测 Maven 的配置是否正确&#xff0c;正确的配置如下图所示&#xff1a; 检查项⼀共有两个&#xff1a; 确认右边的两个勾已经选中&#xff0c;如果没有请…

【前端】ES6模块化

文章目录 1. 模块化概述1.1 什么是模块化?1.2 为什么需要模块化? 2. 有哪些模块化规范3. CommonJs3.1 导出数据3.2 导入数据3.3 扩展理解3.4 在浏览器端运行 4.ES6模块化4.1 浏览器运行4.2 在node服务端运行4.3 导出4.3.1 分别导出4.3.2 统一导出4.3.3 默认导出4.3.4 混用 4.…

强化学习笔记(5)——PPO

PPO视频课程来源 首先理解采样期望的转换 变量x在p(x)分布下&#xff0c;函数f(x)的期望 等于f(x)乘以对应出现概率p(x)的累加 经过转换后变成 x在q(x)分布下&#xff0c;f(x)*p(x)/q(x) 的期望。 起因是&#xff1a;求最大化回报的期望&#xff0c;所以对ceta求梯度 具体举例…

20-30 五子棋游戏

20-分析五子棋的实现思路_哔哩哔哩_bilibili20-分析五子棋的实现思路是一次性学会 Canvas 动画绘图&#xff08;核心精讲50个案例&#xff09;2023最新教程的第21集视频&#xff0c;该合集共计53集&#xff0c;视频收藏或关注UP主&#xff0c;及时了解更多相关视频内容。https:…

【HTML入门】Sublime Text 4与 Phpstorm

文章目录 前言一、环境基础1.Sublime Text 42.Phpstorm(1)安装(2)启动Phpstorm(3)“启动”码 二、HTML1.HTML简介(1)什么是HTML(2)HTML版本及历史(3)HTML基本结构 2.HTML简单语法(1)HTML标签语法(2)HTML常用标签(3)表格(4)特殊字符 总结 前言 在当今的软件开发领域&#xff0c…

Kubernetes学习之包管理工具(Helm)

一、基础知识 1.如果我们需要开发微服务架构的应用&#xff0c;组成应用的服务可能很多&#xff0c;使用原始的组织和管理方式就会非常臃肿和繁琐以及较难管理&#xff0c;此时我们需要一个更高层次的工具将这些配置组织起来。 2.helm架构&#xff1a; chart:一个应用的信息集合…

Kamailio 不通过 dmq 实现注册复制功能

春节期间找到一篇文章&#xff0c;需要 fg 才能看到&#xff1a; https://medium.com/tumalevich/kamailio-registration-replication-without-dmq-65e225f9a8a7 kamailio1 192.168.56.115 kamailio2 192.168.56.116 kamailio3 192.168.56.117 route[HANDLE_REPLICATION] {i…

grpc 和 http 的区别---二进制vsJSON编码

gRPC 和 HTTP 是两种广泛使用的通信协议&#xff0c;各自适用于不同的场景。以下是它们的详细对比与优势分析&#xff1a; 一、核心特性对比 特性gRPCHTTP协议基础基于 HTTP/2基于 HTTP/1.1 或 HTTP/2数据格式默认使用 Protobuf&#xff08;二进制&#xff09;通常使用 JSON/…

Intel 与 Yocto 项目的深度融合:全面解析与平台对比

在嵌入式 Linux 领域&#xff0c;Yocto 项目已成为构建定制化 Linux 发行版的事实标准&#xff0c;广泛应用于不同架构的 SoC 平台。Intel 作为 x86 架构的领导者&#xff0c;在 Yocto 生态中投入了大量资源&#xff0c;为其嵌入式处理器、FPGA 和 AI 加速硬件提供了完整的支持…

kubernetes(二)

文章目录 NamespacePodLabelDeploymentService Namespace 在Kubernetes系统中&#xff0c;Namespace是一种至关重要的资源类型&#xff0c;其主要功能在于实现多套环境的资源隔离或者多租户的资源隔离&#xff0c;默认情况下所有的Pod都能够相互访问&#xff0c;但如果不想让两…

巧妙利用数据结构优化部门查询

目录 一、出现的问题 部门树接口超时 二、问题分析 源代码分析 三、解决方案 具体实现思路 四、优化的效果 一、出现的问题 部门树接口超时 无论是在A项目还是在B项目中&#xff0c;都存在类似的页面&#xff0c;其实就是一个部门列表或者叫组织列表。 从页面的展示形式…

【数据分析】案例04:豆瓣电影Top250的数据分析与Web网页可视化(numpy+pandas+matplotlib+flask)

豆瓣电影Top250的数据分析与Web网页可视化(numpy+pandas+matplotlib+flask) 豆瓣电影Top250官网:https://movie.douban.com/top250写在前面 实验目的:实现豆瓣电影Top250详情的数据分析与Web网页可视化。电脑系统:Windows使用软件:PyCharm、NavicatPython版本:Python 3.…

【线程】基于环形队列的生产者消费者模型

1 环形队列 环形队列采用数组来模拟&#xff0c;用取模运算来模拟环状特性。 1.如何判断环形队列为空或者为满? 当环形队列为空时&#xff0c;头和尾都指向同一个位置。当环形队列为满时&#xff0c;头和尾也都指向同一个位置。 因此&#xff0c; 可以通过加计数器或者标记…

Vue指令v-html

目录 一、Vue中的v-html指令是什么&#xff1f;二、v-html指令与v-text指令的区别&#xff1f; 一、Vue中的v-html指令是什么&#xff1f; v-html指令的作用是&#xff1a;设置元素的innerHTML&#xff0c;内容中有html结构会被解析为标签。 二、v-html指令与v-text指令的区别…