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 游戏开发
每月115次下载
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