From bbad89e1fbd82ec84af54537516f8a19c25951c8 Mon Sep 17 00:00:00 2001 From: hut Date: Mon, 1 Apr 2024 20:52:57 +0200 Subject: [PATCH 1/4] WIP despawning asteroids... for some reason, scenes can't despawn --- src/world.rs | 113 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 90 insertions(+), 23 deletions(-) diff --git a/src/world.rs b/src/world.rs index 722b1e4..9e9e203 100644 --- a/src/world.rs +++ b/src/world.rs @@ -1,4 +1,4 @@ -use crate::{actor, nature, settings}; +use crate::{actor, nature, settings, hud}; use bevy::prelude::*; use bevy::render::render_resource::{AsBindGroup, ShaderRef}; use bevy::math::DVec3; @@ -6,11 +6,12 @@ use bevy_xpbd_3d::prelude::*; use bevy_xpbd_3d::plugins::sync::SyncConfig; 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 STARS_MAX_MAGNITUDE: f32 = 5.5; const CENTER_WORLD_ON_PLAYER: bool = true; +const ASTEROIDS_ARE_SPHERES: bool = true; const ASSET_ASTEROID1: &str = "models/asteroid.glb#Scene0"; const ASSET_ASTEROID2: &str = "models/asteroid2.glb#Scene0"; @@ -59,13 +60,15 @@ impl Plugin for WorldPlugin { #[derive(Resource)] struct AsteroidUpdateTimer(Timer); #[derive(Resource)] struct AsteroidDatabase(Vec); +#[derive(Component)] struct Asteroid; + struct AsteroidData { + entity: Option, is_spawned: bool, + spawned_once: bool, class: u8, size: f32, - x: f64, - y: f64, - z: f64, + pos: DVec3, } #[derive(Asset, TypePath, AsBindGroup, Debug, Clone)] @@ -94,7 +97,6 @@ pub fn setup( mut meshes: ResMut>, mut materials: ResMut>, mut materials_custom: ResMut>, - asset_server: Res, ) { // Generate starmap let sphere_handle = meshes.add(Sphere::new(1.0)); @@ -177,10 +179,14 @@ fn generate_asteroids( let wobble: f64 = dist/2.0; let (i, j, k) = (i as f64, j as f64, k as f64); db.0.push(AsteroidData { + entity: None, is_spawned: false, - x: player_x + offset + dist * i + wobble * (j+k/pi).sin() * (k+j/pi).cos(), - y: player_y + offset + dist * j + wobble * (k+i/pi).sin() * (i+k/pi).cos(), - z: player_z + offset + dist * k + wobble * (i+j/pi).sin() * (j+i/pi).cos(), + spawned_once: false, + pos: DVec3::new( + 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, class: (((i+j+k) as i32) % 2) as u8, }); @@ -194,45 +200,102 @@ fn spawn_despawn_asteroids( mut timer: ResMut, mut db: ResMut, mut commands: Commands, + q_player: Query<&Position, With>, + mut meshes: ResMut>, + mut q_asteroid: Query<(Entity, &mut Visibility), With>, + mut materials: ResMut>, asset_server: Res, + mut log: ResMut, ) { - if !timer.0.tick(time.delta()).just_finished() { + if !timer.0.tick(time.delta()).just_finished() || q_player.is_empty() { return; } + let player = q_player.get_single().unwrap(); + let mut spawned = 0; + let mut despawned = 0; for asteroid in &mut db.0 { - if asteroid.is_spawned { + let dist = player.distance(asteroid.pos); + let should_spawn = dist < 10000.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; + commands.entity(entity).despawn(); + break; + } + } + } continue; } - asteroid.is_spawned = true; - let asset = match asteroid.class { - 0 => ASSET_ASTEROID1, - _ => ASSET_ASTEROID2, - }; - commands.spawn(( + + // Spawn + let mut entity_commands = commands.spawn(( actor::Actor::default(), RigidBody::Dynamic, AngularVelocity(DVec3::new(0.1, 0.1, 0.03)), LinearVelocity(DVec3::new(0.0, 0.0, 0.35)), 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().mesh().uv(128, 128)); + 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 { scale: Vec3::splat(asteroid.size), ..default() }, - scene: asset_server.load(asset), ..default() - }, - Rotation::from(Quat::from_rotation_y(-PI / 3.)), - Position::from_xyz(asteroid.x, asteroid.y, asteroid.z), - )); + }); + } + else { + let asset = match asteroid.class { + 0 => ASSET_ASTEROID1, + _ => ASSET_ASTEROID2, + }; + entity_commands.insert(SceneBundle { + scene: asset_server.load(asset), + transform: Transform { + scale: Vec3::splat(asteroid.size), + ..default() + }, + ..default() + }); + } + 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_cheats( + mut commands: Commands, key_input: Res>, mut q_player: Query<(&Transform, &mut Position, &mut LinearVelocity), With>, mut q_life: Query<(&mut actor::LifeForm, ), With>, + q_entities: Query, Without)>, settings: ResMut, ) { if !settings.dev_mode || q_player.is_empty() || q_life.is_empty() { @@ -259,6 +322,10 @@ fn handle_cheats( v.0 += DVec3::from(trans.rotation * Vec3::new(0.0, 0.0, -1000.0)); } 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; } if key_input.pressed(settings.key_cheat_adrenaline_mid) { From 3f89826acb2f03e6f8df91319fc6dd5ca7025d6a Mon Sep 17 00:00:00 2001 From: hut Date: Mon, 1 Apr 2024 21:07:28 +0200 Subject: [PATCH 2/4] tweak asteroid parameters --- src/world.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/world.rs b/src/world.rs index 9e9e203..869ab80 100644 --- a/src/world.rs +++ b/src/world.rs @@ -166,16 +166,17 @@ pub fn setup( fn generate_asteroids( mut db: ResMut, ) { - let maxdist = 4; + let maxdist = 30; + let maxdist_orthogonal = maxdist / 4; let pi = PI as f64; let player_x: f64 = -300000.0; let player_y: f64 = 0.0; let player_z: f64 = -500000.0; + let offset: f64 = 500.0; + let dist: f64 = 8e3; for i in -maxdist..maxdist { - for j in -maxdist..maxdist { + for j in -maxdist_orthogonal..maxdist_orthogonal { for k in -maxdist..maxdist { - let offset: f64 = 500.0; - let dist: f64 = 8e3; let wobble: f64 = dist/2.0; let (i, j, k) = (i as f64, j as f64, k as f64); db.0.push(AsteroidData { @@ -216,7 +217,7 @@ fn spawn_despawn_asteroids( let mut despawned = 0; for asteroid in &mut db.0 { let dist = player.distance(asteroid.pos); - let should_spawn = dist < 10000.0; + let should_spawn = dist < 50000.0; if should_spawn == asteroid.is_spawned { continue; // Nothing to do } @@ -249,7 +250,7 @@ fn spawn_despawn_asteroids( Asteroid, )); if ASTEROIDS_ARE_SPHERES { - let sphere_handle = meshes.add(Sphere::default().mesh().uv(128, 128)); + 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, From ca0b2d9b9611b86c953f2a7a2df726d9c239e291 Mon Sep 17 00:00:00 2001 From: hut Date: Mon, 1 Apr 2024 23:29:12 +0200 Subject: [PATCH 3/4] fix bevy_xpbd_3d version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3f39ec8..5056c06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ rust-version = "1.76.0" [dependencies] 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_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" [features] From cfbd23f485f39981b603e5b1dc0093be210c9365 Mon Sep 17 00:00:00 2001 From: hut Date: Mon, 1 Apr 2024 23:54:56 +0200 Subject: [PATCH 4/4] fix despawning of scene-based asteroids, turn them back from spheres to scenes --- src/world.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/world.rs b/src/world.rs index 869ab80..2d57c01 100644 --- a/src/world.rs +++ b/src/world.rs @@ -11,7 +11,7 @@ const ASTEROID_SIZE: f32 = 100.0; const STARS_MAX_MAGNITUDE: f32 = 5.5; const CENTER_WORLD_ON_PLAYER: bool = true; -const ASTEROIDS_ARE_SPHERES: bool = true; +const ASTEROIDS_ARE_SPHERES: bool = false; const ASSET_ASTEROID1: &str = "models/asteroid.glb#Scene0"; const ASSET_ASTEROID2: &str = "models/asteroid2.glb#Scene0"; @@ -36,6 +36,7 @@ impl Plugin for WorldPlugin { app.add_systems(Startup, setup); app.add_systems(Startup, generate_asteroids); app.add_systems(Update, handle_cheats); + app.add_systems(PostUpdate, handle_despawn); app.add_systems(Update, spawn_despawn_asteroids); app.add_plugins(PhysicsPlugins::default()); app.add_plugins(MaterialPlugin::::default()); @@ -44,6 +45,7 @@ impl Plugin for WorldPlugin { app.insert_resource(AsteroidUpdateTimer( Timer::from_seconds(ASTEROID_UPDATE_INTERVAL, TimerMode::Repeating))); app.insert_resource(AsteroidDatabase(Vec::new())); + app.add_event::(); if CENTER_WORLD_ON_PLAYER { // Disable bevy_xpbd's position->transform sync function @@ -71,6 +73,9 @@ struct AsteroidData { pos: DVec3, } +#[derive(Event)] +pub struct DespawnEvent(Entity); + #[derive(Asset, TypePath, AsBindGroup, Debug, Clone)] pub struct RingMaterial { alpha_mode: AlphaMode, @@ -207,6 +212,7 @@ fn spawn_despawn_asteroids( mut materials: ResMut>, asset_server: Res, mut log: ResMut, + mut ew_despawn: EventWriter, ) { if !timer.0.tick(time.delta()).just_finished() || q_player.is_empty() { return; @@ -230,7 +236,7 @@ fn spawn_despawn_asteroids( asteroid.entity = None; asteroid.is_spawned = false; despawned += 1; - commands.entity(entity).despawn(); + ew_despawn.send(DespawnEvent(entity)); break; } } @@ -291,6 +297,15 @@ fn spawn_despawn_asteroids( } } +fn handle_despawn( + mut commands: Commands, + mut er_despawn: EventReader, +) { + for despawn in er_despawn.read() { + commands.entity(despawn.0).despawn(); + } +} + fn handle_cheats( mut commands: Commands, key_input: Res>,