吃豆人(Pacman)作为1980年代风靡全球的街机游戏,以其简单却极具策略性的玩法成为游戏史上的经典。本文将通过Python的turtle库实现一个简化版吃豆人游戏,代码不仅还原了核心玩法——控制黄色吃豆人在迷宫中吃掉白色豆子,同时躲避红色鬼魂的追捕,还提供了丰富的拓展思路,让玩家可以自定义游戏体验。
吃豆人游戏由南梦宫公司于1980年推出,迅速成为街机游戏的标志性作品。本Python实现使用turtle图形库,这是一个适合初学者的Python标准库,通过简单的命令即可创建图形界面。
技术选择说明: 虽然turtle库性能有限,但对于教学和小型游戏开发非常合适。如需更复杂的游戏开发,可考虑Pygame或Arcade等专业游戏库。
"""Pacman, classic arcade game.
Exercises
1. Change the board.
2. Change the number of ghosts.
3. Change where pacman starts.
4. Make the ghosts faster/slower.
5. Make the ghosts smarter.
"""
from random import choice
from turtle import *
from freegames import floor, vector
# 游戏状态(得分)
state = {'score': 0}
# 绘图路径与分数显示
path = Turtle(visible=False)
writer = Turtle(visible=False)
# 吃豆人移动方向与初始位置
aim = vector(5, 0)
pacman = vector(-40, -80)
# 鬼魂列表(位置+移动方向)
ghosts = [
[vector(-180, 160), vector(5, 0)],
[vector(-180, -160), vector(0, 5)],
[vector(100, 160), vector(0, -5)],
[vector(100, -160), vector(-5, 0)],
]
# 迷宫地图(0=墙壁,1=豆子,2=已吃掉的豆子)
tiles = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
# 中间省略部分地图数据...
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]
def square(x, y):
"""绘制迷宫方块(墙壁或豆子所在格子)"""
path.up()
path.goto(x, y)
path.down()
path.begin_fill()
for _ in range(4):
path.forward(20)
path.left(90)
path.end_fill()
def offset(point):
"""计算坐标点在tiles数组中的索引偏移量"""
x = (floor(point.x, 20) + 200) / 20
y = (180 - floor(point.y, 20)) / 20
return int(x + y * 20)
def valid(point):
"""检测移动是否合法(非墙壁且在路径上)"""
index = offset(point)
if tiles[index] == 0:
return False
index = offset(point + 19)
if tiles[index] == 0:
return False
return point.x % 20 == 0 or point.y % 20 == 0
def world():
"""绘制游戏地图:黑色背景、蓝色墙壁、白色豆子"""
bgcolor('black')
path.color('blue')
for index in range(len(tiles)):
tile = tiles[index]
if tile > 0:
x = (index % 20) * 20 - 200
y = 180 - (index // 20) * 20
square(x, y)
if tile == 1: # 绘制豆子
path.up()
path.goto(x + 10, y + 10)
path.dot(2, 'white')
def move():
"""更新游戏状态:移动吃豆人与鬼魂,检测碰撞"""
writer.undo()
writer.write(state['score'])
clear()
# 吃豆人移动
if valid(pacman + aim):
pacman.move(aim)
index = offset(pacman)
if tiles[index] == 1: # 吃掉豆子
tiles[index] = 2
state['score'] += 1
x = (index % 20) * 20 - 200
y = 180 - (index // 20) * 20
square(x, y)
# 绘制吃豆人
up()
goto(pacman.x + 10, pacman.y + 10)
dot(20, 'yellow')
# 鬼魂移动(随机策略)
for point, course in ghosts:
if valid(point + course):
point.move(course)
else:
# 遇到墙壁时随机选择新方向
options = [vector(5, 0), vector(-5, 0), vector(0, 5), vector(0, -5)]
course.update(choice(options))
# 绘制鬼魂
up()
goto(point.x + 10, point.y + 10)
dot(20, 'red')
update()
# 检测吃豆人是否被鬼魂追上
for point, _ in ghosts:
if abs(pacman - point) < 20:
return
# 定时刷新游戏画面(100毫秒)
ontimer(move, 100)
def change(x, y):
"""改变吃豆人移动方向(仅当移动合法时)"""
if valid(pacman + vector(x, y)):
aim.x = x
aim.y = y
# 游戏初始化
setup(420, 420, 370, 0)
hideturtle()
tracer(False)
writer.goto(160, 160)
writer.color('white')
writer.write(state['score'])
# 绑定键盘事件
listen()
onkey(lambda: change(5, 0), 'Right')
onkey(lambda: change(-5, 0), 'Left')
onkey(lambda: change(0, 5), 'Up')
onkey(lambda: change(0, -5), 'Down')
world()
move()
done()
迷宫地图(tiles):使用一维数组表示20×20的网格,通过索引计算对应坐标:
0 表示墙壁1 表示可食用豆子2 表示已吃掉的豆子角色位置(vector):利用freegames库的vector类存储坐标,方便进行向量运算(如移动方向)。
地图绘制(world):遍历tiles数组,根据数值绘制蓝色墙壁和白色豆子,黑色背景形成经典吃豆人视觉效果。
移动逻辑(move):吃豆人按玩家输入方向移动,鬼魂采用"随机碰壁转向"策略,每次移动后检测碰撞与得分。
输入控制(change):绑定键盘方向键,实时更新吃豆人移动方向,确保移动合法(不穿墙)。
通过ontimer(move, 100)实现定时刷新,每100毫秒更新一次游戏状态,配合tracer(False)关闭自动刷新,手动调用update()提升画面流畅度。
性能提示: 在更复杂的游戏中,应考虑使用双缓冲技术或更高效的游戏循环机制来避免画面闪烁。
代码注释中给出了5个拓展练习,以下是具体实现思路:
直接修改tiles数组中的数值分布:
示例:将中间区域的墙壁改为通道,或设计"传送门"机制(当吃豆人到达特定坐标时瞬移到另一位置)。
修改ghosts列表的元素数量:
注意: 鬼魂数量过多可能导致画面卡顿,需适当调整移动间隔(ontimer的时间参数)。
修改pacman变量的初始坐标(如vector(0, 0)),并确保新起点在合法路径上(tiles[offset(pacman)] > 0)。
修改ghosts列表中移动向量的数值:
vector(5, 0),增大数值(如10)可加快速度原代码问题:鬼魂采用随机移动策略,缺乏智能性,可通过以下方式改进:
这个Python版吃豆人游戏通过turtle库直观展示了游戏开发的基本流程:地图建模、角色控制、碰撞检测与游戏循环。对于编程初学者,可通过修改代码理解游戏逻辑;对于进阶开发者,可尝试添加音效、计分系统、关卡切换等功能,甚至结合Pygame库实现更复杂的图形效果。
经典游戏的魅力在于其可扩展性,从简单的随机移动到智能AI,从固定地图到动态生成,每一次改进都是对编程思维的锻炼。希望这份代码能激发你对游戏开发的兴趣,探索更多创意可能!