#bevy #trajectory #ryot #ray-casting #game-mechanics

nightly ryot_ray_casting

为Bevy实现光线投射功能,对交互式游戏机制(如视线、雾、复杂碰撞等)至关重要。

2个版本

0.2.3 2024年5月6日
0.2.2 2024年4月29日

#895 in 游戏开发


ryot_internal中使用

AGPL-3.0-only

120KB
2K SLoC

Ryot Ray Casting

License Crates.io Downloads Docs Discord

什么是Ryot Ray Casting?

Ryot Ray Casting利用光线投射的概念,为Bevy提供强大的光线投射系统。它设计用于与Bevy的ECS无缝协作,使开发者能够在其游戏和模拟中实现基于轨迹的高级机制,这些机制需要进行精确的直线轨迹计算,并支持障碍物、视线和其他复杂交互。尽管它针对2D网格环境进行了优化,但它可以轻松扩展以满足特定的游戏需求和开放世界场景。它是Ryot框架的一部分,依赖Ryot CoreRyot Utils

光线投射和轨迹

光线投射是游戏开发中的基本概念,它使复杂的游戏机制(如抛体运动、视线、战争迷雾、碰撞检测等)成为可能。光线投射是一种通过在二维或三维环境中追踪光线来模拟轨迹的技术,在追踪过程中检测碰撞和交互。它广泛应用于游戏,以实现逼真的物理、光照效果和AI行为,为创建引人入胜的游戏体验提供了一种灵活的工具。

在Ryot Ray Casting的上下文中,它为在Bevy项目中实现光线投射系统提供了一种全面的解决方案,提供了一个灵活且可扩展的框架来处理光线投射逻辑。通过利用ECS架构和与Bevy的无缝集成,开发者可以创建能够适应不断变化的游戏条件和玩家交互的动态光线投射系统。

Ryot RayCasting使用Bevy RayCast3d作为底层光线投射库,适用于2D和3D环境。

功能

  • 无缝Bevy集成:与Bevy的ECS紧密结合,提供流畅的集成并确保与Bevy的事件系统兼容。
  • 光线投射支持:利用光线投射来模拟轨迹,实现精确的碰撞检测和与障碍物的交互。
  • 二维优化:专门针对基于二维网格的导航,为基于瓦片和开放世界游戏环境提供强大的工具。
  • 可扩展架构:设计为灵活,允许开发者扩展和自定义射线投射逻辑,以适应特定的游戏需求。

基本设置

在设置射线投射框架之前,让我们了解核心概念:PointRayCastingPointNavigableRadialArea<P>Perspective<P>

Point

Point 特性表示世界中的位置。它是 Ryot 生态系统的一个核心概念,允许您将您自己的世界表示与 Ryot 及其空间算法集成。

RayCastingPoint

Point 特性的扩展,RayCastingPoint 特性表示世界中可以用于评估射线投射的位置。它用于生成空间中给定点的边界框,用于检查点是否与射线投射冲突。此软件包主要使用 aabb3d(轴对齐边界框)来表示空间中点的边界框,并使用射线投射 aabb 交集来检查点是否在射线内。

Navigable

Navigable 特性属于 ryot_core,用于确定点是否可导航。它用于确定一个角色是否可以通过世界中的特定点,例如,该点是否可步行。

目前,Navigable 有两个标志:is_walkableis_flyable。第一个用于确定一个角色是否可以通过一个点,第二个用于确定一个角色是否可以通过一个点飞行。

RadialArea

RadialArea 结构是对游戏世界中一个区域的描述性表示。它只包含原始的可复制类型,实现 Hash,其主要目的是用作 Perspectives 的描述性表示,允许缓存复杂的角度计算并未来重用。

Perspective

Perspective 结构是从给定观察者点的一个视角的表示。它包含一个遍历数组,这些是 RayCast3d 和射线遍历区域的元组。它用于表示在确定场景/条件下可以从观察者视角投射的所有射线。

Bevy

要集成 ryot_ray_casting,您需要在 Bevy 应用中添加射线投射。这是通过调用 add_ray_casting<T, P, N> 实现的,其中 T 是表示射线投射上下文的标记类型,P 是 RayCastingPoint 类型,而 N 是 Navigable 类型。此方法是 Bevy 应用构建器上的构建方法。

以下是一个基本示例

use bevy::prelude::*;
use ryot_core::prelude::*;
use ryot_ray_casting::prelude::*;

fn setup<P: RayCastingPoint + Component>(mut commands: Commands) {
    // here we use () as a marker, but in a real scenario you should use a marker type
    // that properly represents the context of the ray casting.
    commands.spawn(RayCasting::<(), P>::default());
}

fn build_app<P: RayCastingPoint + Component>(app: &mut App) -> &mut App {
    app
        .add_plugins(DefaultPlugins)
        .add_ray_casting::<(), P, Flags>()
}

组件

此软件包有两个主要的 ECS 组件

RayCasting<T, P>

此结构表示游戏世界中的射线投射。它是一个可以附加到 ECS 实体上的组件,用于表示实体给定的上下文 T 的射线投射请求。

此组件附加到需要射线投射计算的实体上。它指定射线投射评估的参数

  • 区域:表示将要投射射线的平面的径向区域。
  • 共享:射线传播将与之共享的实体。
  • 条件:基于可导航类型,平面点 P 必须满足的条件,以避免与投射的射线冲突。
  • 参数:一组可以用于自定义射线投射计算的参数。
    • max_collisions:光线投射在停止传播之前可以发生的最大碰撞次数。
    • reversed:如果光线应该以相反的顺序(从末端到起始点)进行分析。
    • execution_type:光线投射应该具有的执行类型:一次或基于时间的。
  • last_executed_at:光线投射上次执行的时间,一个标志,用于确定是否应该再次执行。

它是公共API的一部分,应由用户用于触发光线投射计算。

当此组件不再满足与其ExecutionType相关的执行要求时,它会自动删除。

RayPropagation<T, P>

此组件附加到已完成光线投射计算的实体上。它包含光线投射评估的结果,以及光线如何在给定的平面上传播,表示为

  • collisions:光线与请求的平面之间的碰撞,这意味着这些点不可导航。
    • position:碰撞发生的位置。
    • distance:光线起源到碰撞点的距离。
    • previous_position:碰撞发生之前光线接触的先前位置。
    • pierced:如果碰撞被穿透或未被穿透,这意味着光线传播在碰撞后继续。
  • area_of_interest:光线投射的兴趣区域,所有光线投射传播的点,这意味着光线影响这些点上的世界。

此组件附加到已完成光线投射计算的实体上。它是公共API的一部分,应由用户用于检查光线传播。

系统

光线投射框架由三个主要系统组成

  1. update_intersection_cache<T, P>:此系统更新由RayCasting<T, P>组件中存在的径向区域表示的交集缓存。此缓存用于加快光线投射计算,避免重新计算已经计算的光线投射aabb交集。
  2. process_ray_casting<T, P, N>:光线投射框架的主系统,它执行ECS中的光线投射请求,计算光线传播并将结果附加到实体上。
  3. share_results<T, P>:此系统将实体的光线传播结果与光线投射可以共享的实体共享。

还有两个系统是清理过程的一部分

  1. remove_stale_results<T, P>:此系统从不再具有RayCasting<T, P>组件的实体中删除RayPropagation<T, P>。
  2. remove_stale_requests<T, P>:此系统删除不再有效的RayCasting<T, P>请求。

示例

根据您的需求选择一个示例来运行,例如处理多个实体或处理障碍物。

cargo run --example example_name --features stubs

将example_name替换为您希望运行的示例的名称。

理解示例

库中包含的每个示例都展示了光线投射系统的不同方面。

  • 基本:演示了一个基本完整的光线投射用例,包括障碍物和不同的径向区域。
  • 压力测试:评估在高负载条件下光线投射的性能。

构建您自己的场景

利用ExampleBuilder来自定义和创建定制的光线投射示例/测试场景。

fn main() {
    // ExampleBuilder::<T /* Contextual Marker */, P /* RayCastingPoint */, N /* Navigable */>::new()
    // .with_ray_castings(/* array of (ray casting, count) tuples, containing the ray casting to be instantiated and how many */)
    //  .with_obstacles(/* number of obstacles to be instantiated */)
    //      .app() // basic app with visual capabilities
    //      /* add your custom systems, plugins and resources here */
    //      .run();
}

基准测试

性能基准测试被包含在内,以提供对crate效率的洞察。可以通过运行基准测试来评估在不同条件下的性能。

cargo bench --features stubs

结果

针对光线投射系统有三个主要基准测试:创建视角、执行光线投射和检查可导航点与光线传播的匹配。基准测试涵盖了不同的场景,如线性、扇形和圆形区域,以及不同的范围值。

以下表格提供了光线投射系统基准测试结果的概述

创建

测试名称 类型 范围(距离) 时间(ns/iter) 可变性(± ns) 每秒迭代次数(iters/s)
create_linear_range_10 线性 10 143 3 6,993,007
create_linear_range_100 线性 100 821 114 1,218,027
create_linear_range_255 线性 255 1,337 197 747,951
create_45_degrees_sector_range_10 径向_45 10 1,160 12 862,069
create_45_degrees_sector_range_100 径向_45 100 17,142 409 58,358
create_45_degrees_sector_range_255 径向_45 255 29,580 830 33,822
create_90_degrees_sector_range_10 径向_90 10 2,734 112 365,632
create_90_degrees_sector_range_100 径向_90 100 34,297 883 29,159
create_90_degrees_sector_range_255 径向_90 255 59,535 2,329 16,802
create_circular_range_3 圆形 3 1,871 28 534,759
create_circular_range_5 圆形 5 4,724 74 211,640
create_circular_range_10 圆形 10 9,819 292 101,844
create_circular_range_25 圆形 25 38,055 769 26,284
create_circular_range_50 圆形 50 81,998 2,237 12,195
create_circular_range_100 圆形 100 143,330 2,569 6,979
create_circular_range_255 圆形 255 277,505 40,670 3,605

执行

测试名称 类型 范围(距离) 时间(ns/iter) 可变性(± ns) 每秒迭代次数(iters/s)
execute_linear_range_10 线性 10 95 1 10,526,316
execute_linear_range_100 线性 100 1,169 32 855,048
execute_linear_range_255 线性 255 2,783 349 359,323
execute_45_degrees_sector_range_10 径向_45 10 602 6 1,660,798
execute_45_degrees_sector_range_100 径向_45 100 23,884 666 41,866
execute_45_degrees_sector_range_255 径向_45 255 60,248 897 16,600
execute_90_degrees_sector_range_10 径向_90 10 1,227 29 815,073
execute_90_degrees_sector_range_100 径向_90 100 47,821 972 20,914
execute_90_degrees_sector_range_255 径向_90 255 121,197 25,467 8,250
execute_circular_range_3 圆形 3 920 77 1,086,957
execute_circular_range_5 圆形 5 2,034 123 491,699
execute_circular_range_10 圆形 10 5,074 215 197,203
execute_circular_range_25 圆形 25 27,759 923 36,020
execute_circular_range_50 圆形 50 92,329 1,405 10,828
execute_circular_range_100 圆形 100 199,025 3,846 5,025
execute_circular_range_255 圆形 255 812,311 28,281 1,231

可导航碰撞

测试名称 类型 范围(距离) 时间(ns/iter) 可变性(± ns) 每秒迭代次数(iters/s)
check_1million_obstacles_against_line_range_15 线性 15 44 1 22,727,273
check_1million_obstacles_against_line_range_50 线性 50 267 8 3,745,318
check_1million_obstacles_against_line_range_100 线性 100 585 15 1,709,402
check_1million_obstacles_against_line_range_255 线性 255 1,699 38 588,581
check_1million_obstacles_against_45_degrees_sector_range_15 径向_45 15 612 21 1,633,987
check_1million_obstacles_against_45_degrees_sector_range_50 径向_45 50 6,660 1,812 150,150
check_1million_obstacles_against_45_degrees_sector_range_100 径向_45 100 17,077 612 58,545
check_1million_obstacles_against_45_degrees_sector_range_255 径向_45 255 53,496 8,487 18,692
check_1million_obstacles_against_90_degrees_sector_range_15 径向_90 15 1,339 117 746,808
check_1million_obstacles_against_90_degrees_sector_range_50 径向_90 50 13,385 405 74,706
check_1million_obstacles_against_90_degrees_sector_range_100 径向_90 100 40,414 1,383 24,742
check_1million_obstacles_against_90_degrees_sector_range_255 径向_90 255 108,612 4,525 9,209
check_1million_obstacles_against_circle_range_15 圆形 15 5,136 55 194,748
check_1million_obstacles_against_circle_range_50 圆形 50 67,538 2,029 14,810
check_1million_obstacles_against_circle_range_100 圆形 100 161,176 3,945 6,206
check_1million_obstacles_against_circle_range_255 圆形 255 437,340 10,785 2,287

这种README格式清晰地划分了功能、示例用法和基准测试,为希望将ryot_ray_castingcrate集成到他们项目中的任何人提供了一个全面的指南。

依赖项

~17–59MB
~1M SLoC