设置:带有群和鸟类的小行星克隆
我想用游戏引擎 Bevy 和物理引擎 Avian 在 Rust 中制作一个小行星克隆。我已经有了子弹和小行星的组件。它们生成时也会获得一个碰撞器。
use bevy::prelude::*;
use avian2d::prelude::*;
#[derive(Component)]
struct Bullet;
#[derive(Component)]
struct Asteroid
fn setup(
) {
asteroid_handle = asset_server.load("asteroid.png");
bullet_handle = asset_server.load("bullet.png");
commands.spawn(
(
Asteroid,
Sprite::from_image(asteroid_handle),
Collider::circle(50.),
)
);
commands.spawn(
(
Bullet,
Sprite::from_image(bullet_handle),
Collider::circle(5.),
)
);
}
(当然有一些代码,所以它们可以移动、转动等,但这与问题无关)
问题:寻找子弹和小行星之间的碰撞
实体之间的相互作用是我遇到困难的地方:我想检测小行星何时被子弹击中(这样我就可以让子弹消失并摧毁小行星,但我还不知道如何做)检测碰撞实际上非常容易,我只需监听碰撞事件即可。
fn print_collisions(mut collision_event_reader: EventReader<Collision>) {
for Collision(contacts) in collision_event_reader.read() {
println!(
"Entities {} and {} are colliding",
contacts.entity1,
contacts.entity2,
);
}
}
这确实按预期打印出了碰撞。但它包含了飞船与子弹、飞船与小行星之间的碰撞……这里我只得到了两个实体,没有更多信息。我该如何测试它们是否包含我想要的组件?
我想要的只是子弹和小行星之间的碰撞。
人工智能的建议
我询问了人工智能,它给出了如下建议:
fn print_collisions(
mut collision_event_reader: EventReader<Collision>,
query: Query<(Entity, Option<&Bullet>, Option<&Asteroid>)>,
) {
for Collision(contacts) in collision_event_reader.read() {
let (entity1, bullet1, asteroid1) = query.get(contacts.entity1).unwrap_or((contacts.entity1, None, None));
let (entity2, bullet2, asteroid2) = query.get(contacts.entity2).unwrap_or((contacts.entity2, None, None));
// Check if one entity is a Bullet and the other is an Asteroid
if (bullet1.is_some() && asteroid2.is_some()) || (bullet2.is_some() && asteroid1.is_some()) {
println!(
"Bullet {} collided with Asteroid {}",
if bullet1.is_some() { entity1 } else { entity2 },
if asteroid1.is_some() { entity1 } else { entity2 },
);
}
}
}
我想这应该可行,但在我看来效率很低。我们已经有了事件中的实体,应该没必要再查询所有子弹和小行星来确认它们是否在查询范围内。
我正在寻找:一个简单的解决方案
我是 Rust 和 Bevy 的初学者。我有一些编程经验(主要是 Python)以及其他游戏引擎(例如 Godot),而且到目前为止,我编写的所有 Bevy 代码看起来都很优雅且模块化。这真的让我印象深刻。所以我正在寻找一个简单而优雅的解决方案。