|
|
|
|
import pygame
|
|
|
|
|
from pygame.surface import Surface
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Animation:
|
|
|
|
|
"""
|
|
|
|
|
动画类
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, x, y, img, dw, dh, time, loop, frame_range, frame_callback=None, done_callback=None, fps=60,
|
|
|
|
|
need_blend=False, **kwargs):
|
|
|
|
|
"""
|
|
|
|
|
:param x:绘制动画的中心点(不是左上角)
|
|
|
|
|
:param y:绘制动画的中心点(不是左上角)
|
|
|
|
|
:param img:序列帧图片
|
|
|
|
|
:param dw:单位宽度
|
|
|
|
|
:param dh:单位高度
|
|
|
|
|
:param time:动画播放时长,单位毫秒
|
|
|
|
|
:param loop:否是循环播放
|
|
|
|
|
:param frame_range:动画帧范围,第一帧为0,比如[0,3]为4帧 [1,3]为3帧
|
|
|
|
|
:param frame_callback:帧回调
|
|
|
|
|
:param done_callback:完成回调
|
|
|
|
|
"""
|
|
|
|
|
self.x = x
|
|
|
|
|
self.y = y
|
|
|
|
|
self.img = img
|
|
|
|
|
self.time = time
|
|
|
|
|
self.need_blend = need_blend
|
|
|
|
|
# 一共多少帧
|
|
|
|
|
self.frame_range = frame_range
|
|
|
|
|
self.frame = frame_range[1] - frame_range[0] + 1
|
|
|
|
|
self.dw = dw
|
|
|
|
|
self.dh = dh
|
|
|
|
|
self.speed = int(time / self.frame)
|
|
|
|
|
self.loop = loop
|
|
|
|
|
self.least_once = False # 动画是否至少播放了一次
|
|
|
|
|
self.frame_callback = frame_callback
|
|
|
|
|
self.done_callback = done_callback
|
|
|
|
|
# 精灵图的行和列
|
|
|
|
|
self.row = int(self.img.get_height() / self.dh)
|
|
|
|
|
self.col = int(self.img.get_width() / self.dw)
|
|
|
|
|
self.current_frame = self.frame_range[0] # 当前帧
|
|
|
|
|
self.frame_count = int(self.speed / (1000 / fps)) # 需要等待几次主循环才切换1帧
|
|
|
|
|
self.current_count = self.frame_range[0] * self.frame_count # 当前计数
|
|
|
|
|
|
|
|
|
|
if self.frame_count < 1:
|
|
|
|
|
self.frame_count = 1
|
|
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
|
last_frame = self.current_frame
|
|
|
|
|
self.current_count += 1
|
|
|
|
|
self.current_frame = int(self.current_count / self.frame_count)
|
|
|
|
|
if self.current_frame > self.frame_range[1]:
|
|
|
|
|
# 播放完成
|
|
|
|
|
self.current_frame = self.frame_range[0]
|
|
|
|
|
self.current_count = self.frame_range[0] * self.frame_count
|
|
|
|
|
self.least_once = True
|
|
|
|
|
# 帧回调
|
|
|
|
|
if self.frame_callback:
|
|
|
|
|
self.frame_callback(last_frame)
|
|
|
|
|
# 完成回调
|
|
|
|
|
if self.done_callback:
|
|
|
|
|
self.done_callback(last_frame)
|
|
|
|
|
else:
|
|
|
|
|
# 播放中
|
|
|
|
|
# 每个动画帧回调,而不是每个主循环回调
|
|
|
|
|
if last_frame != self.current_frame and self.frame_callback:
|
|
|
|
|
self.frame_callback(last_frame)
|
|
|
|
|
|
|
|
|
|
def draw(self, surface):
|
|
|
|
|
"""
|
|
|
|
|
绘图,把x,y作为中心点绘制
|
|
|
|
|
:param surface: 目标surface
|
|
|
|
|
"""
|
|
|
|
|
dest_x = self.x - self.dw / 2
|
|
|
|
|
dest_y = self.y - self.dh / 2
|
|
|
|
|
cell_x = self.current_frame % self.col
|
|
|
|
|
cell_y = int(self.current_frame / self.col)
|
|
|
|
|
self.draw_cell(surface, self.img, dest_x, dest_y, cell_x, cell_y, self.dw, self.dh)
|
|
|
|
|
|
|
|
|
|
def blend_draw(self, surface, blend_type):
|
|
|
|
|
"""
|
|
|
|
|
带alpha混合的draw
|
|
|
|
|
"""
|
|
|
|
|
dest_x = self.x - self.dw / 2
|
|
|
|
|
dest_y = self.y - self.dh / 2
|
|
|
|
|
cell_x = self.current_frame % self.col
|
|
|
|
|
cell_y = int(self.current_frame / self.col)
|
|
|
|
|
self.draw_cell(surface, self.img, dest_x, dest_y, cell_x, cell_y, self.dw, self.dh, blend_type)
|
|
|
|
|
|
|
|
|
|
def draw_src(self, surface, x, y):
|
|
|
|
|
"""
|
|
|
|
|
绘图,把x,y作为左上角绘制
|
|
|
|
|
"""
|
|
|
|
|
cell_x = self.current_frame % self.col
|
|
|
|
|
cell_y = int(self.current_frame / self.col)
|
|
|
|
|
self.draw_cell(surface, self.img, x, y, cell_x, cell_y, self.dw, self.dh)
|
|
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
|
"""
|
|
|
|
|
重置动画
|
|
|
|
|
"""
|
|
|
|
|
self.current_frame = 0
|
|
|
|
|
self.current_count = 0
|
|
|
|
|
self.least_once = False
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def draw_cell(dest, source, x, y, cell_x, cell_y, cell_w=32, cell_h=32, blend_type=0):
|
|
|
|
|
"""
|
|
|
|
|
绘制精灵图中指定x,y的图像
|
|
|
|
|
:param dest: surface类型,要绘制到的目标surface
|
|
|
|
|
:param source: surface类型,来源surface
|
|
|
|
|
:param x: 绘制图像在dest中的坐标
|
|
|
|
|
:param y: 绘制图像在dest中的坐标
|
|
|
|
|
:param cell_x: 在精灵图中的格子坐标
|
|
|
|
|
:param cell_y: 在精灵图中的格子坐标
|
|
|
|
|
:param cell_w: 单个精灵的宽度
|
|
|
|
|
:param cell_h: 单个精灵的高度
|
|
|
|
|
:return:
|
|
|
|
|
"""
|
|
|
|
|
dest.blit(source, (x, y), (cell_x * cell_w, cell_y * cell_h, cell_w, cell_h), special_flags=blend_type)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Animator:
|
|
|
|
|
"""
|
|
|
|
|
动画管理类
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, surface):
|
|
|
|
|
"""
|
|
|
|
|
:param surface: 动画显示的目标surface(一般是窗口surface)
|
|
|
|
|
"""
|
|
|
|
|
self.surface = surface
|
|
|
|
|
self.animations = [] # 存储着当前的动画
|
|
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
|
"""
|
|
|
|
|
动画管理类逻辑更新
|
|
|
|
|
"""
|
|
|
|
|
for animation in self.animations[::-1]:
|
|
|
|
|
animation.update()
|
|
|
|
|
# 动画播放完成,删除动画
|
|
|
|
|
if not animation.loop and animation.least_once:
|
|
|
|
|
self.animations.remove(animation)
|
|
|
|
|
|
|
|
|
|
def draw(self):
|
|
|
|
|
"""
|
|
|
|
|
渲染各个动画
|
|
|
|
|
"""
|
|
|
|
|
for animation in self.animations:
|
|
|
|
|
if animation.need_blend:
|
|
|
|
|
animation.blend_draw(self.surface, pygame.BLEND_ADD)
|
|
|
|
|
else:
|
|
|
|
|
animation.draw(self.surface)
|
|
|
|
|
|
|
|
|
|
def add(self, x, y, img, dw, dh, time, loop, frame_range, frame_callback=None, done_callback=None):
|
|
|
|
|
"""
|
|
|
|
|
添加一个动画
|
|
|
|
|
:param x:绘制动画的中心点(不是左上角)
|
|
|
|
|
:param y:绘制动画的中心点(不是左上角)
|
|
|
|
|
:param img:序列帧图片
|
|
|
|
|
:param dw:单位宽度
|
|
|
|
|
:param dh:单位高度
|
|
|
|
|
:param time:动画播放时长,单位毫秒
|
|
|
|
|
:param loop:否是循环播放
|
|
|
|
|
:param frame_range:动画帧范围
|
|
|
|
|
:param frame_callback:帧回调
|
|
|
|
|
:param done_callback:完成回调
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
animation = Animation(x, y, img, dw, dh, time, loop, frame_range, frame_callback, done_callback)
|
|
|
|
|
self.animations.insert(0, animation)
|
|
|
|
|
self.animations.sort(key=lambda obj: obj.y)
|
|
|
|
|
|
|
|
|
|
def add_ani(self, *animations):
|
|
|
|
|
for ani in animations:
|
|
|
|
|
self.animations.insert(0, ani)
|
|
|
|
|
self.animations.sort(key=lambda obj: obj.y)
|
|
|
|
|
|
|
|
|
|
def clear(self):
|
|
|
|
|
"""
|
|
|
|
|
清空所有动画
|
|
|
|
|
"""
|
|
|
|
|
self.animations = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Fade:
|
|
|
|
|
"""
|
|
|
|
|
淡出淡入
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, dest):
|
|
|
|
|
self.sw = False # 开关,是否启动淡入淡出
|
|
|
|
|
self.callback = None # 回调函数
|
|
|
|
|
self.state = 0 # 当前状态
|
|
|
|
|
self.speed = 5
|
|
|
|
|
self.alpha = 0
|
|
|
|
|
self.dest = dest
|
|
|
|
|
self.surface = Surface((640, 480))
|
|
|
|
|
self.surface.fill((0, 0, 0))
|
|
|
|
|
self.surface.set_alpha(self.alpha)
|
|
|
|
|
|
|
|
|
|
def logic(self):
|
|
|
|
|
if not self.sw:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if self.state == 0: # 第一阶段,淡出
|
|
|
|
|
self.alpha += self.speed
|
|
|
|
|
if self.alpha >= 255:
|
|
|
|
|
self.alpha = 255
|
|
|
|
|
if self.callback:
|
|
|
|
|
self.callback()
|
|
|
|
|
self.state = 1
|
|
|
|
|
|
|
|
|
|
elif self.state == 1: # 第二阶段,淡入
|
|
|
|
|
self.alpha -= self.speed
|
|
|
|
|
if self.alpha <= 0:
|
|
|
|
|
self.sw = False
|
|
|
|
|
|
|
|
|
|
self.surface.set_alpha(self.alpha)
|
|
|
|
|
|
|
|
|
|
def draw(self):
|
|
|
|
|
if not self.sw:
|
|
|
|
|
return
|
|
|
|
|
self.dest.blit(self.surface, (0, 0))
|
|
|
|
|
|
|
|
|
|
def start(self, callback=None):
|
|
|
|
|
self.reset()
|
|
|
|
|
self.sw = True
|
|
|
|
|
self.callback = callback
|
|
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
|
self.state = 0 # 当前状态
|
|
|
|
|
self.alpha = 0
|