#状态管理 #曲线 #关键帧 #插值 #保存 #系统 #游戏引擎

bevy_state_curves

为 Bevy 游戏引擎提供通过曲线关键帧进行状态保存和管理的小型库

13 个版本 (5 个重大更新)

0.6.0 2024 年 7 月 5 日
0.5.0 2024 年 2 月 20 日
0.4.0 2024 年 2 月 12 日
0.3.6 2023 年 12 月 15 日
0.3.1 2023 年 11 月 14 日

游戏开发 中排名 #218

Download history 150/week @ 2024-07-01 15/week @ 2024-07-08 80/week @ 2024-07-29

每月 82 次下载

MIT/Apache

42KB
329

bevy_state_curves

Following released Bevy versions crates.io docs.rs

Bevy_State_Curves 是根据这篇 博客文章 中的状态存储和插值系统实现的。这个系统在《星际争霸》中使用,并具有一些从它中产生的有趣特性。

这个包的实现专注于编译时曲线和与 ECS 的集成。编译时曲线是为了性能因素而选择的,而 ECS 是因为 ECS 的一切。

版本兼容性表

Bevy 版本 包版本
0.14 0.6.0
0.13 0.5.0
0.12 0.3.1 - 0.4.0

用法

  1. 创建一个新的曲线关键帧类型

    /// Only Clone is needed for the CurveKeyframes. I also recommend `Component` as it is
    /// an ergonomic way to handle having the current interpolated state be the state thats
    /// on the entity physically
    #[derive(Clone)]
    pub struct ObjectRadius {
        radius: f32,
    }
    
    impl LinearKeyframe<ObjectRadius> for ObjectRadius {
        fn lerp(&self, next_frame_state: &ObjectRadius, ratio: f64) -> ObjectRadius {
            ObjectRadius {
                radius: self.radius + (next_frame_state.radius - self.radius) * ratio as f32,
            }
        }
    }
    
    /// Generally only implement one Keyframe type for a specific type of state.
    /// Nothing technically stops you from doing all three for one but theres absolutely no reason to do that.
    impl SteppedKeyframe<ObjectRadius> for ObjectRadius {}
    
    impl PulseKeyframe<ObjectRadius> for ObjectRadius {}
    
    
  2. 使用适合您的曲线类型的正确曲线组件类型将其插入实体中。 LinearCurve<ObjectRadius>PulseCurve<ObjectRadius>SteppedCurve<ObjectRadius>

         commands.entity(entity).insert(LinearCurve<ObjectRadius>::new());
    
  3. 使用曲线作为实体上的常规组件添加/删除关键帧。使用常规查询在常规系统中获取状态!

        fn insert_keyframes(mut radius_query: Query<&mut LinearCurve<ObjectRadius>){
            for radius in radius_query.iter_mut(){
                radius.insert_keyframe(1, ObjectRadius{radius: 1.0});
                radius.insert_keyframe(10, ObjectRadius{radius: 2.0});
            }
        }
    
        fn curve_entity_system(radius_query: Query<&LinearCurve<ObjectRadius>){
            for radius in radius_query.iter(){
                let radius_at_tick = radius.get_state(5);
                assert_eq!(radius_at_tick, 1.5);
            }
        }
    

游戏时钟

这个包依赖于一个内部的 GameTick 类型别名,这是一个 u64,用于创建时间的感知。更高的时钟被认为是比编号较低的时钟更晚/更旧的。当使用这个包时,您将必须决定您的包中的时钟将是什么样子,并自己实现这些系统。这个包除了提供它和使用它作为状态关键帧的标识符之外,不做任何与 GameTick 相关的事情。

请参阅 solar_system.rs 示例,了解如何在游戏概念中使用 GameTick

曲线

这个包支持三种类型的曲线。有关每个曲线如何工作的详细信息,请参阅 docs.rs 文档。这些都是 Bevy 组件。

  • LinearCurve<T:LinearKeyFrame>
    • 在它的两侧每个关键帧之间线性插值状态。
  • SteppedCurve<T:SteppedKeyFrame>
    • 关键帧之间的状态是平坦的,状态始终与最后一个关键帧相同。
  • PulseCurve<T:脉冲关键帧>
    • 关键帧只在它们存在的刻有效。

功能

  • Serde
    • 包含在“serde”功能下,为所有包含的曲线类型实现了序列化和反序列化。
  • 类型路径
    • 包含在“type_path”功能下。为所有曲线类型实现了Bevy的类型路径

未来计划

Bevy_State_Curves是为我有一个特定的开源项目想法而创建的。随着该项目的成形,我最终会在这里链接它。因此,这个crate的功能将由那个项目所需的功能驱动。如果您随机且糟糕地决定使用这个crate,请告诉我是否有问题,需要更新,或者更好的是,根据需要制作prs和issues!

目前,当前潜在的功能想法包括

  • 一个自定义的SystemParam,用于创建和管理曲线。用于驱动其他功能
  • 一个StateLifetime的概念。基本上,当状态存在于世界中时。这将用于驱动全局状态概念的过滤。例如,通过只过滤“当时存在”的状态来重置世界到这个刻。
  • 更多的CurveTrait函数。目前还不知道,但我确信最终还需要更多。
  • 反射和Serde功能(实现了serde和类型路径)
  • 测试!!!

其中一些功能可能不会在这个crate本身中实现。它们太具体,更容易在使用这个crate的任何项目中手动实现。其他如测试、serde和类似的功能将很快实现。

依赖关系

~22MB
~403K SLoC