6个版本 (破坏性)
0.6.0 | 2024年7月7日 |
---|---|
0.5.0 | 2024年4月5日 |
0.4.0 |
|
0.3.0 | 2024年1月16日 |
0.1.0 | 2023年4月30日 |
157 在 游戏开发 中排名
每月386次 下载
38KB
259 行
extol_sprite_layer
允许您使用单独的组件来指定 Bevy 游戏中精灵的绘制顺序,而不是通过变换的z坐标。
如何使用
use bevy::prelude::*;
use extol_sprite_layer::{LayerIndex, SpriteLayerPlugin, SpriteLayerOptions};
// Define a type to represent your layers. All the traits here other than Copy
// are mandatory.
#[derive(Debug, Copy, Clone, Component, PartialEq, Eq, Hash)]
enum SpriteLayer {
Background,
Object,
Enemy,
Player,
Ui,
}
impl LayerIndex for SpriteLayer {
// Convert your type to an actual z-coordinate.
fn as_z_coordinate(&self) -> f32 {
use SpriteLayer::*;
match *self {
// Note that the z-coordinates must be at least 1 apart...
Background => 0.,
Object => 1.,
Enemy => 2.,
// ... but can be more than that.
Player => 990.,
Ui => 995.
}
}
}
let mut app = App::new();
// Then, add the plugin to your app.
app
.add_plugins(DefaultPlugins)
.add_plugins(SpriteLayerPlugin::<SpriteLayer>::default());
// Now just use SpriteLayer as a component and don't set the z-component on any
// of your transforms.
// To disable y-sorting, do
app.insert_resource(SpriteLayerOptions { y_sort: false });
注意事项
总的来说,它执行以下操作
- 在
Last
调度中,它为具有层的每个实体(及其后代)在GlobalTransform
上设置z坐标(而不是Transform
) - 在
First
调度中,它重新将它们的GlobalTransform
的z坐标重置为零。 - 在这两种情况下,它都会 跳过变更检测。
这是因为子应用都在您的应用程序的主 Main
调度之后运行。
这很丑陋,可能会以微妙的方式破坏事物,但它具有以下属性
- 精灵层可以继承
- 您的应用程序代码可以计算距离,而无需截断位移的z坐标(如果您不将z坐标重置为零,您就必须这样做)
动机
当在 bevy 中制作2D游戏时,z坐标实际上被用作层索引:z坐标较高的东西被渲染在z坐标较低的东西之上。这很有效,但也有一些问题
z坐标对于距离或归一化等事物并不相关。下面的代码有细微的错误
use bevy::prelude::*;
/// Get a unit vector pointing from the position of `source` to `target`, or
/// zero if they're close.
fn get_normal_direction(query: Query<&GlobalTransform>, source: Entity, target: Entity) -> Vec2 {
let from_pos = query.get(source).unwrap().translation();
let to_pos = query.get(target).unwrap().translation();
(from_pos - to_pos).normalize_or_zero().truncate()
}
错误在于我们在截断之前进行归一化,因此z坐标仍然“计算”长度。所以如果源在 (0, 0, 0)
和目标在 (0, 1, 100)
,那么我们将返回 (0, 0.001)
!
同一层的实体以任意顺序绘制,这个顺序可能会在帧之间改变。如果你的游戏允许同一层的实体相互重叠,这意味着实体会在前后“翻转”。这很令人分心。常见的解决方案是Y排序,即同一层的实体按其Y坐标排序,所以屏幕上较低的敌人会先绘制。以下是我正在制作的游戏tengoku的例子,这也促使我开发了这个库。在这两张图片中,所有敌人(蓝色“士兵”)都在同一层。在第一张中,敌人按出生顺序大致绘制,这使得堆叠看起来杂乱无章。第二张是Y排序,结果是一个看起来干净得多的堆叠。(中间的红色机器人代表玩家,在两种情况下都在较高的层。)
性能
如果启用了Y排序(默认设置),则此插件的时间复杂度为O(N log N)
,其中N
是具有精灵层的实体数量。在我的个人电脑(System76 Lemur Pro 10)上的基准测试中(10000个精灵),启用Y排序时,插件增加了大约600us的开销;禁用rayon
功能(或运行在单线程运行时)大致将此数值加倍。
如果未启用Y排序,则开销为O(N)
且并不足以担心。
已知问题
- 出于性能考虑,Y排序会一次性对所有实体进行排序。这意味着,如果某一层的z坐标与精灵数量的乘积大于2^23左右,可能会遇到浮点精度问题。
帮助
请随时在Bevy Discord服务器的任一频道中联系我;我是@Sera。
依赖项
~23MB
~421K SLoC