Merge branch 'despawn_asteroids'
This commit is contained in:
commit
ab14610ea4
|
@ -12,7 +12,7 @@ rust-version = "1.76.0"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
regex = "1"
|
regex = "1"
|
||||||
bevy = { version = "0.13.1", default-features = false, features = ["jpeg", "bevy_asset", "bevy_audio", "bevy_scene", "bevy_winit", "bevy_core_pipeline", "bevy_pbr", "bevy_gltf", "bevy_render", "bevy_text", "bevy_ui", "file_watcher", "multi-threaded", "png", "vorbis", "x11", "tonemapping_luts"]}
|
bevy = { version = "0.13.1", default-features = false, features = ["jpeg", "bevy_asset", "bevy_audio", "bevy_scene", "bevy_winit", "bevy_core_pipeline", "bevy_pbr", "bevy_gltf", "bevy_render", "bevy_text", "bevy_ui", "file_watcher", "multi-threaded", "png", "vorbis", "x11", "tonemapping_luts"]}
|
||||||
bevy_xpbd_3d = { version = "0.4", default-features = false, features = ["3d", "f64", "parry-f64", "parallel", "async-collider"] }
|
bevy_xpbd_3d = { version = "0.4.2", default-features = false, features = ["3d", "f64", "parry-f64", "parallel", "async-collider"] }
|
||||||
bevy_embedded_assets = "0.10.2"
|
bevy_embedded_assets = "0.10.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
133
src/world.rs
133
src/world.rs
|
@ -1,4 +1,4 @@
|
||||||
use crate::{actor, nature, settings};
|
use crate::{actor, nature, settings, hud};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::render::render_resource::{AsBindGroup, ShaderRef};
|
use bevy::render::render_resource::{AsBindGroup, ShaderRef};
|
||||||
use bevy::math::DVec3;
|
use bevy::math::DVec3;
|
||||||
|
@ -6,11 +6,12 @@ use bevy_xpbd_3d::prelude::*;
|
||||||
use bevy_xpbd_3d::plugins::sync::SyncConfig;
|
use bevy_xpbd_3d::plugins::sync::SyncConfig;
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
const ASTEROID_UPDATE_INTERVAL: f32 = 1.0; // seconds
|
const ASTEROID_UPDATE_INTERVAL: f32 = 0.1; // seconds
|
||||||
const ASTEROID_SIZE: f32 = 100.0;
|
const ASTEROID_SIZE: f32 = 100.0;
|
||||||
const STARS_MAX_MAGNITUDE: f32 = 5.5;
|
const STARS_MAX_MAGNITUDE: f32 = 5.5;
|
||||||
|
|
||||||
const CENTER_WORLD_ON_PLAYER: bool = true;
|
const CENTER_WORLD_ON_PLAYER: bool = true;
|
||||||
|
const ASTEROIDS_ARE_SPHERES: bool = false;
|
||||||
|
|
||||||
const ASSET_ASTEROID1: &str = "models/asteroid.glb#Scene0";
|
const ASSET_ASTEROID1: &str = "models/asteroid.glb#Scene0";
|
||||||
const ASSET_ASTEROID2: &str = "models/asteroid2.glb#Scene0";
|
const ASSET_ASTEROID2: &str = "models/asteroid2.glb#Scene0";
|
||||||
|
@ -35,6 +36,7 @@ impl Plugin for WorldPlugin {
|
||||||
app.add_systems(Startup, setup);
|
app.add_systems(Startup, setup);
|
||||||
app.add_systems(Startup, generate_asteroids);
|
app.add_systems(Startup, generate_asteroids);
|
||||||
app.add_systems(Update, handle_cheats);
|
app.add_systems(Update, handle_cheats);
|
||||||
|
app.add_systems(PostUpdate, handle_despawn);
|
||||||
app.add_systems(Update, spawn_despawn_asteroids);
|
app.add_systems(Update, spawn_despawn_asteroids);
|
||||||
app.add_plugins(PhysicsPlugins::default());
|
app.add_plugins(PhysicsPlugins::default());
|
||||||
app.add_plugins(MaterialPlugin::<RingMaterial>::default());
|
app.add_plugins(MaterialPlugin::<RingMaterial>::default());
|
||||||
|
@ -43,6 +45,7 @@ impl Plugin for WorldPlugin {
|
||||||
app.insert_resource(AsteroidUpdateTimer(
|
app.insert_resource(AsteroidUpdateTimer(
|
||||||
Timer::from_seconds(ASTEROID_UPDATE_INTERVAL, TimerMode::Repeating)));
|
Timer::from_seconds(ASTEROID_UPDATE_INTERVAL, TimerMode::Repeating)));
|
||||||
app.insert_resource(AsteroidDatabase(Vec::new()));
|
app.insert_resource(AsteroidDatabase(Vec::new()));
|
||||||
|
app.add_event::<DespawnEvent>();
|
||||||
|
|
||||||
if CENTER_WORLD_ON_PLAYER {
|
if CENTER_WORLD_ON_PLAYER {
|
||||||
// Disable bevy_xpbd's position->transform sync function
|
// Disable bevy_xpbd's position->transform sync function
|
||||||
|
@ -59,15 +62,20 @@ impl Plugin for WorldPlugin {
|
||||||
#[derive(Resource)] struct AsteroidUpdateTimer(Timer);
|
#[derive(Resource)] struct AsteroidUpdateTimer(Timer);
|
||||||
#[derive(Resource)] struct AsteroidDatabase(Vec<AsteroidData>);
|
#[derive(Resource)] struct AsteroidDatabase(Vec<AsteroidData>);
|
||||||
|
|
||||||
|
#[derive(Component)] struct Asteroid;
|
||||||
|
|
||||||
struct AsteroidData {
|
struct AsteroidData {
|
||||||
|
entity: Option<Entity>,
|
||||||
is_spawned: bool,
|
is_spawned: bool,
|
||||||
|
spawned_once: bool,
|
||||||
class: u8,
|
class: u8,
|
||||||
size: f32,
|
size: f32,
|
||||||
x: f64,
|
pos: DVec3,
|
||||||
y: f64,
|
|
||||||
z: f64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Event)]
|
||||||
|
pub struct DespawnEvent(Entity);
|
||||||
|
|
||||||
#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)]
|
#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)]
|
||||||
pub struct RingMaterial {
|
pub struct RingMaterial {
|
||||||
alpha_mode: AlphaMode,
|
alpha_mode: AlphaMode,
|
||||||
|
@ -94,7 +102,6 @@ pub fn setup(
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
mut materials_custom: ResMut<Assets<RingMaterial>>,
|
mut materials_custom: ResMut<Assets<RingMaterial>>,
|
||||||
asset_server: Res<AssetServer>,
|
|
||||||
) {
|
) {
|
||||||
// Generate starmap
|
// Generate starmap
|
||||||
let sphere_handle = meshes.add(Sphere::new(1.0));
|
let sphere_handle = meshes.add(Sphere::new(1.0));
|
||||||
|
@ -164,23 +171,28 @@ pub fn setup(
|
||||||
fn generate_asteroids(
|
fn generate_asteroids(
|
||||||
mut db: ResMut<AsteroidDatabase>,
|
mut db: ResMut<AsteroidDatabase>,
|
||||||
) {
|
) {
|
||||||
let maxdist = 4;
|
let maxdist = 30;
|
||||||
|
let maxdist_orthogonal = maxdist / 4;
|
||||||
let pi = PI as f64;
|
let pi = PI as f64;
|
||||||
let player_x: f64 = -300000.0;
|
let player_x: f64 = -300000.0;
|
||||||
let player_y: f64 = 0.0;
|
let player_y: f64 = 0.0;
|
||||||
let player_z: f64 = -500000.0;
|
let player_z: f64 = -500000.0;
|
||||||
for i in -maxdist..maxdist {
|
|
||||||
for j in -maxdist..maxdist {
|
|
||||||
for k in -maxdist..maxdist {
|
|
||||||
let offset: f64 = 500.0;
|
let offset: f64 = 500.0;
|
||||||
let dist: f64 = 8e3;
|
let dist: f64 = 8e3;
|
||||||
|
for i in -maxdist..maxdist {
|
||||||
|
for j in -maxdist_orthogonal..maxdist_orthogonal {
|
||||||
|
for k in -maxdist..maxdist {
|
||||||
let wobble: f64 = dist/2.0;
|
let wobble: f64 = dist/2.0;
|
||||||
let (i, j, k) = (i as f64, j as f64, k as f64);
|
let (i, j, k) = (i as f64, j as f64, k as f64);
|
||||||
db.0.push(AsteroidData {
|
db.0.push(AsteroidData {
|
||||||
|
entity: None,
|
||||||
is_spawned: false,
|
is_spawned: false,
|
||||||
x: player_x + offset + dist * i + wobble * (j+k/pi).sin() * (k+j/pi).cos(),
|
spawned_once: false,
|
||||||
y: player_y + offset + dist * j + wobble * (k+i/pi).sin() * (i+k/pi).cos(),
|
pos: DVec3::new(
|
||||||
z: player_z + offset + dist * k + wobble * (i+j/pi).sin() * (j+i/pi).cos(),
|
player_x + offset + dist * i + wobble * (j+k/pi).sin() * (k+j/pi).cos(),
|
||||||
|
player_y + offset + dist * j + wobble * (k+i/pi).sin() * (i+k/pi).cos(),
|
||||||
|
player_z + offset + dist * k + wobble * (i+j/pi).sin() * (j+i/pi).cos(),
|
||||||
|
),
|
||||||
size: ASTEROID_SIZE,
|
size: ASTEROID_SIZE,
|
||||||
class: (((i+j+k) as i32) % 2) as u8,
|
class: (((i+j+k) as i32) % 2) as u8,
|
||||||
});
|
});
|
||||||
|
@ -194,45 +206,112 @@ fn spawn_despawn_asteroids(
|
||||||
mut timer: ResMut<AsteroidUpdateTimer>,
|
mut timer: ResMut<AsteroidUpdateTimer>,
|
||||||
mut db: ResMut<AsteroidDatabase>,
|
mut db: ResMut<AsteroidDatabase>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
|
q_player: Query<&Position, With<actor::PlayerCamera>>,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut q_asteroid: Query<(Entity, &mut Visibility), With<Asteroid>>,
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
|
mut log: ResMut<hud::Log>,
|
||||||
|
mut ew_despawn: EventWriter<DespawnEvent>,
|
||||||
) {
|
) {
|
||||||
if !timer.0.tick(time.delta()).just_finished() {
|
if !timer.0.tick(time.delta()).just_finished() || q_player.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let player = q_player.get_single().unwrap();
|
||||||
|
|
||||||
|
let mut spawned = 0;
|
||||||
|
let mut despawned = 0;
|
||||||
for asteroid in &mut db.0 {
|
for asteroid in &mut db.0 {
|
||||||
if asteroid.is_spawned {
|
let dist = player.distance(asteroid.pos);
|
||||||
|
let should_spawn = dist < 50000.0;
|
||||||
|
if should_spawn == asteroid.is_spawned {
|
||||||
|
continue; // Nothing to do
|
||||||
|
}
|
||||||
|
if !should_spawn {
|
||||||
|
// Despawn
|
||||||
|
if let Some(entity) = asteroid.entity {
|
||||||
|
for (ent, mut vis) in &mut q_asteroid {
|
||||||
|
if ent == entity {
|
||||||
|
*vis = Visibility::Hidden;
|
||||||
|
asteroid.entity = None;
|
||||||
|
asteroid.is_spawned = false;
|
||||||
|
despawned += 1;
|
||||||
|
ew_despawn.send(DespawnEvent(entity));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
asteroid.is_spawned = true;
|
|
||||||
let asset = match asteroid.class {
|
// Spawn
|
||||||
0 => ASSET_ASTEROID1,
|
let mut entity_commands = commands.spawn((
|
||||||
_ => ASSET_ASTEROID2,
|
|
||||||
};
|
|
||||||
commands.spawn((
|
|
||||||
actor::Actor::default(),
|
actor::Actor::default(),
|
||||||
RigidBody::Dynamic,
|
RigidBody::Dynamic,
|
||||||
AngularVelocity(DVec3::new(0.1, 0.1, 0.03)),
|
AngularVelocity(DVec3::new(0.1, 0.1, 0.03)),
|
||||||
LinearVelocity(DVec3::new(0.0, 0.0, 0.35)),
|
LinearVelocity(DVec3::new(0.0, 0.0, 0.35)),
|
||||||
Collider::sphere(1.0),
|
Collider::sphere(1.0),
|
||||||
SceneBundle {
|
Rotation::from(Quat::from_rotation_y(-PI / 3.)),
|
||||||
|
Position::new(asteroid.pos),
|
||||||
|
Asteroid,
|
||||||
|
));
|
||||||
|
if ASTEROIDS_ARE_SPHERES {
|
||||||
|
let sphere_handle = meshes.add(Sphere::default());
|
||||||
|
let sphere_material_handle = materials.add(StandardMaterial {
|
||||||
|
base_color: Color::rgb(0.4, 0.4, 0.4),
|
||||||
|
perceptual_roughness: 1.0,
|
||||||
|
metallic: 0.0,
|
||||||
|
..default()
|
||||||
|
});
|
||||||
|
entity_commands.insert(PbrBundle {
|
||||||
|
mesh: sphere_handle,
|
||||||
|
material: sphere_material_handle,
|
||||||
transform: Transform {
|
transform: Transform {
|
||||||
scale: Vec3::splat(asteroid.size),
|
scale: Vec3::splat(asteroid.size),
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
|
..default()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let asset = match asteroid.class {
|
||||||
|
0 => ASSET_ASTEROID1,
|
||||||
|
_ => ASSET_ASTEROID2,
|
||||||
|
};
|
||||||
|
entity_commands.insert(SceneBundle {
|
||||||
scene: asset_server.load(asset),
|
scene: asset_server.load(asset),
|
||||||
|
transform: Transform {
|
||||||
|
scale: Vec3::splat(asteroid.size),
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
Rotation::from(Quat::from_rotation_y(-PI / 3.)),
|
..default()
|
||||||
Position::from_xyz(asteroid.x, asteroid.y, asteroid.z),
|
});
|
||||||
));
|
}
|
||||||
|
asteroid.entity = Some(entity_commands.id());
|
||||||
|
spawned += 1;
|
||||||
|
asteroid.spawned_once = true;
|
||||||
|
asteroid.is_spawned = true;
|
||||||
|
}
|
||||||
|
if spawned != 0 || despawned != 0 {
|
||||||
|
log.notice(format!("spawned: {spawned}, despawned: {despawned}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_despawn(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut er_despawn: EventReader<DespawnEvent>,
|
||||||
|
) {
|
||||||
|
for despawn in er_despawn.read() {
|
||||||
|
commands.entity(despawn.0).despawn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_cheats(
|
fn handle_cheats(
|
||||||
|
mut commands: Commands,
|
||||||
key_input: Res<ButtonInput<KeyCode>>,
|
key_input: Res<ButtonInput<KeyCode>>,
|
||||||
mut q_player: Query<(&Transform, &mut Position, &mut LinearVelocity), With<actor::PlayerCamera>>,
|
mut q_player: Query<(&Transform, &mut Position, &mut LinearVelocity), With<actor::PlayerCamera>>,
|
||||||
mut q_life: Query<(&mut actor::LifeForm, ), With<actor::Player>>,
|
mut q_life: Query<(&mut actor::LifeForm, ), With<actor::Player>>,
|
||||||
|
q_entities: Query<Entity, (With<actor::Actor>, Without<actor::Player>)>,
|
||||||
settings: ResMut<settings::Settings>,
|
settings: ResMut<settings::Settings>,
|
||||||
) {
|
) {
|
||||||
if !settings.dev_mode || q_player.is_empty() || q_life.is_empty() {
|
if !settings.dev_mode || q_player.is_empty() || q_life.is_empty() {
|
||||||
|
@ -259,6 +338,10 @@ fn handle_cheats(
|
||||||
v.0 += DVec3::from(trans.rotation * Vec3::new(0.0, 0.0, -1000.0));
|
v.0 += DVec3::from(trans.rotation * Vec3::new(0.0, 0.0, -1000.0));
|
||||||
}
|
}
|
||||||
if key_input.pressed(settings.key_cheat_adrenaline_zero) {
|
if key_input.pressed(settings.key_cheat_adrenaline_zero) {
|
||||||
|
// NOTE: temporarily added despawn all in here
|
||||||
|
for entity in &q_entities {
|
||||||
|
commands.entity(entity).despawn();
|
||||||
|
}
|
||||||
lifeform.adrenaline = 0.0;
|
lifeform.adrenaline = 0.0;
|
||||||
}
|
}
|
||||||
if key_input.pressed(settings.key_cheat_adrenaline_mid) {
|
if key_input.pressed(settings.key_cheat_adrenaline_mid) {
|
||||||
|
|
Loading…
Reference in a new issue