前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自制街机游戏(1):初次实现

自制街机游戏(1):初次实现

作者头像
不可言诉的深渊
发布2019-07-26 16:39:25
2.4K0
发布2019-07-26 16:39:25
举报

Python功能众多,你已尝试使用了几个,现在该大干一场了。在本项目中,你将学习如何使用Pygame,这个扩展让你能够使用Python编写功能齐备的全屏街机游戏。Pygame虽然易于使用,功能却非常强大。它由多个组件组成,Pygame文档(参见Pygame官网http://pygame.org)做了详尽的介绍。本项目将介绍一些主要的Pygame概念,但鉴于本项目的目标是让你起步,因此不会介绍诸如声音和视频处理等有趣的功能。建议你掌握基本知识后再去探索其他功能。你可能还想参阅Will McGugan和Harrison Kinsley的著作Beginning Python Games Development或Paul Craven的著作Program Arcade Games with Python and Pygame

1.问题描述

那么,如何编写计算机游戏呢?游戏的基本设计过程与其它程序类似,但开发对象模型前,必须先设计游戏本身,如游戏包含的角色、所处的环境以及要实现的目标。

为避免打乱有关Pygame基本概念的介绍,这里创建的游戏比较简单。如果你愿意,完全可以创建更复杂的游戏。

这里将创建的游戏是从巨蟒剧团推出的著名短剧“Self-Defense Against Fresh Fruit”改编而来的。在这个短剧中,军士长John Cleese指挥士兵使用防守战术抵御入侵者使用新鲜水果(如石榴、糖水芒果、青梅和香蕉)发起的进攻。防守战术包括使用枪支、放老虎以及敌人头顶扔下重达16吨的铅锤。在这个游戏中,我们将反过来,让玩家控制一只香蕉。这只香蕉要躲开从天而降的16吨铅锤,尽力在防御战中活下来。我想将这个游戏命名为Squish比较合适。


注意 阅读本项目时,如果你想尝试编写自己的游戏,去做就是了。如果你只是想修改这个游戏的外观,只需替换其中的图形(几幅GIF或PNG图像)和一些描述性文本即可。


这个项目的目标是围绕着游戏设计展开的。这款游戏必须像设计的那样:香蕉能够移动,16吨的铅锤从天而降。另外,与往常一样,代码必须是模块化的,且易于扩展。一个重要的需求是。设计应包含一些游戏状态(如游戏简介、关卡和“游戏结束”状态),同时可轻松地添加新状态。

2.有用的工具

这个项目需要的工具只有一个,那就是Pygame,可从其官网(http://pygame.org)下载。要在UNIX中使用Pygame,可能还需要安装其他一些软件,安装Pygame的最简单方式是使用pip。

Pygame发布版包含多个模块,但在这个项目中大都用不到。接下来几小节将描述需要用到的模块(只讨论需要用到的具体函数或类)。除了接下来将描述的函数外,将用到的各种对象(如Surface、Group和Sprite)还包含一些很有用的方法,我们会在实现部分用到时对其进行讨论。

2.1.pygame

模块pygame自动导入其他所有的Pygame模块,因此只要在程序开头包含语句import pygame,就能使用其他模块,如pygame.display和pygame.font。

模块pygame包含类Surface,它返回一个新的Surface对象。Surface对象其实就是一个指定尺寸的空图像,可用来绘画和传送。传送(调用Surface对象的方法blit)意味着在Surface之间传输内容。【传送的英文单词blit是从技术术语块传输(block transfer)的简写BLT衍生而来的。】

函数init是Pygame游戏的核心,必须在游戏进入主事件循环前调用。这个函数自动化其他所有模块(如font和image)。

想要捕获Pygame特有的错误,就需要使用error类。

2.2.pygame.locals

模块pygame.locals包含你可能在自定义模块的作用域内使用的名称(变量),如事件类型、键、视频模式等名称。可导入这个模块的所有内容(from pygame.locals import*),但如果知道需要哪些名称,应该做更具体的导入,如from pygame.locals import FULLSCREEN。

2.3.pygame.display

模块pygame.display包含处理内容显示的函数,这些内容可显示在普通窗口中,也可占据整个屏幕。在这个项目中,需要用到如下函数。

  • flip:更新显示。一般而言,分两步来修改屏幕。首先,对函数get_surface返回的Surface对象做必要的修改,然后调用pygame.display.flip来更新显示,反映出所做的修改。
  • update:只想更新屏幕的一部分时,使用这个函数而不是flip。调用这个函数时,可只提供一个参数,即RenderUpdates类的方法draw返回的矩形列表(这个方法将在接下来讨论模块pygame.sprite时介绍)。
  • set_mode:设置显示的尺寸和类型。显示模式有多种,但这里只是用全拼模式和默认模式“在窗口中显示”。
  • set_caption:设置Pygame程序的标题。函数set_caption主要用于游戏在窗口中运行(而不是以全屏模式运行)时,因为标题将用作窗口的标题。
  • get_surface:返回一个Surface对象,你可在其中绘制图形,再调用pygame.display.flip或pygame.display.blit。这个项目只使用了Surface对象的一个方法来绘画,这就是blit,它将一个Surface对象中的图形传输到另一个Surface对象的指定位置。另外,还将使用Group对象的方法draw在Surface上绘制Sprite对象。

2.4.pygame.font

模块pygame.font将包含类Font。字体对象可用于表示不同的字体,可用于将文本渲染为可在Pygame中作为普通图形使用的图像。

2.5.pygame.sprite

模块pygame.sprite包含两个非常重要的类:Sprite和Group。

Sprite类是所有可见游戏对象(在这个项目中,是香蕉和重16吨的铅锤)的基类。要实现自定义的游戏对象,可从Sprite派生出子类,并重写构造函数以设置其属性image和rect(这些属性决定了Sprite的外观和位置),同时重写在Sprite可能需要更新时调用的方法update。

Group及其子类的实例用作Sprite对象的容器。一般而言,使用Group是个不错的注意。在简单的游戏(如本项目)中,只需创建一个名为sprites或allsprites之类的Group,并将所有Sprite都添加到其中。这样,当你调用Group对象的方法update时,将自动调用所有Sprite对象的方法update。另外,Group对象的方法clear用于清除它包含的所有Sprite对象(实际的清理工作是使用一个回调函数完成的),而方法draw可用于绘制所有的Sprite对象。

在这个项目中,将使用Group的子类RenderUpdates,其方法draw返回列表,其中包含所有受到影响的矩形。可将这个列表传递给pygame.display.update,以后只更新需要更新的部分。通过这样做,有可能极大地改善游戏的性能。

2.6.pygame.mouse

在即将开发的游戏Squish中,只是用模块pygame.mouse来做两件事情:隐藏鼠标以及获取鼠标的位置。这两件事分别是使用pygame.mouse.set_visible(False)和pygame.mouse.get_pos()来完成的。

2.7.pygame.event

模块pygame.event跟踪各种事件,如鼠标单击、鼠标移动、按下或松开键等。要获取最近发生的事件列表,可使用函数pygame.event.get。


注意 如果只需要状态信息,如pygame.mouse.get_pos返回的鼠标位置,就无需使用pygame.event.get。然而,你需要确保Pygame同步地更新,为此可定期调用函数pygame.event。pump。


2.8.pygame.image

模块pygame.image用于处理图像,如以GIF、PNG、JPEG和其他几种文件格式存储的图像。在这个项目中,只需要这个模块的函数load,它读取图像文件并创建一个包含该图像的Surface对象。

3.准备工作

对一些Pygame模块的功能进行粗略了解后,改动手编写这个游戏的第一个原型了。然而,这样做之前,需要做几项准备工作。首先必须确保安装了Pygame,包括模块image和font。(要核实是否安装了这些模块,可在交互式Python解释器中导入它们。)

你还需准备几幅图像。如果要按本项目说的那样呈现游戏的主题,就需要两幅图像,分别表示重16吨的铅锤和香蕉,如图所示。这些图像的尺寸无关紧要,但最好在100像素x100像素~200像素x200像素之间。这两幅图像还应使用常见的图像文件格式,如GIF、PNG或JPEG。


注意 你可能还想提供一张启动屏幕(像游戏用户问候的第一个屏幕)图像。在这个项目中,我直接使用了表示铅锤的图像。


4.初次实现

使用诸如Pygame等新工具开发程序时,应让第一个原型尽可能简单,并将重点放在学习新工具的基本知识,而不是程序本身的细节上。这样做通常大有裨益。因此,在游戏Squish的第一个版本中,我们只创建重16吨的铅锤从天而降的动画。制作这个动画需要步骤如下。

(1)使用pygame.init、pygame.display.set_mode和pygame.mouse.set_visible初始化Pygame。使用pygame.display.get_surface获取屏幕表面,使用方法fill以白色填充屏幕表面,再调用pygame.display.flip现实所做的修改。

(2)加载铅锤图像。

(3)使用这幅图像创建自定义类Weight(Sprite的子类)的一个实例。将这个对象添加到RenderUpdates编组sprites中。(处理多个Sprite对象时,这样做很有帮助。)

(4)使用pygame.event.get获取最近发生的所有事件,并依次检查这些事件。如果发现事件QUIT或因按下Escape键(K_ESCAPE)而触发的KEYDOWN事件,就退出程序。(事件类型和键分别存储在事件对象的属性type和key中。诸如QUIT、KEYDOWN和K_ESCAPE等常量可从模块pygame.locals导入。)

(5)调用编组sprites的方法clear和update。方法clear使用毁掉函数来清除所有的Sprite对象(这里是铅锤),而方法update调用Weight实例的方法update(你必须在Weight类中实现方法update)。

(6)调用sprites.draw并将屏幕表面作为参数,以便在当前位置绘制铅锤(每次调用Weight实例的update方法后,位置都将发生变化)。

(7)调用pygame.display.update,并将sprites.draw返回的矩形列表作为参数,只需更新需要更新的部分。(如果你不在乎性能,可使用pygame.display.flip来更新整个屏幕。)

(8)重复第4~7步。

下图列出了实现这些步骤的代码。在你退出游戏,如关闭窗口时,将发生QUIT事件。

要运行这个程序,可使用下面的命令:

python weights.py

执行这个命令时,必须确保weights.py和weight.png(铅锤图像)都在当前目录中。下图显示了执行这个程序时的屏幕截图。

这些代码大都是不言自明的,但有几点需要解释一下。

  • 所有的Sprite对象都有属性image和rect,其中前者应是一个Surface对象(图像)而后者应是一个矩形对象(只需使用self.image.get_rect()初始化它即可)。绘制Sprite对象时,将用到这两个属性。通过修改self.rect,可移动Sprite对象。
  • Surface对象包含方法convert,可用于创建使用不同颜色模式的副本。你无需关心细节,只需在调用convert时不提供任何参数即可。这将根据当前显示量身定制一个Surface对象,从而最大限度的提高其显示速度。
  • 颜色是使用RGB元组(红-绿-蓝,每个值的取值范围都是0~255)指定的,因此元组(255, 255, 255)表示白色。

要修改矩形(如这里的self.rect),可设置其属性(top、bottom、left、right、topleft、topright、bottomleft、bottomright、size、width、height、center、centerx、centery、midleft、midright、midtop和midbottom),也可调用诸如inflate、move等方法。有关这些属性和方法的描述,请参阅Pygame文档(http://pygame.org/docs/ref/rect.html)。

Pygame技术就位后,该稍微扩展和重构游戏的逻辑了。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-08-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python机器学习算法说书人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
媒体处理
媒体处理(Media Processing Service,MPS)是一种云端音视频处理服务。基于腾讯多年音视频领域的深耕,为您提供极致的编码能力,大幅节约存储及带宽成本、实现全平台播放,同时提供视频截图、音视频增强、内容理解、内容审核等能力,满足您在各种场景下对视频的处理需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档