fix: randomised target positions
This commit is contained in:
parent
490fef5393
commit
eb67c2bf23
@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use avian3d::prelude::*;
|
use avian3d::prelude::*;
|
||||||
|
|
||||||
@ -20,35 +22,90 @@ impl Plugin for TargetWallPlugin
|
|||||||
{
|
{
|
||||||
fn build(&self, app: &mut App)
|
fn build(&self, app: &mut App)
|
||||||
{
|
{
|
||||||
|
app.insert_resource(TargetResources {
|
||||||
|
target_separation: 0.1,
|
||||||
|
target_handle_counter: 0,
|
||||||
|
targets: HashMap::new(),
|
||||||
|
});
|
||||||
|
|
||||||
app.add_systems(Startup, setup_target_wall);
|
app.add_systems(Startup, setup_target_wall);
|
||||||
app.add_systems(PostProcessCollisions, on_targets_shot.run_if(on_event::<CollisionEnded>));
|
app.add_systems(PostProcessCollisions, on_targets_shot.run_if(on_event::<CollisionEnded>));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
struct Target;
|
struct TargetHandle(i32); // todo: would be nice to use the Entity handle here
|
||||||
|
|
||||||
impl Target
|
#[derive(Resource)]
|
||||||
|
struct TargetResources
|
||||||
{
|
{
|
||||||
fn random_transform() -> Transform
|
target_separation: f32,
|
||||||
|
target_handle_counter: i32,
|
||||||
|
targets: HashMap<TargetHandle,(Vec2,Circle)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TargetResources
|
||||||
|
{
|
||||||
|
fn new_handle(&mut self) -> TargetHandle
|
||||||
|
{
|
||||||
|
self.target_handle_counter += 1;
|
||||||
|
TargetHandle(self.target_handle_counter)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_transform(&mut self, handle: &TargetHandle) -> Transform
|
||||||
|
{
|
||||||
|
self.targets.remove(&handle);
|
||||||
|
|
||||||
|
let (transform, cache_entry) = loop
|
||||||
{
|
{
|
||||||
let radius = rand::random::<f32>() * 0.4 + 0.3;
|
let radius = rand::random::<f32>() * 0.4 + 0.3;
|
||||||
let x = rand::random::<f32>() * (WALL_SIZE.x - radius) - WALL_SIZE.x * 0.5;
|
let x = rand::random::<f32>() * (WALL_SIZE.x - radius) - WALL_SIZE.x * 0.5;
|
||||||
let y = rand::random::<f32>() * (WALL_SIZE.y - radius);
|
let y = rand::random::<f32>() * (WALL_SIZE.y - radius) - WALL_SIZE.y * 0.5;
|
||||||
|
|
||||||
Transform::IDENTITY
|
let position = Vec2::new(x, y);
|
||||||
.with_translation(Vec3::new(x, y, WALL_FACE_Z + TARGET_HEIGHT * 0.5))
|
let circle = Circle::new(radius);
|
||||||
|
|
||||||
|
let has_overlap = self.targets.values().any(|&(position_other, circle_other)|
|
||||||
|
{
|
||||||
|
let distance_squared = Vec2::distance_squared(position, position_other);
|
||||||
|
let max_distance = circle.radius + circle_other.radius + self.target_separation;
|
||||||
|
distance_squared < max_distance * max_distance
|
||||||
|
});
|
||||||
|
|
||||||
|
if has_overlap {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let transform = Transform::IDENTITY
|
||||||
|
.with_translation(Vec3::new(x, y, TARGET_HEIGHT * 0.5))
|
||||||
.with_rotation(Quat::from_rotation_x(std::f32::consts::PI * 0.5))
|
.with_rotation(Quat::from_rotation_x(std::f32::consts::PI * 0.5))
|
||||||
.with_scale(Vec3::new(radius, 1.0, radius))
|
.with_scale(Vec3::new(radius, 1.0, radius))
|
||||||
|
;
|
||||||
|
|
||||||
|
break (transform, (position, circle));
|
||||||
|
};
|
||||||
|
|
||||||
|
self.targets.insert(*handle, cache_entry);
|
||||||
|
return transform;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct TargetWall;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct Target;
|
||||||
|
|
||||||
fn setup_target_wall(
|
fn setup_target_wall(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
mut target_resources: ResMut<TargetResources>,
|
||||||
) {
|
) {
|
||||||
commands.spawn((
|
// spawn the wall
|
||||||
|
//
|
||||||
|
let mut wall_commands = commands.spawn((
|
||||||
|
TargetWall,
|
||||||
Mesh3d(meshes.add(Cuboid::from_corners(
|
Mesh3d(meshes.add(Cuboid::from_corners(
|
||||||
Vec3::ZERO, WALL_SIZE
|
Vec3::ZERO, WALL_SIZE
|
||||||
))),
|
))),
|
||||||
@ -56,7 +113,7 @@ fn setup_target_wall(
|
|||||||
base_color: WALL_COLOR,
|
base_color: WALL_COLOR,
|
||||||
..default()
|
..default()
|
||||||
})),
|
})),
|
||||||
Transform::from_xyz(0.0, WALL_SIZE.y * 0.5, WALL_FACE_Z - WALL_SIZE.z * 0.5),
|
Transform::from_xyz(0.0, WALL_SIZE.y * 0.5, WALL_FACE_Z),
|
||||||
Collider::cuboid(WALL_SIZE.x, WALL_SIZE.y, WALL_SIZE.z * 0.5),
|
Collider::cuboid(WALL_SIZE.x, WALL_SIZE.y, WALL_SIZE.z * 0.5),
|
||||||
RigidBody::Static,
|
RigidBody::Static,
|
||||||
));
|
));
|
||||||
@ -73,35 +130,49 @@ fn setup_target_wall(
|
|||||||
TARGET_RADIUS, TARGET_HEIGHT
|
TARGET_RADIUS, TARGET_HEIGHT
|
||||||
);
|
);
|
||||||
|
|
||||||
let targets: Box<[_;TARGET_COUNT]> = Box::new(std::array::from_fn(|_| (
|
// spawn the targets as children of the wall
|
||||||
|
//
|
||||||
|
(0..TARGET_COUNT).for_each(|_|
|
||||||
|
{
|
||||||
|
let handle = target_resources.new_handle();
|
||||||
|
let transform = target_resources.random_transform(&handle);
|
||||||
|
|
||||||
|
wall_commands.with_child((
|
||||||
Target,
|
Target,
|
||||||
|
handle,
|
||||||
Mesh3d(target_mesh.clone()),
|
Mesh3d(target_mesh.clone()),
|
||||||
MeshMaterial3d(target_material.clone()),
|
MeshMaterial3d(target_material.clone()),
|
||||||
Target::random_transform(),
|
transform,
|
||||||
target_collider.clone(),
|
target_collider.clone(),
|
||||||
RigidBody::Static,
|
RigidBody::Static,
|
||||||
)));
|
));
|
||||||
commands.spawn_batch(targets.into_iter());
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_targets_shot(
|
fn on_targets_shot(
|
||||||
mut collision_events: EventReader<CollisionEnded>,
|
mut collision_events: EventReader<CollisionEnded>,
|
||||||
mut bullet_query: Query<Entity, With<Bullet>>,
|
mut query_set: ParamSet<(
|
||||||
mut target_query: Query<&mut Transform, With<Target>>,
|
Query<Entity, With<Bullet>>,
|
||||||
|
Query<(&TargetHandle, &mut Transform), With<Target>>,
|
||||||
|
)>,
|
||||||
|
mut target_resources: ResMut<TargetResources>,
|
||||||
) {
|
) {
|
||||||
for collision in collision_events.read()
|
for collision in collision_events.read()
|
||||||
{
|
{
|
||||||
// resolve the query data from the collision, if the collision is
|
// resolve the query data from the collision, if the collision is
|
||||||
// between a bullet and a target
|
// between a bullet and a target
|
||||||
//
|
//
|
||||||
let Ok(_) = collision.query_unique(&mut bullet_query) else {
|
let bullet_query = &mut query_set.p0();
|
||||||
continue;
|
let Ok(_) = collision.query_unique(bullet_query) else {
|
||||||
|
continue; // the collision doesn't involve a bullet
|
||||||
};
|
};
|
||||||
let Ok(mut target_transform) = collision.query_unique(&mut target_query) else {
|
//
|
||||||
continue;
|
let target_query = &mut query_set.p1();
|
||||||
|
let Ok((target_handle, mut target_transform)) = collision.query_unique(target_query) else {
|
||||||
|
continue; // the collision doesn't involve a target
|
||||||
};
|
};
|
||||||
|
|
||||||
// move the target
|
// move the target
|
||||||
*target_transform = Target::random_transform();
|
*target_transform = target_resources.random_transform(target_handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user