一.前言
在上一节,我们完成了玩家的移动,但是并没有给玩家一个具体的形象,因此这里我们要导入玩家的图片素材,并且把player类的image替换成相应的图片
所有的图片素材都在与code同级的graphics文件夹下,其中玩家的图片素材在character文件夹下
但是玩家有很多种状态,比如向上移动的时候,向下移动的时候,砍树的时候,浇水的时候等等,在做不同的动作的时候,玩家的图片肯定是不一样的,因此我们把做不同动作用到的图片分别装在了不同的文件夹下,如下图所示
每个动作基本上都分为上下左右四个方向,如果文件夹的名字是单纯的up,down等等,那就是做出向上走,向下走的动作用到的图片,如果方向的后面加上_idle,就是面向对应的方向待机的时候的动作,如果是加上_water,就是面向相应的方向浇水的动作,_axe代表使用斧头,_hoe代表使用锄头
比如使用斧头,这个动作是由两张图片构成的, 利用人的视觉暂留机制,在零点几秒内快速循环播放这两张图片,可以达到主角挥舞斧头的动画效果
不过动画播放是下一节才实现的,这里先把图片导入进来并用一种数据结构存储起来,方便以后制作动画的时候使用
二.代码实现
self.animations = {'up': [],'down': [],'left': [],'right': [],
'right_idle':[],'left_idle':[],'up_idle':[],'down_idle':[],
'right_hoe':[],'left_hoe':[],'up_hoe':[],'down_hoe':[],
'right_axe':[],'left_axe':[],'up_axe':[],'down_axe':[],
'right_water':[],'left_water':[],'up_water':[],'down_water':[]}
比如,我们要取面向左边是用斧头的第一张图片,就需要self.animations[left_axe][0]
但是现在,我们只不过是给这个数据结构创建出来了,我们还没往里面放图片
仔细观察,会发现,我们的动作的文件夹的名称和字典里的key值是相同的,可以利用这个特性,一个for循环就能得到所有图片的路径
for animation in self.animations.keys():
full_path = '../graphics/character/' + animation
self.animations[animation] = import_folder(full_path)
for循环循环读取self.animations的key值,赋给animation
就比如第一次循环animation是'up',第二次循环animation是'down'...
'../graphics/character/' + animation刚好就是对应动作的文件夹的路径
有了文件夹的路径,我们希望有这么一个函数,我们给这个函数一个文件夹的路径,他能把该路径的文件夹下的所有图片都给导入进来,放到一个列表里,并把这个列表当作返回值返回,显然这个函数是需要我们自己写的,import_folder就是一个这样的函数,我们用animations[对应的动作]来接收返回的列表
这个函数我们不希望在player.py里面写,因为后续我们导入其他的图片的时候,比如树木,土地等等也能用到这个函数,我们不希望他是player.py独有的函数,因此我们单独创建一个文件,叫做support.py,在这个文件里面实现import_folder函数
不过在此之前,我们还要在player.py内导入support.py
from support import *
from os import walk
import pygame
def import_folder(path):
surface_list = []
#walk是扫一遍文件夹
#三个返回值,_是一个str类型,是该文件夹的路径
#__是一个列表,里面存的是该文件夹下的文件夹的名字
#img_files是一个列表,列表里存放若干个str,是该文件夹下的每一个文件的文件名
#文件夹路径 + / + 文件名就是每一个文件的路径
for _, __, img_files in walk(path):
for image in img_files:
full_path = path + '/' + image
image_surf = pygame.image.load(full_path).convert_alpha()
surface_list.append(image_surf)
return surface_list
walk(path)中的path是一个字符串,是一个文件夹的路径,也就是我们在player.py中传入的参数
walk(path)有三个返回值,第一个返回值是一个字符串,是该文件夹下的路径,与path是一样的; 第二个返回值是一个列表,里面存放若干个字符串,每个字符串是该文件夹下的子文件夹的名称,显然,我们的文件夹下全是图片,没有子文件夹,所以第二个返回值返回的是一个空列表; 第三个返回值是一个列表,里面存放若干个字符串,每个字符串是该文件夹下的文件的名称,在这里就是文件夹下的每一张图片的名称
文件夹的路径 + '/' + 图片的名称 = 图片的路径,我们用full_path来接收每一张图片的路径,并且用pygame.image.load(full_path)来将这个路径的图片导入进来
pygame.image.load()的作用是把对应路径的图片导入进来,变成一个可以被pygame直接使用的图片数据类型
可以这么理解:full_path是一个字符串,代表的是图片的路径,它经过load之后,得到的image_surf就是一张图片,可以展示到pygame的游戏窗口上了
至于后面的.convert_alpha()就是把这张图片的存储方式转换成alpha存储方式,可加可不加,加了会使程序运行的更快
我们得到了图片之后把它插入到列表中,最后把列表当作返回值返回即可
至此,我们就完成了对support.py的书写,接下来让我们回到player.py,把我们上面的代码封装成一个函数:
def import_assets(self):
self.animations = {'up': [],'down': [],'left': [],'right': [],
'right_idle':[],'left_idle':[],'up_idle':[],'down_idle':[],
'right_hoe':[],'left_hoe':[],'up_hoe':[],'down_hoe':[],
'right_axe':[],'left_axe':[],'up_axe':[],'down_axe':[],
'right_water':[],'left_water':[],'up_water':[],'down_water':[]}
for animation in self.animations.keys():
full_path = '../graphics/character/' + animation
self.animations[animation] = import_folder(full_path)
这个函数的作用就是创建一个字典,里面存放了玩家进行各种动作所需要的各种图片
很显然,我们需要在玩家类初始化的时候就把图片导入进来,因此需要在__init__函数里面调用import_assets函数
并且我们可以把先前临时设置成绿色方框的self.image改成字典中的任意图片了
新增加两个变量,self.status是一个字符串类型,代表玩家正在进行的动作,self.fream_index是一个int类型的数,代表正在播放该动作的第几张图片,那么
self.animations[self.status][self.fream_index]就是我们正在播放的那张图片,令self.image = self.animations[self.status][self.frame_index]即可
其中self.status 初始化为"down_idle"最好,因为游戏一开始,玩家不可能是浇水或者砍树的,肯定是面朝下面的待机状态
三.完整代码
import pygame
from settings import *
from support import *
class Player(pygame.sprite.Sprite):
def __init__(self, pos, group):
super().__init__(group)
self.import_assets()
self.status = 'down_idle'
self.frame_index = 0
# general setup
self.image = self.animations[self.status][self.frame_index]
self.rect = self.image.get_rect(center = pos)
# movement attributes
self.direction = pygame.math.Vector2()
self.pos = pygame.math.Vector2(self.rect.center)
self.speed = 200
def import_assets(self):
self.animations = {'up': [],'down': [],'left': [],'right': [],
'right_idle':[],'left_idle':[],'up_idle':[],'down_idle':[],
'right_hoe':[],'left_hoe':[],'up_hoe':[],'down_hoe':[],
'right_axe':[],'left_axe':[],'up_axe':[],'down_axe':[],
'right_water':[],'left_water':[],'up_water':[],'down_water':[]}
for animation in self.animations.keys():
full_path = '../graphics/character/' + animation
self.animations[animation] = import_folder(full_path)
def input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
self.direction.y = -1
elif keys[pygame.K_DOWN]:
self.direction.y = 1
else:
self.direction.y = 0
if keys[pygame.K_RIGHT]:
self.direction.x = 1
elif keys[pygame.K_LEFT]:
self.direction.x = -1
else:
self.direction.x = 0
def move(self,dt):
# normalizing a vector
if self.direction.magnitude() > 0:
self.direction = self.direction.normalize()
# horizontal movement
self.pos.x += self.direction.x * self.speed * dt
self.rect.centerx = self.pos.x
# vertical movement
self.pos.y += self.direction.y * self.speed * dt
self.rect.centery = self.pos.y
def update(self, dt):
self.input()
self.move(dt)
from os import walk
import pygame
def import_folder(path):
surface_list = []
#walk是扫一遍文件夹
#三个返回值,_是一个str类型,是该文件夹的路径
#__是一个列表,里面存的是该文件夹下的文件夹的名字
#img_files是一个列表,列表里存放若干个str,是该文件夹下的每一个文件的文件名
#文件夹路径 + / + 文件名就是每一个文件的路径
for _, __, img_files in walk(path):
for image in img_files:
full_path = path + '/' + image
image_surf = pygame.image.load(full_path).convert_alpha()
surface_list.append(image_surf)
return surface_list
四.总结
本节,我们创建了一个文件,叫做support.py,在里面实现了一个叫做import_folder的函数,它的作用是,传入一个代表文件夹路径的字符串参数,会把该文件夹下的所有图片都加载进来,并存放到一个列表里,并返回该列表
利用这个函数,我们在player.py里,把玩家进行各种操作所需要的图片都加载了进来,并且把我们之间给玩家临时设置的绿色矩形方块形象给变成了图片的形象