40个版本

0.6.0 2024年5月3日
0.5.61 2024年2月8日
0.5.21 2023年12月18日
0.3.1 2023年7月7日
0.2.3 2023年3月19日

#440 in 游戏开发

Download history 229/week @ 2024-05-02 6/week @ 2024-05-09 3/week @ 2024-05-16 3/week @ 2024-05-23 1/week @ 2024-06-06 95/week @ 2024-07-25 20/week @ 2024-08-01

每月115次下载

MIT/Apache

84KB
1.5K SLoC

bevy_animations是一个轻量级的2D动画引擎,为Bevy构建

Bevy Animations仍在beta测试中,未来可能会发生重大的API和后端更改。

bevy_animations能做什么

  • 完全集成到Bevy ECS
  • 易于使用的构建器模式语法
  • 创建具有自定义配置的实体动画
  • 自动释放动画实体

将bevy_animations添加到您的Bevy应用

use bevy_animations::AnimationsPlugin;
use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(AnimationsPlugin {
            pixels_per_meter: 20. // your desired pixels_per_meter
        })
        .run()
}

bevy_animations动画的工作原理

  • 为每个帧指定时间或meters_per_frame
  • 用户定义哪些y索引是面向左、右、上和下的精灵,或者精灵是否应该翻转
  • 某些动画可以阻止其他动画发生
  • 使用基于优先级的系统,您可以定义具有不同优先级的多个阻止动画以进行渲染

如何定义bevy_animations动画

您首先需要使用Commands之类的命令生成一个实体,如下所示

use bevy_animations::*;
use bevy::prelude::*;

fn entity_setup(
    mut commands: Commands,
    animations: ResMut<Animations>
) {
    let entity = commands.spawn(
        Animator::default(), // the `AnimationDirection` component is needed on the entity to determine the direction
        SpriteSheetBundle {
            texture_atlas: // your sprite sheet handle
            transform: Transform::from_xyz(0., 0., 0.) // your desired location in the `World`
        }
        /* The rest of your entity configuration */
    );
}

注意如果您没有向您的实体添加AnimationDirection组件,则您的动画看起来将永远不会插入,因为bevy_animations正在其Query中寻找AnimationDirection组件

然后您可以将您的动画添加到ResMut<Animations>,如下所示

animations.insert_animation(
    NewAnimation {
        handle: player_movement_texture.clone(), /* the handle for the TextureAtlas */
        animation: AnimationType::Timed(
            TransformAnimation::new(
                    Vec::from(PLAYER_RUNNING_FRAMES), /* animation_frames */
                    PLAYER_RUNNING_METERS_PER_FRAME, /* meters_per_frame */
                    Vec2::new(14., 38.), /* frame */
                    AnimationDirectionIndexes::FlipBased(FlipBasedDirection { /* direction_indexes */
                        left_direction_is_flipped: true,
                        x_direction_index: 3,
                    }),
                    true, /* repeating */
                ),
                "player_running", /* AnimationName */
        ),
    },
    Some(player_entity), /* specify an entity to add the animation to now instead of later */
)

注意如果您有一个单向动画,您可以使用AnimationDirectionIndexes::one_directional()

注意确保您向bevy_animations传递正确的字符串以使您的实体动画化

您还可以添加一个TimedAnimation,如下所示

animations.insert_animation(
    NewAnimation {
        handle: player_movement_texture.clone(), /* the handle for the TextureAtlas */
        animation: AnimationType::Timed(
            TimedAnimation::new(
                    Vec::from(PLAYER_RUNNING_FRAMES), /* animation_frames */
                    Vec::from(PLAYER_RUNNING_TIMINGS), /* frame_timings_in_secs */
                    Vec2::new(14., 38.), /* frame */
                    AnimationDirectionIndexes::FlipBased(FlipBasedDirection { /* direction_indexes */
                        left_direction_is_flipped: true,
                        x_direction_index: 3,
                    }),
                    true, /* repeating */
                    false, /* blocking */
                    0 /* blocking_priory */
                ),
                "player_running", /* AnimationName */
        ),
    },
    Some(player_entity), /* specify an entity to add the animation to now instead of later */
)

然后我们可以通过发送它到EventWriter<AnimationEvent>来开始动画,如下所示

fn move_player(
    mut event_writer: EventWriter<AnimationEvent>,
    player_query: Query<Entity, With<Player>>
) {
    // your move logic here...

    event_writer.send(AnimationEvent("player_running", entity));
}
  • 注意您可以在动画进行时发送具有相同名称的事件多次,而不会破坏它

  • 注意已发送的动画将播放至结束或无限重复

如果您想更改动画的方向,您将像这样从 AnimatingEntity 中查询它

fn move_player(
    mut event_writer: EventWriter<AnimationEvent>,
    mut query: Query<&mut Animator, With<Player>> // specify the `With` to get the entity associated with your custom component 
) {
    // your move logic here...

    let mut animator = query.single_mut(); // get the direction via query

    animator.change_direction(AnimationDirection::Left); // the direction can be changed like this

    event_writer.send(AnimationEvent("player_running", entity));
}
  • 注意 如果您发送一个不同名称的事件,实体当前的动画将立即更改,除非当前动画正在阻止或具有更高的优先级。

了解这一点,您可以在另一个系统中将 player_running 动画更改为 player_die,在该系统中您可以检查碰撞,如下所示

fn check_collisions(
    mut commands: Commands,
    rapier_context: Res<RapierContext> // great 2d physics engine for lots of things we are using it for collision detection
    mut event_writer: EventWriter<AnimationEvent>,
    player_query: Query<Entity, With<Player>>,
    bullet_query: Query<Entity, With<Bullet>>
) {
    let player_entity = player_query.single();

    for bullet_entity in bullet_query.iter() {
        if let Some(_) = context.contact_pair(bullet_entity, player_entity) {
            // send the event for the animating entity
            event_writer.send(AnimationEvent("player_die", entity));
            // despawn the entity after death
            commands.entity(player_entity).despawn();
            commands.entity(bullet_entity).despawn();
        }         
    }
}
  • 注意 如果实体在 World 中不存在,即当实体通过 .despawn() 失踪时,bevy_animations 将自动从它自己的数据结构中删除您的实体。

  • 注意 目前还没有内部功能可以执行类似在动画完成后销毁实体的任务。但是,您可以自行实现。

版本控制

bevy bevy_animations
0.13.x 0.6.x
0.12.x 0.5.x
0.11.x 0.4.x
0.10.x 0.3.x
0.9.x 0.2.x

更多文档

如果您需要更深入的文档和所有当前实现更多示例,请阅读bevy_animations 书籍或访问API 文档

开源

bevy_animations 将永远开源。您可以通过GitHub 仓库 进行贡献。

依赖关系

~18–46MB
~733K SLoC