前言
小乖在得到我们发送的手机定位后,终于找到了正确的方向,呼呼地赶了过来。但当她来到“金暗之森”跟前的时候,一扫一路上的疲态,立马就变得跃跃欲试,恨不得马上进入其中探险。
“小乖!小乖!”你可等等啊,这里面麻烦不断,得先做些准备工作呀。好吧,哪里还能等我们把话说完,附近早已经不见了小乖的影子啦。。。
出现在森林之中
1.Ship类
在本章,由于小乖的到来,我们需要建立一个新类来对小乖的行为作出管理约束。这便是我们的Ship类啦。Ship类目前的主要功能为在游戏窗口中绘制人物、通过键盘来控制人物的行动。来看以下代码:
import pygame
class Ship:
def __init__(self, screen, img_path="rc/pic/ic_actor.png", speed_factor=1):
"""
构造方法,目前负责在指定位置绘制游戏人物,使人物对键盘作出响应
:param screen: 当前游戏窗口的Surface对象
:param img_path: 人物图片的路径
:param speed_factor: 控制人物移动的快慢
"""
self.screen = screen
self.img = pygame.image.load(img_path) # 获得当前人物图片的Surface对象
self.rect = self.img.get_rect() # 获得人物图片外接矩形的Rect对象
self.screen_rect = self.screen.get_rect()
self.rect.centerx = self.screen_rect.centerx # 确定人物在游戏窗口中的X位置
self.rect.centery = self.screen_rect.bottom - 30 # 确定人物在游戏窗口中的Y位置
def blit_actor(self):
"""
负责在游戏中绘制人物
:return: 无
"""
self.screen.blit(self.img, self.rect)
以上代码没有什么出现什么新的知识点,都是对之前所讲的再熟悉利用,所以,这里就不再赘述了。相应的,game_frame.py中的代码也需要做一定的调整。
def run_game(self): # 当游戏开始时候调用此方法
if self.ship is None:
self.ship = Ship(self.screen) #实例化人物
for ev in pygame.event.get(): # 从队列获取事件
if ev.type == pygame.QUIT: # 获取退出事件,并退出游戏
sys.exit()
self.ship.blit_actor() #绘制人物
仔细观察以上代码可以发现,实际上就是多了对Ship类的实例化和绘制,通过对Ship类的实例化和绘制,使得人物出现在游戏之中。注意这里只是截取的game_frame.py文件中的一个代码片段,大家在实际操作过程中莫要忘了把Ship类导入进来哦。
运行main.py。哦,看哪!小乖终于来到了森林里!好吧,虽然到了森林之中,但是小乖目前啥也干不了,只能静静地站在那里,如若失了神一般。
“叫你跑那么快!”我们缓步追上,轻笑道。刚刚正准备为你写一段代码,让你在森林之中行动自如的,现在傻眼了吧。
好吧,我们也不能让小乖一直站在那个地方,太(没)可(法)怜(探)了(路),现在我们就来聊一聊如何让小乖动起来吧。
2.为人物添加键盘响应
还记得我们之前讲的pygame的事件机制嘛,其实当我们在游戏中按下键盘的时候,pygame就已经检测到了,并且也已经将这个事件存入了事件队列当中,只是当时我们没有处理这些事件。
那么现在是时候处理这些事件了,来看以下代码:
class Ship:
def __init__(self, screen, img_path="rc/pic/ic_actor.png", speed_factor=1):
"""
构造方法,目前负责在指定位置绘制游戏人物,使人物对键盘作出响应
:param screen: 当前游戏窗口的Surface对象
:param img_path: 人物图片的路径
:param speed_factor: 控制人物移动的快慢
"""
self.screen = screen
self.img = pygame.image.load(img_path) # 获得当前人物图片的Surface对象
self.rect = self.img.get_rect() # 获得人物图片外接矩形的Rect对象
self.screen_rect = self.screen.get_rect()
self.speed_factor = speed_factor
self.cx = float(self.screen_rect.centerx)
self.cy = float(self.screen_rect.bottom)
self.rect.centerx = self.cx # 确定人物在游戏窗口中的X位置
self.rect.centery = self.cy - 30 # 确定人物在游戏窗口中的Y位置
self.moving_right = False # 开关变量,当为真的时候改变人物X坐标
self.moving_left = False # 开关变量,当为真的时候改变人物X坐标
self.moving_up = False # 开关变量,当为真的时候改变人物Y坐标
self.moving_down = False # 开关变量,当为真的时候改变人物Y坐标
def blit_actor(self):
"""
负责在游戏中绘制人物
:return: 无
"""
self.screen.blit(self.img, self.rect)
def check_ev(self, ev):
"""
检测当前事件是键盘按键被按下还是按键复位
:param ev: 当前事件,从事件迭代中获得
:return: 无
"""
if ev.type == pygame.KEYDOWN:
self.check_ev_keydown(ev)
elif ev.type == pygame.KEYUP:
self.check_ev_keyup(ev)
def check_ev_keydown(self, ev):
"""
当有按键被按下的时候,判断是哪个按键被按下
:param ev: 当前事件,从事件迭代中获得
:return: 无
"""
if ev.key == pygame.K_LEFT: # 如果左键被按下,将对应开关变量置为真,改变人物X坐标
self.moving_left = True
elif ev.key == pygame.K_RIGHT: # 如果右键被按下,将对应开关变量置为真,改变人物X坐标
self.moving_right = True
elif ev.key == pygame.K_UP: # 如果上键被按下,将对应开关变量置为真,改变人物Y坐标
self.moving_up = True
elif ev.key == pygame.K_DOWN: # 如果下键被按下,将对应开关变量置为真,改变人物Y坐标
self.moving_down = True
elif ev.key == pygame.K_SPACE: # 如果空格被按下,发射子弹(预留)
pass
def check_ev_keyup(self, ev):
if ev.key == pygame.K_LEFT: # 左键弹起,将对应开关变量置为假,停止改变人物X坐标
self.moving_left = False
elif ev.key == pygame.K_RIGHT: # 右键弹起,将对应开关变量置为假,停止改变人物X坐标
self.moving_right = False
elif ev.key == pygame.K_UP: # 上键弹起,将对应开关变量置为假,停止改变人物Y坐标
self.moving_up = False
elif ev.key == pygame.K_DOWN: # 下键弹起,将对应开关变量置为假,停止改变人物Y坐标
self.moving_down = False
def moving_update(self):
"""
在游戏主循环中被调用,通过改变人物外接矩形坐标使人物移动
:return:
"""
if self.moving_left and self.rect.left > self.screen_rect.left:
self.cx -= self.speed_factor
self.rect.centerx = self.cx
if self.moving_right and self.rect.right < self.screen_rect.right:
self.cx += self.speed_factor
self.rect.centerx = self.cx
if self.moving_up and self.rect.top > self.screen_rect.top:
self.cy -= self.speed_factor
self.rect.centery = self.cy
if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
self.cy += self.speed_factor
self.rect.centery = self.cy
self.blit_actor()
以上代码结合我给的注解理解起来还是非常容易的。只是大家要注意,Surface对象是不能直接改变它的坐标的,必须要通过它的外接矩形来改变(前面说过,Rect对象就是用来存储这些坐标的)。以上代码通过四个开关变量来控制人物的移动,键盘的按下与弹起来控制开关变量,开关变量来控制是否改变人物外接矩形坐标。同时,在moving_update方法中,我们还增加了避免让人物移出窗口之外的判断。
好了,运行main.py吧,现在小乖已经能够在“金暗之森”中愉快地玩(探)耍(路)了。
源代码下载
本章节源代码可以在[https://download.csdn.net/download/linuxlike/10831121]下载