• 003-Pacman_FreePythonGames


    一 相关知识

    1 choice()函数

    • 描述:choice() 方法返回一个列表,元组或字符串的随机项。
    • 语法:choice()是不能直接访问的,需要导入 random 模块,然后通过 random 静态对象调用该方法。
      • import random
      • random.choice( seq )
    • 参数:seq -- 可以是一个列表,元组或字符串。
    • 返回值:返回随机项。

    2 abs()函数

    • 描述:abs() 函数返回数字的绝对值。
    • 语法:abs( x )
    • 参数:x -- 数值表达式。
    • 返回值:函数返回x(数字)的绝对值。

    3 turtle.dot(size=None, *color)方法

    • 功能:绘制一个直径为 size,颜色为 color 的圆点。如果 size 未指定,则直径取 pensize+4 和 2*pensize 中的较大值。

    4 turtle.undo()方法

    • 撤消 (或连续撤消) 最近的一个 (或多个) 海龟动作。可撤消的次数由撤消缓冲区的大小决定。

    5 turtle.write(arg,move=False,align="left",font=("Arial",8,"normal"))

    • 描述:书写文本
    • 参数:
      • arg -- 要书写到 TurtleScreen 的对象, 书写指定的字符串 - 到当前海龟位置
      • move -- True/False,如果 move 为 True,画笔会移动到文本的右下角。默认 move 为 False
      • align -- 指定对齐方式 ("left", "center" 或 right")
      • font -- 一个三元组 (fontname, fontsize, fonttype),表示不同的字体

    二 代码结构分析

    1 游戏环境的创建:画出背景世界/迷宫,即吃豆人和幽灵的活动范围

    主要思路:定义了一个地图列表tiles,通过判断地图列表中元素的值是否为1来画出背景世界的基本框架。代码内容包括两部分:square()函数部分和world函数部分,其中列表索引值和地图坐标之间的转换感觉很奇妙,我想不出来。。。

    2 吃豆人和幽灵移动部分

    主要思路:

    首先需要画出吃豆人和幽灵,调用turtle库中的dot函数就可以了

    然后是吃豆人和幽灵的移动过程,都是通过改变他们的坐标来实现的,因为吃豆人和幽灵都是在我们画出的背景世界里面移动的,所以要定义一个函数valid()判断其坐标是否有效,即是否在背景世界范围内;

    还有一部分是统计吃豆人在移动过程中吃到了多少个豆子,这部分内容是通过统计改变tiles元素值得次数得到的,然后再利用turtle库的write函数将统计得到的数值写入字典state中。

    3 游戏结束判断

    吃豆人碰到幽灵即为游戏结束的标志,实际过程中通过判断两者坐标的差值是否小于20个坐标单位即可实现。

    三 代码

      1 """Pacman,classic arcade game.
      2 
      3 Exercises
      4 
      5 1. Change the board.
      6 2. Change the number of ghosts.
      7 3. Change where pacman starts.
      8 4. Make the ghosts faster/slower.
      9 5. Make the ghosts smaster.
     10 
     11 """
     12 
     13 from random import choice                  # 导入choice函数,随机返回可迭代对象中任意一个元素值
     14 from turtle import *                       # 导入海龟库
     15 from freegames import floor,vector         # 导入floor函数和vector函数,floor应该表示一种数学运算,类似于取余的逆操作
     16 
     17 state = {'score':0}                        # 定义字典变量用来统计被吃掉的豆子数
     18 path = Turtle(visible=False)               # 用来画出吃豆人活动的世界,游戏中的蓝色部分
     19 writer = Turtle(visible=False)             # 用来将豆子数写入state字典中的画笔
     20 aim = vector(5,0)                          # 用来改变吃豆人的坐标
     21 pacman = vector(-40,-80)                   # 用来表示吃豆人的坐标
     22 ghosts = [
     23     [vector(-180,160),vector(5,0)],
     24     [vector(-180,-160),vector(0,5)],
     25     [vector(100,160),vector(0,-5)],
     26     [vector(100,-160),vector(-5,0)],
     27 ]                                          # 用来表示四个幽灵的初始坐标
     28 tiles = [
     29     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     30     0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
     31     0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
     32     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
     33     0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0,
     34     0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0,
     35     0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
     36     0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
     37     0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
     38     0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0,
     39     0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0,
     40     0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
     41     0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
     42     0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0,
     43     0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0,
     44     0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0,
     45     0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
     46     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
     47     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     48     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     49 ]                                         # 用来表示地图坐标,"1"表是在该位置画出一个蓝色的正方形,"0"表示不画
     50 
     51 # 用来画出背景世界的元素,一个边长为20个坐标单位的正方形
     52 def square(x,y):                                      # 用来画一个大小为20的正方形
     53     "Draw square using path at (x,y)."
     54     path.up()                                         # 提起画笔
     55     path.goto(x,y)                                    # 将画笔移动到坐标为(x,y)处
     56     path.down()                                       # 放下画笔
     57     path.begin_fill()                                 # 开始填充图形
     58     
     59     for count in range(4):                            # 生成一个包含[0,1,2,3]的序列并遍历
     60         path.forward(20)                              # 画笔向前移动20个坐标单位
     61         path.left(90)                                 # 画笔方向逆时针旋转90度
     62     
     63     path.end_fill()                                   # 结束填充
     64 
     65 # 实现坐标和地图列表索引值得切换
     66 def offset(point):
     67     "Return offset of point in titles."
     68     x = (floor(point.x,20) + 200)/20
     69     y = (180 - floor(point.y,20))/20
     70     index = int(x + y * 20)
     71     return index
     72 
     73 # 判断吃豆人和幽灵移动的下一个坐标是否在背景世界内
     74 def valid(point):                                     # 判断坐标是否在地图坐标中
     75     "Return True if point is valid in tiles."
     76     index = offset(point)                             # 调用offset函数,得到index的值,即tiles列表的索引值
     77     
     78     if tiles[index] == 0:                             # 如果索引index对应的列表titles的元素值为0
     79         return False                                  # 返回False
     80     
     81     index = offset(point + 19)                        # 移动到下一个坐标
     82     
     83     if tiles[index] == 0:                             # 再次判断
     84         return False
     85     
     86     return point.x % 20 == 0 or point.y % 20 == 0     # 当坐标在背景世界范围内,返回1
     87 
     88 # 游戏环境的创建
     89 def world():                                            # 画出背景世界
     90     "Draw world using path."
     91     bgcolor('black')                                    # 将背景世界的填充颜色设置为黑色
     92     path.color('blue')                                  # 将画笔的填充颜色设置为蓝色
     93     
     94     for index in range(len(tiles)):                     # 生成一个长度为len(tiles)的列表,并利用index遍历,将index看作列表tiles的索引
     95         tile = tiles[index]                             # 读取index索引对应的列表tiles元素的值
     96         
     97         if tile > 0:                                    # 如果列表元素值为"1"
     98             x = (index % 20) * 20 - 200                 # 通过index得到路径path的横坐标
     99             y = 180 - (index // 20) * 20                # 通过index得到路径path的纵坐标
    100             square(x,y)                                 # 调用square函数,画出正方形
    101             if tile == 1:                               # 如果列表元素值为1
    102                 path.up()                               # 提起画笔
    103                 path.goto(x + 10,y + 10)                # 画笔移动到(x+10,y+10)处
    104                 path.dot(2,'white')                     # 调用dot函数,画出一个直径为2个坐标单位的点,用来表示豆子
    105 
    106 # 吃豆人和幽灵移动部分
    107 def move():                                             # 控制吃豆人和幽灵的移动
    108     "Move pacman and ghosts."
    109     writer.undo()                                       # 撤销writer画笔最近的海归/画笔动作(前面画笔颜色是白色)
    110     writer.write(state['score'])                        # 设定画笔书写对象是字典state中的关键字'score'对应的值
    111     
    112     clear()                                             # 从屏幕中删除writer海龟/画笔的绘图。不移动海龟/画笔。海龟的状态和位置以及其他海龟的绘图不受影响。
    113     
    114     # 吃豆人移动操作
    115     if valid(pacman + aim):                             # 调用valid函数,如果函数返回值为真(即该坐标在可移动的范围内)
    116         pacman.move(aim)                                # 调用move函数,让吃豆人移动到坐标(pacman.x+aim.x,pacman.y+aim.y)处
    117     
    118     index = offset(pacman)                              # 计算pacman新坐标对应的索引值
    119     
    120     # 统计吃到的豆子的部分
    121     if tiles[index] == 1:                               # 如果index索引对应的列表元素值为1
    122         tiles[index] = 2                                # 将index索引对应的值更新为2,表示该坐标的豆子已经被吃掉了
    123         state['score'] += 1                             # 更新分数:每吃一颗豆子,分数加1
    124         x = (index % 20) * 20 - 200                     # 将index索引值转化为坐标
    125         y = 180 - (index // 20) * 20                    # 将index索引值转化为坐标
    126         square(x,y)                                     # 调用square()函数将世界恢复原样
    127     
    128     # 画出吃豆人
    129     up()                                                # 画笔拿起操作
    130     goto(pacman.x + 10,pacman.y + 10)                   # 更新吃豆人的位置,移动到(pacman.x + 10,pacman.y + 10)处
    131     dot(20,'yellow')                                    # 画出一个黄色的直径为20个坐标单位的点,用来表示吃豆人
    132     
    133     # 幽灵移动操作
    134     for point,course in ghosts:                         # 遍历四个幽灵
    135         if valid(point + course):                       # 判断幽灵的坐标是否有效,即在背景世界的活动范围里面
    136             point.move(course)                          # 调用move函数,让幽灵移动到坐标(point.x+course.x,point.y+course.y)处
    137         else:                                           # 更新course的值,用来控制幽灵的移动
    138             options = [
    139                 vector(5,0),
    140                 vector(-5,0),
    141                 vector(0,5),
    142                 vector(0,-5),
    143             ]                                           # 定义一个列表,用来随机更新course的坐标
    144             plan = choice(options)                      # 从options列表中的四个坐标中任意返回一个坐标
    145             course.x = plan.x                           # 更新course的横坐标
    146             course.y = plan.y                           # 更新course的纵坐标
    147         
    148         # 画出幽灵
    149         up()                                            # 提起画笔操作
    150         goto(point.x + 10,point.y + 10)                 # 将画笔移动到坐标(point.x + 10,point.y + 10)处
    151         dot(20,'red')                                   # 画出一个直径为20个坐标单位的点,用来表示幽灵
    152     
    153     update()                                            # 更新画布
    154     
    155     # 判断游戏是否结束
    156     for point,course in ghosts:                         # 判断游戏是否结束
    157         if abs(pacman - point) < 20:                    # 如果吃豆人和幽灵碰到一块儿
    158             return                                      # 结束游戏
    159     
    160     ontimer(move,100)                                   # 每隔100ma重新调用move函数
    161 
    162 # 实现通过键盘控制吃豆人的移动方向
    163 def change(x,y):                                        # 用来改变吃豆人的移动方向
    164     "Change pacman aim if valid."
    165     if valid(pacman + vector(x,y)):                     # 调用valid函数判断新的坐标是否在迷宫内
    166         aim.x = x                                       # 更新坐标
    167         aim.y = y                                       # 更新坐标
    168 
    169 setup(420,420,370,0)                                    # 初始化画布尺寸
    170 hideturtle()                                            # 隐藏鼠标/海龟
    171 tracer(False)                                           # 保证画图操作(食物和贪吃蛇身体)一次性完成
    172 writer.goto(160,160)                                    # 将writer画笔移动到坐标(160,160)处
    173 writer.color('white')                                   # 将画笔颜色初始化为白色
    174 writer.write(state['score'])                            # 设定画笔书写对象是字典state中的关键字'score'对应的值
    175 # 按键控制模块
    176 listen()                                                # 监听,屏幕聚焦
    177 onkey(lambda:change(5,0),'Right')                       # 右转,Right是键盘方向键的右键,不是输入单词Right
    178 onkey(lambda:change(-5,0),'Left')                       # 左转
    179 onkey(lambda:change(0,5),'Up')                          # 向上走
    180 onkey(lambda:change(0,-5),'Down')                       # 向下走
    181 world()                                                 # 调用world函数,画出背景世界/迷宫
    182 move()                                                  # 调用move函数,开始游戏
    183 done()
  • 相关阅读:
    多表链接 Left join
    v2013调试无法访问此网站 localhost 拒绝了我们的连接请求
    随机不重复流水号。
    通过location对象的某些属性得到一个完整URL的各个部分。
    Vue.JS学习笔记
    前端名词录
    React学习札记一
    kraken-ejs创建一个项目【学习札记】
    express 学习札记
    nth-child & nth-of-type区别
  • 原文地址:https://www.cnblogs.com/luoxun/p/13373721.html
Copyright © 2020-2023  润新知