reorganize cells, add custom game time, switch click detection to 200ms
This commit is contained in:
parent
97eb82e009
commit
533cb2fae4
@ -1,9 +1,11 @@
|
|||||||
|
#![feature(duration_constructors)]
|
||||||
use bevy::{prelude::*, diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}};
|
use bevy::{prelude::*, diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}};
|
||||||
use bevy_inspector_egui::quick::WorldInspectorPlugin;
|
use bevy_inspector_egui::quick::WorldInspectorPlugin;
|
||||||
|
|
||||||
pub mod map;
|
pub mod map;
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
pub mod time;
|
||||||
|
|
||||||
#[bevy_main]
|
#[bevy_main]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
@ -14,6 +16,7 @@ pub fn main() {
|
|||||||
camera::Plugin,
|
camera::Plugin,
|
||||||
map::Plugin,
|
map::Plugin,
|
||||||
ui::Plugin,
|
ui::Plugin,
|
||||||
|
time::Plugin,
|
||||||
FrameTimeDiagnosticsPlugin,
|
FrameTimeDiagnosticsPlugin,
|
||||||
LogDiagnosticsPlugin {
|
LogDiagnosticsPlugin {
|
||||||
filter: Some(vec![FrameTimeDiagnosticsPlugin::FPS]),
|
filter: Some(vec![FrameTimeDiagnosticsPlugin::FPS]),
|
||||||
|
95
src/map.rs
95
src/map.rs
@ -10,14 +10,15 @@ mod picking;
|
|||||||
use picking::*;
|
use picking::*;
|
||||||
use cells::*;
|
use cells::*;
|
||||||
|
|
||||||
|
use crate::time::GameTime;
|
||||||
|
|
||||||
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(Startup, setup)
|
app.add_systems(Startup, setup)
|
||||||
.insert_resource(Time::<Fixed>::from_seconds(0.25)) // Time for a day
|
.insert_resource(Time::<Fixed>::from_seconds(0.25)) // Time for a day
|
||||||
.add_systems(FixedUpdate, update_cells)
|
|
||||||
.add_systems(PreUpdate, picking_backend.in_set(PickSet::Backend))
|
.add_systems(PreUpdate, picking_backend.in_set(PickSet::Backend))
|
||||||
.add_systems(Update, update_map_mesh)
|
.add_systems(Update, (update_map_mesh, cells_regeneration))
|
||||||
.insert_resource(ClearColor(Color::srgb(0., 0., 1.)))
|
.insert_resource(ClearColor(Color::srgb(0., 0., 1.)))
|
||||||
.insert_resource(Seed(thread_rng().gen()));
|
.insert_resource(Seed(thread_rng().gen()));
|
||||||
}
|
}
|
||||||
@ -65,7 +66,7 @@ fn setup(
|
|||||||
.set_lloyd_relaxation_iterations(3)
|
.set_lloyd_relaxation_iterations(3)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut cells_data = Vec::with_capacity(SIZE);
|
let mut cells = Vec::with_capacity(SIZE);
|
||||||
let z_noise = Fbm::<Perlin>::new(seed.0);
|
let z_noise = Fbm::<Perlin>::new(seed.0);
|
||||||
let moisture_noise = Fbm::<Perlin>::new(seed.0+1)
|
let moisture_noise = Fbm::<Perlin>::new(seed.0+1)
|
||||||
.set_frequency(2.);
|
.set_frequency(2.);
|
||||||
@ -89,27 +90,23 @@ fn setup(
|
|||||||
} else {
|
} else {
|
||||||
CellKind::Stone
|
CellKind::Stone
|
||||||
};
|
};
|
||||||
cells_data.push(CellData::new(k, i, (z*255.) as u8, (m*255.) as u8, 0, vec![]));
|
cells.push(Cell {
|
||||||
|
kind: k,
|
||||||
|
voronoi_id: i,
|
||||||
|
altitude: (z*255.) as u8,
|
||||||
|
vertices: vec![]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let mut poss = Vec::new();
|
let mut poss = Vec::new();
|
||||||
let mut colors = Vec::new();
|
|
||||||
let mut indices = Vec::new();
|
let mut indices = Vec::new();
|
||||||
|
|
||||||
for (c, cd) in voronoi.iter_cells().zip(cells_data.iter_mut()).filter(|(_,cd)| cd.kind != CellKind::Forest) {
|
for (c, cd) in voronoi.iter_cells().zip(cells.iter_mut()).filter(|(_,cd)| cd.kind != CellKind::Forest) {
|
||||||
let color = cd.color();
|
|
||||||
// if c.site() == selected_tile {
|
|
||||||
// color[0] = (color[0]+0.4).clamp(0., 1.);
|
|
||||||
// color[1] = (color[1]+0.4).clamp(0., 1.);
|
|
||||||
// color[2] = (color[2]+0.4).clamp(0., 1.);
|
|
||||||
// }
|
|
||||||
let vs = c.iter_vertices().collect::<Vec<_>>();
|
let vs = c.iter_vertices().collect::<Vec<_>>();
|
||||||
let i = poss.len();
|
let i = poss.len();
|
||||||
for v in vs.iter() {
|
for v in vs.iter() {
|
||||||
poss.push(Vec3::new(v.x as f32, v.y as f32, 0.));// [v.x as f32, v.y as f32, 0.]);
|
poss.push(Vec3::new(v.x as f32, v.y as f32, 0.));
|
||||||
// poss.push(Vertex::new_col([v.x as f32, v.y as f32], color, 1));
|
|
||||||
colors.push(color);
|
|
||||||
}
|
}
|
||||||
for v in 1..(vs.len()-1) {
|
for v in 1..(vs.len()-1) {
|
||||||
indices.extend_from_slice(&[i as u32, (i+v) as u32, (i+v+1) as u32]);
|
indices.extend_from_slice(&[i as u32, (i+v) as u32, (i+v+1) as u32]);
|
||||||
@ -117,6 +114,7 @@ fn setup(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let colors = vec![[0.; 4]; poss.len()];
|
||||||
let mesh = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default())
|
let mesh = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default())
|
||||||
// Add 4 vertices, each with its own position attribute (coordinate in
|
// Add 4 vertices, each with its own position attribute (coordinate in
|
||||||
// 3D space), for each of the corners of the parallelogram.
|
// 3D space), for each of the corners of the parallelogram.
|
||||||
@ -130,7 +128,7 @@ fn setup(
|
|||||||
)
|
)
|
||||||
.with_inserted_indices(Indices::U32(indices));
|
.with_inserted_indices(Indices::U32(indices));
|
||||||
|
|
||||||
let mut cells_entities = Vec::with_capacity(cells_data.len());
|
let mut cells_entities = Vec::with_capacity(cells.len());
|
||||||
cmds.spawn((
|
cmds.spawn((
|
||||||
Mesh2d(meshes.add(mesh)),
|
Mesh2d(meshes.add(mesh)),
|
||||||
MeshMaterial2d(materials.add(ColorMaterial::default())),
|
MeshMaterial2d(materials.add(ColorMaterial::default())),
|
||||||
@ -140,21 +138,40 @@ fn setup(
|
|||||||
MeshNeedsUpdate(true),
|
MeshNeedsUpdate(true),
|
||||||
MapMarker
|
MapMarker
|
||||||
)).with_children(|parent| {
|
)).with_children(|parent| {
|
||||||
for cd in cells_data {
|
for cell in cells {
|
||||||
let mut cmd = parent.spawn((cd, LastUpdate(0)));
|
let kind = cell.kind;
|
||||||
cmd.observe(|trigger: Trigger<Pointer<Click>>, mut cells: Query<&mut CellData>, mut map_needs_update: Query<&mut MeshNeedsUpdate, With<MapMarker>>| {
|
let mut cmd = parent.spawn(cell);
|
||||||
if trigger.duration > Duration::from_millis(100) {
|
match kind {
|
||||||
|
CellKind::Grass | CellKind::Forest => {
|
||||||
|
cmd.insert((Wealth(0), Regeneration {
|
||||||
|
last_update: Duration::ZERO,
|
||||||
|
full_growth_duration: kind.regen_full_growth_duration()
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
cmd.observe(|
|
||||||
|
trigger: Trigger<Pointer<Click>>,
|
||||||
|
mut cells: Query<&mut Cell>,
|
||||||
|
mut map_needs_update: Query<&mut MeshNeedsUpdate, With<MapMarker>>,
|
||||||
|
mut cmds: Commands,
|
||||||
|
gt: Res<GameTime>
|
||||||
|
| {
|
||||||
|
if trigger.duration > Duration::from_millis(200) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let mut cd = cells.get_mut(trigger.target).unwrap();
|
let mut cell = cells.get_mut(trigger.target).unwrap();
|
||||||
match cd.kind {
|
match cell.kind {
|
||||||
CellKind::Dirt | CellKind::Grass => {
|
CellKind::Dirt | CellKind::Grass => {
|
||||||
cd.kind = CellKind::Forest;
|
cmds.entity(trigger.target).insert((Wealth(0), Regeneration {
|
||||||
|
last_update: gt.current,
|
||||||
|
full_growth_duration: CellKind::Forest.regen_full_growth_duration()
|
||||||
|
}));
|
||||||
|
cell.kind = CellKind::Forest;
|
||||||
map_needs_update.single_mut().0 = true;
|
map_needs_update.single_mut().0 = true;
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
dbg!(trigger.duration);
|
|
||||||
});
|
});
|
||||||
cells_entities.push(cmd.id());
|
cells_entities.push(cmd.id());
|
||||||
}
|
}
|
||||||
@ -162,30 +179,8 @@ fn setup(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
pub struct LastUpdate(usize);
|
|
||||||
|
|
||||||
fn update_cells(
|
|
||||||
mut cells: Query<(&mut CellData, &mut LastUpdate)>,
|
|
||||||
mut map_needs_update: Query<&mut MeshNeedsUpdate, With<MapMarker>>
|
|
||||||
) {
|
|
||||||
let mut map_needs_update = map_needs_update.single_mut();
|
|
||||||
for (mut cd, mut lu) in cells.iter_mut() {
|
|
||||||
lu.0 += 1;
|
|
||||||
if lu.0 > match cd.kind {
|
|
||||||
CellKind::Void | CellKind::Sea | CellKind::Beach | CellKind::Dirt | CellKind::Stone => usize::MAX,
|
|
||||||
CellKind::Forest => 100*365/4, // Let's say that a forest takes 100 years to mature
|
|
||||||
CellKind::Grass => 7*7/4 // Let's say that grass takes 7 weaks to reach its max
|
|
||||||
} {
|
|
||||||
lu.0 = 0;
|
|
||||||
cd.resource = (cd.resource + 1).clamp(0, 4);
|
|
||||||
map_needs_update.0 = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_map_mesh(
|
fn update_map_mesh(
|
||||||
cells: Query<&CellData>,
|
cells: Query<(&Cell, Option<&Wealth>)>,
|
||||||
mut map: Query<(&Mesh2d, &mut MapColors, &mut MeshNeedsUpdate), With<MapMarker>>,
|
mut map: Query<(&Mesh2d, &mut MapColors, &mut MeshNeedsUpdate), With<MapMarker>>,
|
||||||
mut meshes: ResMut<Assets<Mesh>>
|
mut meshes: ResMut<Assets<Mesh>>
|
||||||
) {
|
) {
|
||||||
@ -193,9 +188,9 @@ fn update_map_mesh(
|
|||||||
if needs_update.0 {
|
if needs_update.0 {
|
||||||
if let Some(mesh) = meshes.get_mut(mesh) {
|
if let Some(mesh) = meshes.get_mut(mesh) {
|
||||||
let mut modified = false;
|
let mut modified = false;
|
||||||
for cd in cells.iter() {
|
for (cell, wealth) in cells.iter() {
|
||||||
let col = cd.color();
|
let col = cell.color(wealth.map(|w| w.0).unwrap_or_default());
|
||||||
for id in cd.vertices.iter() {
|
for id in cell.vertices.iter() {
|
||||||
modified = modified || cols.0[*id] != col;
|
modified = modified || cols.0[*id] != col;
|
||||||
cols.0[*id] = col.clone();
|
cols.0[*id] = col.clone();
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::time::GameTime;
|
||||||
|
|
||||||
|
use super::{MapMarker, MeshNeedsUpdate};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum CellKind {
|
pub enum CellKind {
|
||||||
Void,
|
|
||||||
Sea,
|
Sea,
|
||||||
Beach,
|
Beach,
|
||||||
Forest,
|
Forest,
|
||||||
@ -10,36 +15,72 @@ pub enum CellKind {
|
|||||||
Stone,
|
Stone,
|
||||||
Grass
|
Grass
|
||||||
}
|
}
|
||||||
|
impl CellKind {
|
||||||
|
pub fn regen_full_growth_duration(&self) -> Duration {
|
||||||
|
match self {
|
||||||
|
CellKind::Sea | CellKind::Beach | CellKind::Dirt | CellKind::Stone => unreachable!(),
|
||||||
|
CellKind::Forest => Duration::from_days(365*100), // Let's say that a forest takes 100 years to mature
|
||||||
|
CellKind::Grass => Duration::from_weeks(7) // Let's say that grass takes 7 weeks to reach its max
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Component)]
|
#[derive(Debug, Component)]
|
||||||
pub struct CellData {
|
pub struct Cell {
|
||||||
pub kind: CellKind,
|
pub kind: CellKind,
|
||||||
pub cid: usize,
|
pub voronoi_id: usize,
|
||||||
z: u8,
|
pub altitude: u8,
|
||||||
pub moisture: u8,
|
|
||||||
pub resource: u8, // How much resource there is (between 0 and 4)
|
|
||||||
pub vertices: Vec<usize>
|
pub vertices: Vec<usize>
|
||||||
}
|
}
|
||||||
impl CellData {
|
impl Cell {
|
||||||
pub fn new(kind: CellKind, cell: usize, z: u8, moisture: u8, resource: u8, vertices: Vec<usize>) -> Self {
|
// pub fn new(kind: CellKind, voronoi_id: usize, altitude: u8, moisture: u8, vertices: Vec<usize>) -> Self {
|
||||||
Self {
|
// Self {
|
||||||
kind,
|
// kind,
|
||||||
cid: cell,
|
// voronoi_id,
|
||||||
z,
|
// altitude,
|
||||||
moisture,
|
// moisture,
|
||||||
resource,
|
// vertices
|
||||||
vertices
|
// }
|
||||||
}
|
// }
|
||||||
}
|
pub fn color(&self, wealth: u8) -> [f32; 4] {
|
||||||
pub fn color(&self) -> [f32; 4] {
|
|
||||||
match self.kind {
|
match self.kind {
|
||||||
CellKind::Void => [0.; 4],
|
|
||||||
CellKind::Sea => [0., 0., 1., 1.],
|
CellKind::Sea => [0., 0., 1., 1.],
|
||||||
CellKind::Beach => [0.82, 0.84, 0.51, 1.],
|
CellKind::Beach => [0.82, 0.84, 0.51, 1.],
|
||||||
CellKind::Forest => [0., 0.5 - (self.resource as f32/4.*0.4), 0., 1.],
|
CellKind::Forest => [0., 0.5 - (wealth as f32/255.*0.4), 0., 1.],
|
||||||
CellKind::Dirt => [0.53 - (self.resource as f32/4.*0.4), 0.38-(self.resource as f32/4.*0.4), 0.29-(self.resource as f32/4.*0.4), 1.],
|
CellKind::Dirt => [0.53 - (wealth as f32/255.*0.4), 0.38-(wealth as f32/255.*0.4), 0.29-(wealth as f32/255.*0.4), 1.],
|
||||||
CellKind::Stone => [0.5, 0.5, 0.5, 1.],
|
CellKind::Stone => [0.5, 0.5, 0.5, 1.],
|
||||||
CellKind::Grass => [(136./255.) - (self.resource as f32/4.*0.4), (204./255.) - (self.resource as f32/4.*0.4), (59./255.) - (self.resource as f32/4.*0.4), 1.]
|
CellKind::Grass => [(136./255.) - (wealth as f32/255.*0.4), (204./255.) - (wealth as f32/255.*0.4), (59./255.) - (wealth as f32/255.*0.4), 1.]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct Wealth(pub u8);
|
||||||
|
|
||||||
|
impl Default for Wealth {
|
||||||
|
fn default() -> Self {
|
||||||
|
Wealth(u8::MAX)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
#[require(Wealth)]
|
||||||
|
pub struct Regeneration {
|
||||||
|
pub last_update: Duration,
|
||||||
|
pub full_growth_duration: Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cells_regeneration(
|
||||||
|
mut cells: Query<(&mut Regeneration, &mut Wealth)>,
|
||||||
|
mut map_needs_update: Query<&mut MeshNeedsUpdate, With<MapMarker>>,
|
||||||
|
gt: Res<GameTime>
|
||||||
|
) {
|
||||||
|
let mut map_needs_update = map_needs_update.single_mut();
|
||||||
|
for (mut regen, mut wealth) in cells.iter_mut() {
|
||||||
|
if gt.current - regen.last_update > regen.full_growth_duration/u8::MAX as u32 {
|
||||||
|
regen.last_update = gt.current;
|
||||||
|
wealth.0 = wealth.0.saturating_add(1);
|
||||||
|
map_needs_update.0 = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
28
src/time.rs
Normal file
28
src/time.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
pub struct Plugin;
|
||||||
|
impl bevy::prelude::Plugin for Plugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.insert_resource(GameTime {
|
||||||
|
current: Duration::ZERO,
|
||||||
|
speed: 24. * 60. * 60. * 365.
|
||||||
|
})
|
||||||
|
.add_systems(PreUpdate, update_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct GameTime {
|
||||||
|
pub current: Duration,
|
||||||
|
speed: f32 // = game time / real time
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_time(
|
||||||
|
mut gt: ResMut<GameTime>,
|
||||||
|
time: Res<Time>
|
||||||
|
) {
|
||||||
|
let speed = gt.speed;
|
||||||
|
gt.current += Duration::from_secs_f32(time.delta_secs() * speed);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user