Skip to content

hyj1230/INS-Transition

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

INS-Transition

简介

这是一个为 Python 对象提供 CSS 风格过渡(transition)功能的轻量级库。你可以定义多个状态(state),每个状态为对象的属性指定目标值和过渡配置( 持续时间、延迟、缓动函数),然后通过 TransitionGroup 在状态之间切换,实现属性的平滑过渡。其行为模仿了 Web 前端中 CSS Transition 的特性,包括反转缩短(reverse shortening)

安装

目前库以源码形式提供,你可以将文件放置在你的项目中直接导入:

from INS-Transition import TransitionGroup, State, TransitionData

需要依赖 Python 3.6+。

核心概念

TransitionData(过渡配置)

TransitionData 定义了过渡的持续时间、缓动函数和延迟。类似于 CSS 的 transition-durationtransition-timing-functiontransition-delay

data = TransitionData(
 transition_duration='0.5s', # 支持字符串如 '0.5s' 或数字(秒)
 transition_timing_function=ease, # 缓动函数
 transition_delay='0.1s' # 延迟时间
)
  • transition_duration 以秒或毫秒为单位指定过渡动画所需的时间。默认值为 '0s',表示不出现过渡动画。特别地,负数时间也会被存储为 '0s'
    其支持以下形式的参数:
    1. CSS 风格的字符串,如 '100ms', '.5s'
    2. 一个整数或浮点数,以秒为单位
  • transition_timing_function 设置如何计算受过渡效果影响的属性的中间值。 其支持以下形式的参数:
    1. 代码形式,需要通过 from INS-Transition import 需要的函数 导入,具体包含:
      1. 预制的缓动函数 linear, ease, ease_in, ease_in_out, ease_out
      2. 自定义缓动函数,如 CubicBezier(0.42, 0.0, 0.58, 1.0)
    2. CSS 风格字符串形式,具体包含:
      1. 预制的缓动函数 'linear', 'ease', 'ease-in', 'ease-in-out', 'ease-out'
      2. 自定义缓动函数,如 'cubic-bezier(.42, 0, .58, 1)'
  • transition_delay 规定了在过渡效果开始作用之前需要等待的时间。值的格式与 transition_duration 相同,表明动画过渡效果将在何时开始。取值为正时会延迟一段时间来响应过渡效果;取值为负时与 CSS 处理方式相同,这里不做介绍。

Property(属性包装器)

Property 内部管理对象某个属性的过渡逻辑。通常你不需要直接创建它,而是通过 TransitionGroup 自动生成。

每个 Property 持有:

  • object_class: 需要进行过渡操作的外部对象
  • name: 属性的名称
  • value:当前值(直接读写对象属性,通过 getattr(object_class, name) 以及 setattr
  • after_change_value:最终目标值
  • transition_data:过渡配置
  • transition:当前正在进行的过渡实例(内部)

State(状态)

State 是一组属性目标值和过渡配置的集合。你可以通过 State.create() 快速创建。

对于状态中的每个属性,创建的格式如下:
属性名 = (目标值, TransitionData对象)

state_a = State.create(
 x=(100, TransitionData('1s')),
 y=(200, TransitionData('0.5s', linear))
)

状态之间可以继承:子状态若未定义某属性,会自动从父状态(通常是默认状态)获取。

每个 State 类内部不会存储状态的名称,状态的名称将在 TransitionGroup 中统一管理

TransitionGroup(状态组)

TransitionGroup 是核心类,它持有一个对象和多个状态,负责在切换状态时更新所有属性的过渡。

你需要在每一帧调用 update() 方法来实时计算所有属性的过渡

切换状态需要使用 set_state(字符串形式的状态名称) 方法

group = TransitionGroup(
 object_class=box,  # 要控制的对象
 default_state=default_state,  # 默认状态,其状态名称将被赋予为 'default'
 lerp_funcs={'x': my_lerp},  # 可选,为特定属性指定插值函数
 state1=state1, # 其他状态,格式为 状态名称 = State对象
 state2=state2
)

对于非数值类的属性,lerp_funcs 的指定是必要的。lerp_funcs 是一个字典,表示每个属性对应的插值函数(一般应当为线性插值)

自定义的插值函数要求符合以下格式:

def lerp(t, value1, value2):
    return new_value

其中,t 是表示进度的浮点数,决定了结果处于 value1value2 之间的位置。特别地,0表示返回 value1,1表示返回 value2

比如,这是内置的插值函数:

def lerp(t: float, value1, value2):
    """线性插值函数"""
    return value1 + (value2 - value1) * t

另给出一个示例,这是用于插值 pygame.Color 的函数:

def lerp_color(t: float, color1: pygame.Color, color2: pygame.Color):
    """颜色线性插值函数"""
    return color1.lerp(color2, t)

Transition(运行时过渡实例)

Transition 是内部类,表示一个正在进行的过渡过程。用户一般无需直接操作它。

特性详解

类似 CSS 的过渡配置

  • 持续时间延迟 支持字符串(如 '0.3s')或数字(秒)。
  • 缓动函数:内置贝塞尔曲线缓动函数
  • 多个属性可独立配置:每个属性可以在不同状态中拥有自己的过渡参数。(若未配置,将自动从 'default' 状态继承)

反转缩短(Reverse Shortening)

这是 CSS 过渡的一个细节:当一个过渡正在进行时,如果目标值被改回过渡开始时的值,过渡不会重新开始,而是“反转”并缩短剩余时间。本库实现了这一行为。这一特性使得状态切换更加自然。

API 参考

class TransitionData

初始化参数

  • transition_duration (str/float):持续时间,默认 '0s'
  • transition_timing_function (str/callable):缓动函数,默认 ease
  • transition_delay (str/float):延迟,默认 '0s'

属性

  • duration (float):持续时间(秒)。
  • timing_function (callable):缓动函数。
  • delay (float):延迟(秒)。
  • combine_duration (float):delay + duration

class Property

通常不直接实例化,由 TransitionGroup 自动创建。

方法

  • update():更新属性值(基于当前过渡状态)。应在循环中调用。
  • value (property):获取/设置当前值(直接读写对象属性)。

class State

类方法

  • create(**kwargs):快速创建状态。参数格式为 属性名=(目标值, TransitionData对象)
  • none_transition_data:类属性,表示无过渡的默认配置。

实例方法

  • add_property(property_name, target_value, transition_data=None):添加或更新属性。
  • inherit_state(father_state):从父状态继承未定义的属性。

class TransitionGroup

初始化参数

  • object_class:要控制的对象。
  • default_state (State):默认状态。
  • lerp_funcs (dict, optional):为特定属性指定插值函数,格式 {属性名: 函数}
  • **kwargs:额外的状态,如 state1=state_obj

方法

  • add_state(name, state):添加一个命名状态。
  • add_states(**kwargs):批量添加状态。
  • update():计算所有属性的过渡。
  • set_state(new_state_name):切换到指定状态,更新每个属性的目标值和过渡配置。

属性

  • current_state_name:字符串,当前状态名。
  • property:字典,{属性名: Property对象}
  • states:字典,{状态名: State对象}

快速使用

按照以下四个步骤,你可以快速上手使用 INS-Transition 实现属性平滑过渡:

  1. 选定需要应用过渡的属性 确定你想要实现动画效果的对象属性,例如位置(x, y)、尺寸(width, height)、颜色(color)等。这些属性将作为过渡的目标。

  2. 设定 'default' 状态 创建一个 State 对象作为默认状态,为每个属性指定初始值。

    default = State.create(
        x=(0, TransitionData('1s')),
        y=(0, TransitionData('1s'))
    )

    这类似于以下 CSS 代码:

    .box {
        transform: translate(0px, 0px);
        transition: transform 1s ease;
    }
  3. 设定其他状态 根据需要创建其他状态(如 'hover''active'

    hover = State.create(
        x=(100, TransitionData('0.5s', ease_out)),
        y=(200, TransitionData('0.5s', ease_out))
    )

    这类似于以下 CSS 代码:

    .box:hover {
        transform: translate(100px, 200px);
        transition: transform 0.5s ease-out;
    }
  4. 主循环中执行 update() 方法 将对象和状态绑定到 TransitionGroup,并在每一帧(如游戏循环)中调用其 update() 方法。切换状态时使用 set_state()update() 会自动计算并更新对象的属性值。

    group = TransitionGroup(my_object, default, hover=hover)
    
    while running:  # 主循环
        group.update()  # 每帧调用,更新属性
        # 渲染对象...
        if 条件满足:
            group.set_state('hover')  # 切换到 hover 状态

完整示例

下面是一个更完整的示例,你也可以查看 slider_test.py 这个更复杂的示例

import pygame
import sys
from INS_Transition import State, TransitionGroup, TransitionData


pygame.init()
w, h = 800, 600
screen = pygame.display.set_mode((w, h), pygame.RESIZABLE)
clock = pygame.time.Clock()


class Button:
    def __init__(self):
        self.center = (400, 300)
        self.w, self.h = 200, 100
        
        self.state = False

        default_state = State.create(
            w = (self.w, TransitionData('1s')),
            h = (self.h, TransitionData('1s'))
        )
        focus_state = State.create(
            w = (self.w * 1.5, TransitionData('1s')),
            h = (self.h * 1.5, TransitionData('1s'))
        )
        
        self.transition_group = TransitionGroup(self, default_state, focus = focus_state)
        
    def get_rect(self):
        rect = pygame.Rect(0, 0, round(self.w), round(self.h))
        rect.center = self.center
        return rect

    def render(self, sf):
        pygame.draw.rect(sf, (255, 0, 0), self.get_rect(), border_radius=20)

    def handle_event(self, _event):
        if _event.type == pygame.MOUSEBUTTONDOWN and self.get_rect().collidepoint(_event.pos):
            self.state = not self.state
            self.transition_group.set_state('focus' if self.state else 'default')
                
    def update(self):
        self.transition_group.update()


button = Button()


while 1:
    pygame_events = pygame.event.get()
    for event in pygame_events:
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        button.handle_event(event)

    screen.fill('white')
    button.update()
    button.render(screen)

    pygame.display.flip()
    clock.tick(120)

About

A third-party library that references CSS specifications and is written with Pygame for transitions, making smooth transition effects no longer cumbersome.

Topics

Resources

License

Stars

2 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages