前言
接上回说,有可能是那天雾太大吧,小乖并没有成功的到达“金暗之森”,但小乖实际是去了什么地方,这是个谜。反正小乖就是迷路了,不知道究竟去了什么地方,而现在就只有我来带领大家前往真正的目的地了。
必须要了解的知识Surface与Rect
关于pygame中的Surface大家最好是去看pygame的官方文档,在这里,我就用我自己对Surface的理解来和大家聊一聊。
Surface,平面或者表面。正如这单词的意思一般,在pygame中,一切拥有固定分辨率的窗口、图片、包括使用Font类渲染出的文字都可以被叫做Surface。因此pygame中的image模块中的load函数返回值为一个Surface对象,而pygame中Font类的render方法亦是返回一个Surface对象,等等。在我们的项目中,“小乖”实际作为一张图片在pygame中我们要把她化为Surface对象来操作,“金暗之森”作为背景图片亦需转化为Surface对象来操作。同理,我们项目中的怪物、子弹等在pygame中都是通过Surface对象来体现的。
Rect,矩形。如文档所描述,是用来存放矩形坐标的。这个Rect的对象乍一看似乎是没有什么用,但是在实际的代码编写过程中,这个Rect的对象最常见也是最重要的用法就是为当前Surface对象确定在上层Surface对象中的位置。说起来有些绕,来看下面代码:
#已知self.screen为当前游戏窗口Surface对象,并且已由pygame.display.set_mode函数返回值得到
def set_bg(self, src="rc/pic/bg_forest.png"):
if self.bg is None:
self.bg = pygame.image.load(src).convert() #得到背景图片的Surface对象
self.screen.blit(self.bg, self.bg.get_rect()) #在游戏窗口的Surface对象上显示背景图片
通过观察上面的代码我们可以发现,Rect对象self.bg.get_rect()帮助背景图片的Surface对象self.bg在当前游戏窗口Surface对象中做出了正确的显示。而在窗口Surface对象中的哪个位置进行显示,正是Rect对象所要做的事情。
继续我们的旅程
好吧,虽然小乖现在仍然是持续掉线中,但是我们现在已经到达了目的地并且我已经完全做好了让“金暗之森”呈现在大家面前的准备。快快键入并运行下面代码,让“金暗之森”出现在眼前吧!
1.GameFrame类
这个类将做为整个游戏的主要框架,许多重要的部分例如计分板的Surface对象,人物的Surface对象,怪物的Group对象都将在这个类中完成创建。
class GameFrame:
def __init__(self):
pygame.init() #初始化pygame库
self.bg = None #背景图片
self.screen = pygame.display.set_mode((1024, 768)) #通过设置分辨率得到窗口Surface对象
pygame.display.set_caption("girl & spider") #设置标题
def set_bg(self, src="rc/pic/bg_forest.png"):
if self.bg is None:
self.bg = pygame.image.load(src).convert()
self.screen.blit(self.bg, self.bg.get_rect())
def check_game(self):
while True: #开启游戏主循环
self.set_bg() #设置背景图片
pygame.display.flip() #不断刷新所有Surface对象,并在屏幕上显示
相应的main.py也要做出一些修改:
import pygame
from game_frame import GameFrame
if __name__ == "__main__":
print("hello pygame" if pygame.vernum >= (1, 5) else "warning: new version expected")
ins = GameFrame() #创建主框架对象
ins.check_game() #启动游戏主循环
现在运行main.py,看哪!同学们,“金暗之森”终于出现了!诶?似乎有些不对,这个“金暗之森”似乎真的是只能看一下。。。它不能响应我们的任何指令,甚至连窗口也不能拖动。最后,windows给了我们程序无法响应的反馈。难道真的有什么神奇力量阻止着我们的探索?没错,这就是接下来必须要说一说的pygame中的事件。
2.事件
以上程序之所以对我们的操做没有任何响应,这是因为目前我们并没有为这个程序撰写任何的事件代码。现在我们就来了解一下事件吧。
pygame.event模块为pygame提供了事件与消息机制。熟悉win32编程的同学肯定对事件已经非常的熟悉了。没错,如果你熟悉win32编程,那么你会发现其实在pygame中,事件与消息机制其实与win32中的事件大同小异。这个直接叙述比较冗杂,我们还是直接看看代码,从代码中来讲解吧。
def run_game(self): # 当游戏开始时候调用此方法
for ev in pygame.event.get(): # 从队列获取事件
if ev.type == pygame.QUIT: # 获取退出事件,并退出游戏
sys.exit()
run_game方法将在游戏开始时候被调用,同时pygame.event.get函数从队列里获取事件,这个函数返回的值是一个Eventlist对象,看到这个对象,相信大多数同学都明白了,这个对象是可以迭代的,毕竟在实际运用中,键盘的事件,鼠标的事件等很可能是一起发生的,因此在同一时刻,我们可能会得到多个不同的事件响应,通过迭代我们将这些事件拿到。在这个时候肯定又有同学会问了,这个这些事件是从哪儿来的?熟悉win32编程的同学肯定是不会产生这样的疑问的,因为pygame中的事件与消息机制与win32编程的是差不多的。简单的说一下win32编程吧,懂了win32的事件与消息机制,相信pygame的事件与消息机制就太简单了。
在win32编程中,当你的窗口被拖动、放大、缩小,键盘的按键的敲击,鼠标的移动在windows的内部都会生成消息,比如当窗口被拖动,windwos就会向当前进程发送WM_MOVE消息。当移动鼠标,windows就会向当前进程发送WM_MOUSEMOVE消息,我们的程序无时无刻都在接受这些windwos发送过来的消息,这个时候我们就需要一个函数帮助我们捕获这些消息,同时我们再根据捕获消息的类型来撰写相应的处理代码。同理,在pygame中也有这样的一个函数,它负责将pygame发送给当前进程的事件存入事件队列供我们使用,它就是pygame.event.get函数。关于这个函数的具体使用方法,大家还可以查看一下官方文档。
在上面的代码中,我们只对pygame.QUIT事件错了处理,当捕获到这个事件的时候,我们的处理为退出程序。同时因为开启了事件循环,我们的游戏窗口就能够接受诸如拖动、窗口缩小与放大等等的消息了。
看!那片森林
现在运行main.py,“金暗之森”再次出现,只是这次,我们已经能够拖动、缩小不会再像之前一样得到windwos发来的程序无响应的反馈了,我们可以尽情的在这片森林中玩耍。什么?太危险?好吧,还好小乖随身带着手机,赶紧拿出手机,打开微信,向小乖发送位置共享,召唤小乖过来探险(路)啦!
本章节程序源代码可以在[https://download.youkuaiyun.com/download/linuxlike/10831121]下载