Python随身听-源码分析-经典小游戏-pacman
周六了,让我们按照老规矩,一起读点代码放松一下吧!
今天要给大家看的代码是一段游戏的代码,这一次是一个 1980 年就诞生的经典游戏:pacman,中文翻译好像是吃豆人。其实就是一个迷宫,摆满了各种小豆子,一个小黄人去边走边吃,里面会有几个游荡的鬼魂,撞到了会让小黄人死翘翘,所以走起路来要小心啊!
游戏动图:
源码
建议先仔细阅读一下,然后再往后看 DE8UG 对源码的分析。
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)],
]
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, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0,
0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0,
0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 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, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0,
0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 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,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]
def square(x, y):
"Draw square using path at (x, y)."
path.up()
path.goto(x, y)
path.down()
path.begin_fill()
for count in range(4):
path.forward(20)
path.left(90)
path.end_fill()
def offset(point):
"Return offset of point in tiles."
x = (floor(point.x, 20) + 200) / 20
y = (180 - floor(point.y, 20)) / 20
index = int(x + y * 20)
return index
def valid(point):
"Return True if point is valid in tiles."
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():
"Draw world using path."
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():
"Move pacman and all ghosts."
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),
]
plan = choice(options)
course.x = plan.x
course.y = plan.y
up()
goto(point.x + 10, point.y + 10)
dot(20, 'red')
update()
for point, course in ghosts:
if abs(pacman - point) < 20:
return
ontimer(move, 100)
def change(x, y):
"Change pacman aim if valid."
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()
运行
复制上述代码到一个 py 为后缀的文件,命名 pacman.py.
在文件所在目录打开控制台:运行pip install freegames
,然后运行python pacman.py
分析
这个游戏代码里面有很多和之前给大家解说的代码(直接给公号后天回复搜索,然后搜游戏代码即可)类似的地方,这里就直接略过了。我们只看看和之前不一样的地方。
整体布局
这里是一个迷宫地图,左上角还需要显示分数,所以最开始的全局变量新建了两个 Turtle 对象,相当于两个画笔,一个画具体路径,一个更新分数。
整体布局是采用 world 函数完成的。最开始定义的 tiles 列表,里面用 0 和 1 指代了每一块瓦片的位置和是否有食物。绘制的时候,用 x,y 换算为从左上角开始的坐标位置,然后开始调用 square 函数开始绘制地图。注意这里整体偏左,因为右上角要留出位置记录分数。
移动与碰撞
在 move 函数中,还是如之前一样是一个定时循环。绘制每一次的动作。
最开始是分数的统计,采用重绘来进行。然后清理屏幕,判断小黄人的移动是否合法。接下来用 offset 函数把小黄人坐标映射回 tiles 列表的索引,去判断是否吃到食物,如果吃到,则重绘当前的方块,注意这时候其实和绘制整体地图时候一样,只是不再绘制中间的食物。
然后移动小黄人,绘制为黄色。
地图里面的小幽灵们是一直移动的,其实是循环每个的坐标位置,判断是否合法,合法就移动,不合法就给出一个设定好的坐标。
然后就判断小黄人是否和幽灵碰撞,即 abs(pacman - point) < 20,撞到也就 game over 了!
play!
接下来就是启动游戏,开始玩了 😊
ok,这就是本周六的源码分析了,祝你阅读愉快。目前在 Python 随身听的微信栏目里,已经从周一到周日安排了:技术精选,基础学习,Python 练习,项目连载,难点问答,源码分析,DE8UG 杂谈这些栏目,欢迎围观。有任何想法建议疑问欢迎留言,明天见~