20182324 2019-2020-2 《Python 程序设计》实验4报告

20182324 2019-2020-2 《Python 程序设计》实验4报告

课程:《Python 程序设计》
班级: 1823
姓名: 殷宇豪
学号: 20182324
实验教师:王志强
实验日期:2020年6月10日
必修/选修: 公选课

1. 实验内容

  • Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。

  • 本次实践选择 pygame 制作微信的飞机大战游戏,采取主要代码参考网上,细节处理自己改动的方式

    • 为什么要选择 pygame ?
      爬虫太简单,只需要掌握基础 HTML 知识即可,在学习了 Web 程序开发后对爬虫有了一定的了解;数据处理是一个值得学习的领域,做好了能够实现自动化,目前已有初步了解; pygame 从来没碰过,是一片全新的值得挑战的领域;机器学习、网络安全较难,在有限的时间内暂不考虑。相比之下,从学习更多新知识的角度考虑,我选择了有一定难度与综合性,但又不至于花费太多精力,能够快速入门的 pygame 进行实验。

    • 这次实验的代码完全是自己写的吗?
      我可以很负责地说:不是。因为自己对于 pygame 完全是零基础,因此主要代码是参考网上别人写的,进行一些具有自己想法的改动。正如上学期学 Java 时王老师所说:加点代码,改点代码是理解的最好方式。

    • 为什么没有自己从头至尾地写代码?
      众所周知,互联网带来很大的一个好处就是可以借鉴。与其从什么是 pygame、怎么创建 pygame 这样一章一章地固化学习(甚至很可能学完就忘了),最后做出一个完全不实用、不好看的程序,不如直接在别人的基础上进行扩展,通过推敲与学习别人是怎么写这些代码的,从而达到理解这些方法的效果。

    • 自己在这次实验上进行了哪些改动?
      这次实验查找的网上代码主要实现了飞机的左右水平移动、发射子弹等功能。自己在其基础上,增添了飞机上下竖直移动、鼠标按键发射子弹、结果显示与统计等功能。

    • 在这些改动中学到了什么?
      通过学习既有代码,了解了 pygame 游戏代码的基本结构,了解了事件的组成,游戏的进行即是一个又一个事件的发生与重复;通过研究既有左右移动的功能,对键盘事件有了一定的认识,并在此基础上扩展至了上下左右移动(包括我们熟知的 WSAD 移动);主动学习了鼠标事件,实现了鼠标按键发射子弹的功能;主动学习了 EasyGUI,实现了登录与统计界面,也为下一步的可视化设计打了一定基础。

2. 实验过程及结果

  • 直接借鉴的主程序就不用说了,主要谈谈自己进行的改动

  • (1) 通过 pygame.key.get_pressed() 事件判断键盘按键,实现 ↑ ↓ ← → 和 W A S D 两种按键方式对飞机进行移动

            # 右键或D
            if keys_pressed[pygame.K_RIGHT] or keys_pressed[pygame.K_d]:
                self.hero.speed = 4
            # 左键或A
            elif keys_pressed[pygame.K_LEFT] or keys_pressed[pygame.K_a]:
                self.hero.speed = -4
            # 上键或W
            elif keys_pressed[pygame.K_UP] or keys_pressed[pygame.K_w]:
                self.hero.speed = -4
            # 下键或S
            elif keys_pressed[pygame.K_DOWN] or keys_pressed[pygame.K_s]:
                self.hero.speed = 4
    

    通过按键判断是水平还是竖直方向上的移动

            if keys_pressed[pygame.K_RIGHT] or keys_pressed[pygame.K_LEFT] \
                    or keys_pressed[pygame.K_a] or keys_pressed[pygame.K_d]:
                # 我方战机在水平方向移动
                self.rect.x += self.speed
            elif keys_pressed[pygame.K_UP] or keys_pressed[pygame.K_DOWN] \
                    or keys_pressed[pygame.K_w] or keys_pressed[pygame.K_s]:
                # 我方战机在竖直方向移动
                self.rect.y += self.speed
    
  • (2) 通过 pygame.key.get_pressed() 判断键盘按键实现空格发射子弹,并通过 pygame.mouse.get_pressed() 判断鼠标按键实现鼠标左键发射子弹

            # 使用键盘提供的方法获取键盘按键 - 按键元组
            keys_pressed = pygame.key.get_pressed()
            # 使用鼠标提供的方法获取是否按下鼠标左键
            mouse_pressed = pygame.mouse.get_pressed()
            # 空格或鼠标左键发射子弹
            if keys_pressed[pygame.K_SPACE] or mouse_pressed[0]:
    
                # 1. 创建子弹精灵
                bullet = Bullet()
    
                # 2. 设置精灵的位置
                bullet.rect.bottom = self.rect.y
                bullet.rect.centerx = self.rect.centerx
    
                # 3. 将精灵添加到精灵组
                self.bullets.add(bullet)
    
  • (3) 启动游戏需输入用户名,若不输入则系统自动指派一个,该用户名仅用于统计排行榜。通过 EasyGUI 的 enterbox 实现。

            # 输入用户名
            userid = g.enterbox("请输入用户名:", "登录", "20182324yyh")
            # 如果不输入用户名,则为其默认指定一个
            if userid == "" or userid == None:
                userid = "游客" + str(random.randint(1000, 10000))
    
  • (4) 在游戏界面的左上角实时显示玩家名称与得分。通过 pygame.font.SysFont 和 screen.blit 方法实现。

            game_user = pygame.font.SysFont('simsunnsimsun', 20, True)  # 字体
            self.screen.blit(game_user.render(u'%s' % userid, True, [0, 0, 0]), [20, 20])  # 显示用户名
            game_font = pygame.font.SysFont('simsunnsimsun', 20, True)  # 字体
            self.screen.blit(game_font.render(u'当前得分:%d' % sum, True, [0, 0, 0]), [20, 40])  # 显示实时得分
    
  • (5) 游戏结束后弹框显示本次游戏的得分,并可选择查看排行榜。得分弹框通过 EasyGUI 的 ccbox 实现,排行榜通过 EasyGUI 的 textbox 实现,数据存入 sqlite 数据库中。数据库中共有三个字段:Unix 时间戳(主键)、玩家名称、玩家得分。在输出排行榜时需对 Unix 时间戳进行还原处理。

            sql()
            box = g.ccbox("用户 " + userid + "\n您本次游戏得分:" + str(sum), "游戏结束", ("确定", "排行榜"))
            if box == 0:
                s1 = "\t时间\t\t玩家\t\t得分\t\t"
                s = ""
                yyh20182324 = sqlite3.connect("排行榜.db")
                cursor = yyh20182324.cursor()
                cursor.execute('select * from Ranklist order by core desc')
                for line in cursor.fetchall():
                    # 月
                    if time.gmtime(line[0])[1] < 10:
                        month = "0" + str(time.gmtime(line[0])[1])
                    else:
                        month = str(time.gmtime(line[0])[1])
                    # 日
                    if time.gmtime(line[0])[2] < 10:
                        day = "0" + str(time.gmtime(line[0])[2])
                    else:
                        day = str(time.gmtime(line[0])[2])
                    # 时
                    if (time.gmtime(line[0])[3] + 8) % 24 < 10:
                        hour = "0" + str((time.gmtime(line[0])[3] + 8) % 24)
                    else:
                        hour = str((time.gmtime(line[0])[3] + 8) % 24)
                    # 分
                    if time.gmtime(line[0])[4] < 10:
                        minute = "0" + str(time.gmtime(line[0])[4])
                    else:
                        minute = str(time.gmtime(line[0])[4])
                    # 秒
                    if time.gmtime(line[0])[5] < 10:
                        second = "0" + str(time.gmtime(line[0])[5])
                    else:
                        second = str(time.gmtime(line[0])[5])
                    calendar = str(time.gmtime(line[0])[0]) + "-" + month + "-" + day + "  " + hour + ":" + minute + ":" + second
                    s = s + calendar + "\t  \t" + line[1] + "\t\t\t  " + str(line[2]) + "\t\n"
                g.textbox(s1, "排行榜", s)
                yyh20182324.close()
    

    调用数据库的方法

    # 排行榜数据库文件
    def sql():
        yyh20182324 = sqlite3.connect("排行榜.db")
        cursor = yyh20182324.cursor()
        cursor.execute('create table if not exists Ranklist(time int(10) primary key, userid text, core int)')
        cursor.execute('insert into Ranklist(time, userid, core) values (?, ?, ?)', (int(time.time()), userid, sum))
        yyh20182324.commit()
        yyh20182324.close()
    
  • (6) 游戏过程截图

  • 代码托管

3. 实验过程中遇到的问题和解决过程

  • 问题 1 :使用pip install --upgrade pip命令升级 pip 后,安装模块时提示:ModuleNotFoundError:No module named pip._internal

  • 问题 1 解决方案:系 pip 升级失败。参考 pip升级时报错--- No module named 'pip._internal' 文章,使用 python get-pip.py --force-reinstall 命令强制重装 pip

  • 问题 2 :使用全局变量统计得分时报错 UnboundLocalError: local variable 'sum' referenced before assignment

  • 问题 2 解决方案:在函数内部对全局变量进行操作时,应先使用 global 声明,否则程序将把该变量视为未定义的局部变量

  • 问题 3 :使用 pygame.font 显示文字时报错 pygame.error: font not initialized

  • 问题 3 解决方案:在主程序开始前必须执行pygame.init()使 pygame 初始化,或执行 pygame.font.init() 使字库初始化

  • 问题 4 :pygame 无法显示多行文字,使用 "\n" 也无效

  • 问题4解决方案:Font.render不支持多行显示,想要显示多行文字,只能创建多个 render 对象进行逐行显示

  • 问题 5 :pygame 中文显示乱码

  • 问题 5 解决方案:字体引用不正确。可使用pygame.font.get_fonts()来查看字体名,例如 宋体 对应 simsunnsimsun ,pygame.font.SysFont('simsunnsimsun',20)

  • 问题 6 :enterbox 取消输入用户名后报错TypeError: can only concatenate str (not "NoneType") to str

  • 问题 6 解决方案:enterbox 不输入任何东西返回 None,即 Java 中的 null,表示空值。None 的类型为 NoneType,要想判断该类型,直接判断该变量值是否等于 None 即可。注意不是 null。

其他(感悟、思考等)

一学期的课程又结束了,一期一度的大作业真的很考验人的综合运用能力。这学期的 Python 总体而言没有上学期的 Java 累,可能也是选修课与必修课的区别。通过对 Python 的学习,真真切切地感受到它的方便快捷,不愧为今天最受欢迎的编程语言。总的来说上王老师的课能够学到很多东西,不管是主动学习还是被动学习,只有真真正正学到了才能做出成果,相比于闭卷考试,这种考核方式更值得提倡。
我对这门课的建议是:坚持写 blog 的优良传统不要放弃
最后:

参考资料

  • 《Python 编程:从入门到实践》

  • Python实现微信小游戏:飞机大战

  • Python游戏系列之七_显示得分

  • pygame系列_mouse鼠标事件

你可能感兴趣的:(20182324 2019-2020-2 《Python 程序设计》实验4报告)