pygame教程——1.4英雄角色的动画实现

文章目录

  • 前言
  • Demo演示
  • 代码如下:
  • 素材样例(可能存在变形):
  • 知识点:

前言

上一节我们实现了英雄角色的左右移动及跳跃功能,但是只有一张单一的图片,英雄无法产生更生动的形象。所以本节我们将会在人物运动的过程中为其添加动画效果。

Demo演示

我们先来看下本节的效果:

python使用pygame开发游戏系列之精灵动画的实现。

代码如下:

import json

import pygame


class Player(object):
    """player对象"""

    def __init__(self):
        self.player_img = "zombie.png"
        self.all_frames = self.load_frames_from_sheet()
        self.rect = self.all_frames.get("left").get("idle")[0].get_rect()
        self.rect.midbottom = (100, screen_height - 135)
        self.vel_y = 0
        self.current_frame = 0
        self.jumped = False
        self.direction = 1  # 1:右 -1:左
        self.dir_frames = []
        self.frames = []
        self.state = 'idle'
        self.is_attack = False
        self.last_updated = 0
        self.current_image = self.all_frames.get("left").get("idle")[0]

    def handle_state(self):
        """根据状态决定行为"""
        if self.direction == -1:  # 根据方向选择朝向不同的序列图片
            self.dir_frames = self.all_frames.get("left")
        else:
            self.dir_frames = self.all_frames.get("right")

        if self.state == 'idle':
            self.frames = self.dir_frames.get("idle")
        elif self.state == "run":
            self.frames = self.dir_frames.get("run")
        elif self.state == "walk":
            self.frames = self.dir_frames.get("walk")
        elif self.state == "jump":
            self.frames = self.dir_frames.get("jump")
        elif self.state == "fall":
            self.frames = self.dir_frames.get("fall")
        elif self.state == "attack":
            self.frames = self.dir_frames.get("attack")

    def animate(self):
        now = pygame.time.get_ticks()
        if now - self.last_updated > 100:
            self.last_updated = now
            self.current_frame = (self.current_frame + 1) % len(self.frames)
            self.current_image = self.frames[self.current_frame]

    def load_frames_from_sheet(self):
        my_sprite_sheet = SpriteSheet(self.player_img)
        stand_frames = [my_sprite_sheet.parse_sprite("idle")]
        move_frames = [my_sprite_sheet.parse_sprite("walk{}".format(i)) for i in range(0, 8)]
        jump_frames = [my_sprite_sheet.parse_sprite("jump")]
        fall_frames = [my_sprite_sheet.parse_sprite("fall")]
        attack_frames = [my_sprite_sheet.parse_sprite("attack{}".format(i)) for i in range(0, 3)]
        run_frames = [my_sprite_sheet.parse_sprite("run{}".format(i)) for i in range(0, 3)]
        right_frames = {
     "idle": stand_frames,
                        "walk": move_frames,
                        "jump": jump_frames,
                        "fall": fall_frames,
                        "run": run_frames,
                        "attack": attack_frames}
        left_frames = {
     key: [pygame.transform.flip(frame, True, False) for frame in frames]
                       for key, frames in right_frames.items()}
        all_frames = {
     "left": left_frames, "right": right_frames}
        return all_frames

    def update(self):
        x_move = 0
        y_move = 0
        self.state = "idle"
        self.is_attack = False
        # 获取按键,并进行相应的移动
        key = pygame.key.get_pressed()
        if key[pygame.K_SPACE] and not self.jumped:
            self.vel_y = -15
            self.jumped = True
        if key[pygame.K_LEFT]:
            x_move -= 5
            self.direction = -1
            self.state = "walk"
        elif key[pygame.K_a]:
            x_move -= 7
            self.direction = -1
            self.state = "run"
        if key[pygame.K_RIGHT]:
            x_move += 5
            self.direction = 1
            self.state = "walk"
        elif key[pygame.K_d]:
            x_move += 7
            self.direction = 1
            self.state = "run"

        if key[pygame.K_j] and self.is_attack is False:
            self.state = "attack"
            self.is_attack = True
        if self.vel_y < 0:
            self.state = "jump"
        if self.jumped and self.vel_y > 0:
            self.state = "fall"

        # 添加角色重力(跳跃之后自然下落)
        self.vel_y += 0.8
        if self.vel_y > 10:
            self.vel_y = 10
        y_move += self.vel_y

        self.rect.x += x_move
        self.rect.y += y_move

        # 控制人物的最低位置
        if self.rect.bottom > screen_height - 135:
            self.rect.bottom = screen_height - 135
            self.jumped = False
        self.handle_state()
        self.animate()
        # 绘制人物
        screen.blit(self.current_image, self.rect)
        # pygame.draw.rect(screen, (255, 255, 255), self.rect, 2)


class Cloud(object):
    """云层对象"""

    def __init__(self, x, y):
        self.image = pygame.image.load('cloud.png').convert_alpha()
        self.rect = self.image.get_rect()
        self.rect.topleft = (x, y)

    def update(self):
        self.rect.x -= 1  # 云层移动
        screen.blit(self.image, self.rect)
        if self.rect.x < -1400:  # 超出边界后重新在屏幕最右边绘制云层
            self.rect.x = 1400


class SpriteSheet(object):
    def __init__(self, filename):
        self.filename = filename
        self.sprite_sheet = pygame.image.load(filename).convert()
        self.meta_data = self.filename.replace('png', 'json')
        with open(self.meta_data) as f:
            self.data = json.load(f)
        f.close()

    def get_sprite(self, x, y, w, h):
        sprite = pygame.Surface((w, h))
        sprite.set_colorkey((0, 0, 0))
        sprite.blit(self.sprite_sheet, (0, 0), (x, y, w, h))
        return sprite

    def parse_sprite(self, name):
        sprite = self.data['frames'][name]["frame"]
        x, y, w, h = int(sprite["x"]), int(sprite["y"]), int(sprite["w"]), int(sprite["h"])
        image = self.get_sprite(x, y, w, h)
        image = pygame.transform.scale(image, (90, 120))
        return image


# --------------------------------加载基本的窗口和时钟----------------------------
pygame.init()
screen_width = 1400
screen_height = 700
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('player_control')
clock = pygame.time.Clock()  # 设置时钟
# -------------------------------- 加载对象 ----------------------------------
bg = pygame.image.load("bg.png").convert()
player = Player()
cloud1 = Cloud(0, 0)
cloud2 = Cloud(1400, 0)

# -------------------------------- 游戏主循环 ----------------------------------
run = True
while run:
    clock.tick(60)
    screen.blit(bg, (0, 0))
    # -------------------------------- 角色更新 ----------------------------------
    cloud1.update()
    cloud2.update()
    player.update()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
    # ------------------------------- 窗口更新并绘制 ------------------------------
    pygame.display.update()
pygame.quit()

素材样例(可能存在变形):

pygame教程——1.4英雄角色的动画实现_第1张图片

背景:
pygame教程——1.4英雄角色的动画实现_第2张图片

云彩:
pygame教程——1.4英雄角色的动画实现_第3张图片

英雄图片集合:
pygame教程——1.4英雄角色的动画实现_第4张图片
英雄图片坐标文件:

{
  "frames": {
    "idle": {"frame": {"x": "0", "y": "0", "w": "192", "h": "256"}},
    "jump": {"frame": {"x": "192", "y": "0", "w": "192", "h": "256"}},
    "fall": {"frame": {"x": "384", "y": "0", "w": "192", "h": "256"}},
    "duck": {"frame": {"x": "576", "y": "0", "w": "192", "h": "256"}},
    "hit": {"frame": {"x": "768", "y": "0", "w": "192", "h": "256"}},
    "climb0": {"frame": {"x": "960", "y": "0", "w": "192", "h": "256"}},
    "climb1": {"frame": {"x": "1152", "y": "0", "w": "192", "h": "256"}},
    "cheer0": {"frame": {"x": "1344", "y": "0", "w": "192", "h": "256"}},
    "cheer1": {"frame": {"x": "1536", "y": "0", "w": "192", "h": "256"}},
    "back": {"frame": {"x": "0", "y": "256", "w": "192", "h": "256"}},
    "slide": {"frame": {"x": "192", "y": "256", "w": "192", "h": "256"}},
    "interact": {"frame": {"x": "384", "y": "256", "w": "192", "h": "256"}},
    "switch0": {"frame": {"x": "576", "y": "256", "w": "192", "h": "256"}},
    "switch1": {"frame": {"x": "768", "y": "256", "w": "192", "h": "256"}},
    "kick": {"frame": {"x": "960", "y": "256", "w": "192", "h": "256"}},
    "side": {"frame": {"x": "1152", "y": "256", "w": "192", "h": "256"}},
    "shove": {"frame": {"x": "1344", "y": "256", "w": "192", "h": "256"}},
    "shoveBack": {"frame": {"x": "1536", "y": "256", "w": "192", "h": "256"}},
    "talk": {"frame": {"x": "0", "y": "512", "w": "192", "h": "256"}},
    "attackKick": {"frame": {"x": "192", "y": "512", "w": "192", "h": "256"}},
    "hang": {"frame": {"x": "384", "y": "512", "w": "192", "h": "256"}},
    "hold": {"frame": {"x": "576", "y": "512", "w": "192", "h": "256"}},
    "show": {"frame": {"x": "768", "y": "512", "w": "192", "h": "256"}},
    "behindBack": {"frame": {"x": "960", "y": "512", "w": "192", "h": "256"}},
    "run0": {"frame": {"x": "1152", "y": "512", "w": "192", "h": "256"}},
    "run1": {"frame": {"x": "1344", "y": "512", "w": "192", "h": "256"}},
    "run2": {"frame": {"x": "1536", "y": "512", "w": "192", "h": "256"}},
    "attack0": {"frame": {"x": "0", "y": "768", "w": "192", "h": "256"}},
    "attack1": {"frame": {"x": "192", "y": "768", "w": "192", "h": "256"}},
    "attack2": {"frame": {"x": "384", "y": "768", "w": "192", "h": "256"}},
    "think": {"frame": {"x": "576", "y": "768", "w": "192", "h": "256"}},
    "down": {"frame": {"x": "768", "y": "768", "w": "192", "h": "256"}},
    "drag": {"frame": {"x": "960", "y": "768", "w": "192", "h": "256"}},
    "hurt": {"frame": {"x": "1152", "y": "768", "w": "192", "h": "256"}},
    "wide": {"frame": {"x": "1344", "y": "768", "w": "192", "h": "256"}},
    "rope": {"frame": {"x": "1536", "y": "768", "w": "192", "h": "256"}},
    "walk0": {"frame": {"x": "0", "y": "1024", "w": "192", "h": "256"}},
    "walk1": {"frame": {"x": "192", "y": "1024", "w": "192", "h": "256"}},
    "walk2": {"frame": {"x": "384", "y": "1024", "w": "192", "h": "256"}},
    "walk3": {"frame": {"x": "576", "y": "1024", "w": "192", "h": "256"}},
    "walk4": {"frame": {"x": "768", "y": "1024", "w": "192", "h": "256"}},
    "walk5": {"frame": {"x": "960", "y": "1024", "w": "192", "h": "256"}},
    "walk6": {"frame": {"x": "1152", "y": "1024", "w": "192", "h": "256"}},
    "walk7": {"frame": {"x": "1344", "y": "1024", "w": "192", "h": "256"}},
    "fallDown": {"frame": {"x": "1536", "y": "1024", "w": "192", "h": "256"
      }
    }
  }
}

知识点:

1、动画的实现原理
2、使用相应的坐标文件从图片集合中加载各种动作

ps:如果觉得文章对您有所帮助,欢迎点赞收藏转发,感谢呦!
pygame教程——1.4英雄角色的动画实现_第5张图片

你可能感兴趣的:(pygame系列,pygame,游戏开发,python)