4个版本
0.2.0 | 2024年7月6日 |
---|---|
0.1.0 | 2024年4月10日 |
0.1.0-beta.1 | 2024年4月8日 |
0.1.0-beta.0 | 2024年4月7日 |
#395 in 游戏开发
117每月下载量
145KB
1.5K SLoC
bevy_spritesheet_animation是一个用于动画精灵的Bevy插件,这些精灵由精灵图集支持。
功能
- 一个用于添加到实体以播放动画的Bevy组件component。
- 可调节参数:duration(持续时间),repetitions(重复次数),direction(方向),easing(缓动)。
- 由多个剪辑组成的可组合动画。
- 用于响应动画结束或到达特定点的事件。
- 用于在精灵图集中选择帧的方便的API。
快速开始
- 将SpritesheetAnimationPlugin添加到您的应用程序
- 使用SpritesheetLibrary资源来创建新的剪辑和动画
- 将SpritesheetAnimation组件添加到您的实体
fn main() {
App::new()
.add_plugins(DefaultPlugins)
// Add the plugin to enable animations.
// This makes the SpritesheetLibrary resource available to your systems.
.add_plugins(SpritesheetAnimationPlugin)
.add_systems(Startup, setup)
.run();
}
fn setup(
mut commands: Commands,
mut library: ResMut<SpritesheetLibrary>,
mut atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
assets: Res<AssetServer>,
) {
// Create an animation
let clip_id = library.new_clip(|clip| {
// You can configure this clip here (duration, number of repetitions, etc...)
// This clip will use all the frames in row 3 of the spritesheet
clip.push_frame_indices(Spritesheet::new(8, 8).row(3));
});
let animation_id = library.new_animation(|animation| {
// You can configure this animation here (duration, number of repetitions, etc...)
animation.add_stage(clip_id.into());
// This is a simple animation with a single clip but we can create more sophisticated
// animations with multiple clips, each one having different parameters.
//
// See the `composition` example for more details.
});
// Spawn a sprite using Bevy's built-in SpriteSheetBundle
let texture = assets.load("character.png");
let layout = atlas_layouts.add(TextureAtlasLayout::from_grid(
UVec2::new(96, 96),
8,
8,
None,
None,
));
commands.spawn((
SpriteSheetBundle {
texture,
atlas: TextureAtlas {
layout,
..default()
},
..default()
},
// Add a SpritesheetAnimation component that references our newly created animation
SpritesheetAnimation::from_id(animation_id),
));
commands.spawn(Camera2dBundle::default());
}
概述
动画剪辑
动画剪辑是一系列可重复使用的帧。
它是创建动画的最基本构建块。
使用SpritesheetLibrary资源来创建和配置一个新的剪辑。
然后可以在任何数量的动画中引用此剪辑。
fn setup(mut commands: Commands, mut library: ResMut<SpritesheetLibrary>) {
// Create a clip that uses some frames from a spritesheet
let clip_id = library.new_clip(|clip| {
clip
.push_frame_indices(Spritesheet::new(8, 8).column(2))
.set_default_duration(AnimationDuration::PerCycle(1500))
.set_default_repeat(5);
});
// Add this clip to an animation
let animation_id = library.new_animation(|animation| {
animation.add_stage(clip_id.into());
});
// ... Assign the animation to an entity with the SpritesheetAnimation component ...
}
动画
在其最简单形式中,动画由一个无限循环的单个剪辑组成。
然而,您可以通过链接多个剪辑并调整动画参数来创建更复杂的动画。
使用 SpritesheetLibrary 资源创建一个新的动画。
然后,您可以在任意数量的 SpritesheetAnimation 组件中引用此动画。
fn setup(mut commands: Commands, mut library: ResMut<SpritesheetLibrary>) {
// ...
let animation_id = library.new_animation(|animation| {
let mut stage1 = AnimationStage::from_clip(some_clip_id);
stage1
.set_repeat(5)
.set_easing(Easing::InOut(EasingVariety::Quadratic));
let mut stage2 = AnimationStage::from_clip(another_clip_id);
stage2
.set_duration(AnimationDuration::PerFrame(120))
.set_direction(Animation::Direction::Backwards);
animation
.add_stage(stage1)
.add_stage(stage2)
.set_duration(AnimationDuration::PerCycle(1000))
.set_direction(Animation::Direction::PingPong);
});
// ... Assign the animation to an entity with the SpritesheetAnimation component ...
}
将剪辑和动画视为资产!
剪辑和动画应该只创建一次。然后,您可以将其分配给许多实体。
❌ 错误
您不应该为每个播放的实体创建相同的剪辑/动画。
fn spawn_enemies(mut commands: Commands, mut library: ResMut<SpritesheetLibrary>) {
// Creating identical animations gives more work to the plugin and degrades performance!
for _ in 0..100 {
let clip_id = library.new_clip(|clip| { /* ... */ });
let animation_id = library.new_animation(|animation| { /* ... */ });
commands.spawn((
SpriteSheetBundle { /* .... */ },
SpritesheetAnimation::from_id(animation_id),
));
}
}
👍 正确
相反,一次性创建剪辑/动画,然后在需要时引用它们。
例如,您可以在设置系统中创建所有动画,给它们唯一的名称,然后在稍后的阶段将它们分配给实体。
fn create_animation(mut library: ResMut<SpritesheetLibrary>) {
let clip_id = library.new_clip(|clip| { /* ... */ });
let animation_id = library.new_animation(|animation| { /* ... */ });
// Here, we name the animation to make it easy to retrieve it in other systems.
//
// Alternatively, you may prefer to store the animation ID yourself.
// For instance, in a Bevy Resource that contains the IDs of all your clips/animations.
// Something like:
//
// #[derive(Resource)]
// struct GameAnimations {
// enemy_running: Option<AnimationId>,
// enemy_firing: Option<AnimationId>,
// ... and so on ...
// }
library.name_animation(animation_id, "enemy running");
}
fn spawn_enemies(mut commands: Commands, library: Res<SpritesheetLibrary>) {
// Retrieve our animation and assign it to many entities
if let Some(animation_id) = libray.animation_with_name("enemy running") {
for _ in 0..100 {
commands.spawn((
SpriteSheetBundle { /* .... */ },
SpritesheetAnimation::from_id(animation_id),
));
}
}
}
更多示例
有关更多示例,请浏览 examples/ 目录。
示例 | 描述 |
---|---|
基本 | 最小示例,展示如何创建一个动画精灵 |
组合 | 高级示例,展示如何创建具有多个阶段的动画 |
参数 | 显示每个参数的效果 |
角色 | 展示如何创建具有多个动画的可控角色 |
事件 | 展示如何使用事件对动画到达感兴趣点做出反应 |
压力测试 | 数千个动画精灵的压力测试 |
兼容性
bevy | bevy_spritesheet_animation |
---|---|
0.14 | 0.2.0 |
0.13 | 0.1.0 |
鸣谢
- 示例中使用的角色精灵表来自 thekingphoenix 的 CC0。
依赖项
~35–72MB
~1.5M SLoC