This commit is contained in:
Arkitu 2025-06-27 16:14:55 +02:00
parent 6c74ed9272
commit b4ca8bb032
7 changed files with 51 additions and 68 deletions

View File

@ -1,4 +1,4 @@
use bevy::{prelude::*, render::camera::ScalingMode}; use bevy::prelude::*;
pub struct Plugin; pub struct Plugin;
impl bevy::prelude::Plugin for Plugin { impl bevy::prelude::Plugin for Plugin {
@ -10,7 +10,7 @@ impl bevy::prelude::Plugin for Plugin {
#[derive(Component)] #[derive(Component)]
pub struct CameraMarker; pub struct CameraMarker;
fn setup(mut cmds: Commands, window: Query<&Window>) { fn setup(mut cmds: Commands) {
cmds.spawn(( cmds.spawn((
CameraMarker, CameraMarker,
Camera3d { Camera3d {

View File

@ -1,14 +1,8 @@
use core::f32;
use std::time::Duration;
use bevy::{ use bevy::{
asset::RenderAssetUsages, asset::RenderAssetUsages,
pbr::MaterialExtension,
picking::PickSet, picking::PickSet,
prelude::*, prelude::*,
render::mesh::{Indices, PrimitiveTopology}, render::mesh::{Indices, PrimitiveTopology},
tasks::AsyncComputeTaskPool,
utils::HashMap,
}; };
use noise::{Fbm, MultiFractal, NoiseFn, Perlin}; use noise::{Fbm, MultiFractal, NoiseFn, Perlin};
use rand::{thread_rng, Rng, SeedableRng}; use rand::{thread_rng, Rng, SeedableRng};
@ -25,10 +19,7 @@ use cells::{
}; };
use picking::*; use picking::*;
use crate::{ use crate::{map::cells::grow::GrowThread, time::GameTime};
map::cells::grow::{grow_thread, GrowThread},
time::GameTime,
};
pub struct Plugin; pub struct Plugin;
impl bevy::prelude::Plugin for Plugin { impl bevy::prelude::Plugin for Plugin {
@ -238,7 +229,6 @@ fn setup(
)) ))
.with_children(|parent| { .with_children(|parent| {
for cell in ch_cells { for cell in ch_cells {
let kind = cell.kind;
// let id = cell.voronoi_id; // let id = cell.voronoi_id;
let mut cmd = parent.spawn(cell.clone()); let mut cmd = parent.spawn(cell.clone());
// if let Some(ch) = hybrid_cells.get(&id) { // if let Some(ch) = hybrid_cells.get(&id) {
@ -300,12 +290,12 @@ fn update_chunk_mesh(
/// Between 0 and 1 /// Between 0 and 1
fn get_altitude(z_noise: &Fbm<Perlin>, pos: &[f32; 2]) -> f32 { fn get_altitude(z_noise: &Fbm<Perlin>, pos: &[f32; 2]) -> f32 {
let z_noise = ((z_noise.get([pos[0] as f64, pos[1] as f64]) as f32) + 1.) / 2.; // Noise [0; 1] let z_noise = ((z_noise.get([pos[0] as f64, pos[1] as f64]) as f32) + 1.) / 2.; // Noise [0; 1]
(
-0.2// Arbitrary value -0.2// Arbitrary value
+ (z_noise.exp() / 1f32.exp()) + (z_noise.exp() / 1f32.exp())
// Noise + [0; 1] // Noise + [0; 1]
// - ((pos[0].powi(2)+pos[1].powi(2)).sqrt()*0.3) // - ((pos[0].powi(2)+pos[1].powi(2)).sqrt()*0.3)
// Distance - [0; sqrt(2)] * 0.5 // Distance - [0; sqrt(2)] * 0.5
)
// .clamp(-1., 1.) // .clamp(-1., 1.)
} }

View File

@ -1,14 +1,8 @@
use std::time::Duration; use bevy::prelude::*;
use bevy::{prelude::*, time::common_conditions::on_timer};
use rand::{seq::IteratorRandom, thread_rng, Rng};
use crate::{time::GameTime, ui::CurrentAction}; use crate::{time::GameTime, ui::CurrentAction};
use super::{ use super::{AnimalKind, CELLS_PER_CHUNK, CELL_AREA};
animals::Animal, AnimalKind, CellsEntities, MeshMarker, MeshNeedsUpdate, Voronoi,
AVERAGE_NEIGHBORS_NUMBER, CELLS_PER_CHUNK, CELL_AREA,
};
pub mod grow; pub mod grow;
pub mod input; pub mod input;
@ -25,7 +19,8 @@ impl bevy::prelude::Plugin for Plugin {
// expand.run_if(on_timer(Duration::from_millis(300))), // expand.run_if(on_timer(Duration::from_millis(300))),
// ), // ),
// ) // )
app.add_plugins(MaterialPlugin::<CellMaterial>::default()); app.add_plugins(MaterialPlugin::<CellMaterial>::default())
.add_plugins(grow::Plugin);
} }
} }
@ -44,7 +39,7 @@ impl CellKind {
pub const fn growth_duration(&self) -> u64 { pub const fn growth_duration(&self) -> u64 {
match self { match self {
CellKind::Forest { .. } => 100 * 365 * 24 * 60 * 60, // a forest takes 100 years to mature CellKind::Forest { .. } => 100 * 365 * 24 * 60 * 60, // a forest takes 100 years to mature
CellKind::Grass { .. } => (7 * 7 * 24 * 60 * 60), // grass takes 7 weeks to reach its max CellKind::Grass { .. } => 7 * 7 * 24 * 60 * 60, // grass takes 7 weeks to reach its max
_ => unreachable!(), _ => unreachable!(),
} }
} }

View File

@ -2,21 +2,22 @@ use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc; use std::sync::Arc;
use bevy::prelude::*; use bevy::prelude::*;
use bevy::tasks::futures_lite::{future, FutureExt}; use bevy::tasks::{AsyncComputeTaskPool, Task};
use bevy::tasks::{block_on, AsyncComputeTaskPool, IoTaskPool, Task};
use rand::rngs::SmallRng; use rand::rngs::SmallRng;
use rand::seq::IteratorRandom; use rand::seq::IteratorRandom;
use rand::Rng; use rand::Rng;
use voronoice::Voronoi; use voronoice::Voronoi;
use crate::map::cells::{wealth_to_unit, WealthType}; use crate::map::cells::{wealth_to_unit, WealthType};
use crate::map::{CellKind, CellsEntities, Chunk, MeshNeedsUpdate}; use crate::map::{CellKind, CellsEntities, MeshNeedsUpdate};
use super::Cell; use super::Cell;
pub struct Plugin; pub struct Plugin;
impl bevy::prelude::Plugin for Plugin { impl bevy::prelude::Plugin for Plugin {
fn build(&self, app: &mut App) {} fn build(&self, app: &mut App) {
app.add_systems(Update, rx_chunks_updates);
}
} }
// Background task that manages terrain // Background task that manages terrain
@ -27,7 +28,7 @@ pub struct GrowThread(
pub async_channel::Receiver<Cell>, pub async_channel::Receiver<Cell>,
); );
impl GrowThread { impl GrowThread {
pub fn new(voronoi: Voronoi, gt: Arc<AtomicU64>, cells: Vec<Cell>, mut rng: SmallRng) -> Self { pub fn new(voronoi: Voronoi, gt: Arc<AtomicU64>, cells: Vec<Cell>, rng: SmallRng) -> Self {
let task_pool = AsyncComputeTaskPool::get(); let task_pool = AsyncComputeTaskPool::get();
let (tx_control, rx_control) = async_channel::unbounded(); let (tx_control, rx_control) = async_channel::unbounded();
let (tx_update, rx_update) = async_channel::unbounded(); let (tx_update, rx_update) = async_channel::unbounded();
@ -39,13 +40,11 @@ impl GrowThread {
} }
} }
#[derive(Component)] // #[derive(Component)]
struct GetChunkTask(Task<Vec<Cell>>); // struct GetChunkTask(Task<Vec<Cell>>);
fn start_grow_task(mut cmds: Commands) {}
fn rx_chunks_updates( fn rx_chunks_updates(
mut chunks: Query<(&mut MeshNeedsUpdate)>, mut chunks: Query<&mut MeshNeedsUpdate>,
mut cells: Query<(&mut Cell, &Parent)>, mut cells: Query<(&mut Cell, &Parent)>,
cells_entities: Res<CellsEntities>, cells_entities: Res<CellsEntities>,
grow_thread: Res<GrowThread>, grow_thread: Res<GrowThread>,
@ -54,7 +53,7 @@ fn rx_chunks_updates(
let id = c.voronoi_id; let id = c.voronoi_id;
let (mut cell, parent) = cells.get_mut(cells_entities.0[id]).unwrap(); let (mut cell, parent) = cells.get_mut(cells_entities.0[id]).unwrap();
*cell = c; *cell = c;
chunks.get(parent.get()).unwrap().0 = true; chunks.get_mut(parent.get()).unwrap().0 = true;
} }
} }
@ -63,10 +62,10 @@ const FOREST_EXTEND_STEP: u64 = CellKind::FOREST.growth_duration();
pub async fn grow_thread( pub async fn grow_thread(
voronoi: Voronoi, voronoi: Voronoi,
gt: Arc<AtomicU64>, gt: Arc<AtomicU64>,
mut cells: Vec<Cell>, cells: Vec<Cell>,
mut rng: SmallRng, mut rng: SmallRng,
mut rx_control: async_channel::Receiver<Cell>, rx_control: async_channel::Receiver<Cell>,
mut tx_update: async_channel::Sender<Cell>, tx_update: async_channel::Sender<Cell>,
) { ) {
// Add "modified" flag // Add "modified" flag
let mut cells: Vec<(Cell, bool)> = cells.into_iter().map(|c| (c, false)).collect(); let mut cells: Vec<(Cell, bool)> = cells.into_iter().map(|c| (c, false)).collect();
@ -84,19 +83,19 @@ pub async fn grow_thread(
let gt = gt.load(Ordering::Acquire); let gt = gt.load(Ordering::Acquire);
// Update step // Update step
let grass_grow = ((gt - last_grass_grow) / CellKind::GRASS.growth_duration()) as usize; let grass_grow = (gt - last_grass_grow) / CellKind::GRASS.growth_duration();
let forest_grow = ((gt - last_forest_grow) / CellKind::FOREST.growth_duration()) as usize; let forest_grow = (gt - last_forest_grow) / CellKind::FOREST.growth_duration();
if grass_grow > 0 || forest_grow > 0 { if grass_grow > 0 || forest_grow > 0 {
for (c, modified) in cells.iter_mut() { for (c, modified) in cells.iter_mut() {
if grass_grow > 0 { if grass_grow > 0 {
if let CellKind::Grass { mut wealth } = c.kind { if let CellKind::Grass { ref mut wealth } = c.kind {
wealth = wealth.saturating_add(grass_grow as WealthType); *wealth = wealth.saturating_add(grass_grow as WealthType);
*modified = true; *modified = true;
} }
} }
if forest_grow > 0 { if forest_grow > 0 {
if let CellKind::Forest { mut wealth } = c.kind { if let CellKind::Forest { ref mut wealth } = c.kind {
wealth = wealth.saturating_add(forest_grow as WealthType); *wealth = wealth.saturating_add(forest_grow as WealthType);
*modified = true; *modified = true;
} }
} }
@ -107,11 +106,11 @@ pub async fn grow_thread(
if !cells[i].1 { if !cells[i].1 {
if let Some(wealth) = cells[i].0.kind.grass_wealth() { if let Some(wealth) = cells[i].0.kind.grass_wealth() {
if rng.gen_bool(wealth_to_unit(wealth) as f64) { if rng.gen_bool(wealth_to_unit(wealth) as f64) {
let mut target = &mut cells let target = &mut cells
[voronoi.cell(i).iter_neighbors().choose(&mut rng).unwrap()]; [voronoi.cell(i).iter_neighbors().choose(&mut rng).unwrap()];
if matches!(target.0.kind, CellKind::Dirt) { if matches!(target.0.kind, CellKind::Dirt) {
target.0.kind == CellKind::Grass { wealth: 0 }; target.0.kind = CellKind::Grass { wealth: 0 };
target.1 = true; target.1 = true;
} }
} }
@ -123,21 +122,20 @@ pub async fn grow_thread(
if !cells[i].1 { if !cells[i].1 {
if let CellKind::Forest { wealth } = cells[i].0.kind { if let CellKind::Forest { wealth } = cells[i].0.kind {
if rng.gen_bool(wealth_to_unit(wealth) as f64) { if rng.gen_bool(wealth_to_unit(wealth) as f64) {
let mut target = &mut cells let target = &mut cells
[voronoi.cell(i).iter_neighbors().choose(&mut rng).unwrap()]; [voronoi.cell(i).iter_neighbors().choose(&mut rng).unwrap()];
match target.0.kind { match target.0.kind {
CellKind::Dirt => { CellKind::Dirt => {
target.0.kind == CellKind::Forest { wealth: 0 }; target.0.kind = CellKind::Forest { wealth: 0 };
target.1 = true; target.1 = true;
} }
CellKind::Grass { wealth: w } => { CellKind::Grass { wealth: w } => {
target.0.kind target.0.kind = CellKind::Forest {
== CellKind::Forest { wealth: (w as f32
wealth: (w as f32 * CellKind::GRASS.growth_duration() as f32
* CellKind::GRASS.growth_duration() as f32 / CellKind::FOREST.growth_duration() as f32)
/ CellKind::FOREST.growth_duration() as f32) as WealthType,
as WealthType, };
};
target.1 = true; target.1 = true;
} }
_ => {} _ => {}
@ -148,9 +146,14 @@ pub async fn grow_thread(
} }
} }
last_grass_grow += grass_grow * CellKind::GRASS.growth_duration();
last_forest_grow += forest_grow * CellKind::FOREST.growth_duration();
last_grass_extend += GRASS_EXTEND_STEP;
last_forest_extend += FOREST_EXTEND_STEP;
// Send modifications // Send modifications
for (c, _) in cells.iter().filter(|(_, m)| *m) { for (c, _) in cells.iter().filter(|(_, m)| *m) {
tx_update.send(c.clone()).await; tx_update.send(c.clone()).await.unwrap();
} }
} }
} }

View File

@ -4,7 +4,6 @@ use bevy::prelude::*;
use crate::{ use crate::{
map::{animals::Animal, MeshMarker, MeshNeedsUpdate, Voronoi}, map::{animals::Animal, MeshMarker, MeshNeedsUpdate, Voronoi},
time::GameTime,
ui::CurrentAction, ui::CurrentAction,
}; };
@ -17,7 +16,6 @@ pub fn on_click(
mut chunks: Query<&mut MeshNeedsUpdate, With<MeshMarker>>, mut chunks: Query<&mut MeshNeedsUpdate, With<MeshMarker>>,
mut cmds: Commands, mut cmds: Commands,
ca: Res<CurrentAction>, ca: Res<CurrentAction>,
gt: Res<GameTime>,
) { ) {
if trigger.duration > Duration::from_millis(200) { if trigger.duration > Duration::from_millis(200) {
return; return;

View File

@ -8,7 +8,7 @@ use bevy::{
}; };
use voronoice::Point; use voronoice::Point;
use super::{CellsEntities, MeshMarker, Voronoi}; use super::{CellsEntities, Voronoi};
use crate::camera::CameraMarker; use crate::camera::CameraMarker;
pub fn picking_backend( pub fn picking_backend(

View File

@ -5,7 +5,6 @@ use bevy::{
picking::{focus::HoverMap, pointer::PointerId}, picking::{focus::HoverMap, pointer::PointerId},
prelude::*, prelude::*,
utils::HashMap, utils::HashMap,
window::PrimaryWindow,
}; };
use mevy::*; use mevy::*;
@ -190,7 +189,6 @@ fn zoom_with_scroll(
mut cam: Query<&mut Transform, With<CameraMarker>>, mut cam: Query<&mut Transform, With<CameraMarker>>,
mut ev_scroll: EventReader<MouseWheel>, mut ev_scroll: EventReader<MouseWheel>,
hover_map: Res<HoverMap>, hover_map: Res<HoverMap>,
window: Query<&Window, With<PrimaryWindow>>,
map_ui_id: Query<Entity, With<MapUIComponent>>, map_ui_id: Query<Entity, With<MapUIComponent>>,
) { ) {
let map_ui_id = map_ui_id.single(); let map_ui_id = map_ui_id.single();
@ -199,7 +197,6 @@ fn zoom_with_scroll(
.and_then(|hovered_ids| hovered_ids.get(&map_ui_id)) .and_then(|hovered_ids| hovered_ids.get(&map_ui_id))
.is_some() .is_some()
{ {
let window = window.single();
let mut cam = cam.single_mut(); let mut cam = cam.single_mut();
for ev in ev_scroll.read() { for ev in ev_scroll.read() {
let forward = cam.forward(); let forward = cam.forward();