Add very crude proof-of-concept worldgen

This commit is contained in:
crumblingstatue 2023-04-05 15:09:19 +02:00
parent 314d2eafa0
commit 930f7aac47
7 changed files with 109 additions and 27 deletions

7
Cargo.lock generated
View file

@ -546,6 +546,7 @@ dependencies = [
"s2dc", "s2dc",
"sfml", "sfml",
"sfml-xt", "sfml-xt",
"worldgen",
] ]
[[package]] [[package]]
@ -1159,3 +1160,9 @@ checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "worldgen"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9b77fba24c873b60af296c1f0c5639114186d1ac3c99f880a7bb590bdc04065"

View file

@ -13,6 +13,7 @@ hecs = "0.10.1"
rand = "0.8.5" rand = "0.8.5"
rfd = "0.11.3" rfd = "0.11.3"
sfml = "0.20.0" sfml = "0.20.0"
worldgen = "0.5.3"
[dependencies.s2dc] [dependencies.s2dc]
git = "https://github.com/crumblingstatue/s2dc.git" git = "https://github.com/crumblingstatue/s2dc.git"

View file

@ -100,7 +100,7 @@ impl App {
.clamp(-terminal_velocity, terminal_velocity); .clamp(-terminal_velocity, terminal_velocity);
let mut on_screen_tile_ents = Vec::new(); let mut on_screen_tile_ents = Vec::new();
for_each_tile_on_screen(self.game.camera_offset, |tp, _sp| { for_each_tile_on_screen(self.game.camera_offset, |tp, _sp| {
let tid = self.game.world.tile_at_mut(tp).mid; let tid = self.game.world.tile_at_mut(tp, &self.game.worldgen).mid;
if tid == Tile::EMPTY { if tid == Tile::EMPTY {
return; return;
} }
@ -163,11 +163,11 @@ impl App {
self.game.player.col_en.en.pos.y = wpos.y as i32; self.game.player.col_en.en.pos.y = wpos.y as i32;
} }
if self.input.lmb_down { if self.input.lmb_down {
let t = self.game.world.tile_at_mut(mouse_tpos); let t = self.game.world.tile_at_mut(mouse_tpos, &self.game.worldgen);
t.mid = 0; t.mid = 0;
t.fg = 0; t.fg = 0;
} else if self.input.rmb_down { } else if self.input.rmb_down {
let t = self.game.world.tile_at_mut(mouse_tpos); let t = self.game.world.tile_at_mut(mouse_tpos, &self.game.worldgen);
if self.game.tile_to_place != 7 { if self.game.tile_to_place != 7 {
t.mid = self.game.tile_to_place; t.mid = self.game.tile_to_place;
} else { } else {

View file

@ -9,6 +9,7 @@ use crate::{
math::{wp_to_tp, WorldPos}, math::{wp_to_tp, WorldPos},
res::Res, res::Res,
world::{Tile, TileId, TilePos, World}, world::{Tile, TileId, TilePos, World},
worldgen::Worldgen,
}; };
use self::player::Player; use self::player::Player;
@ -21,6 +22,7 @@ pub struct GameState {
pub tile_to_place: TileId, pub tile_to_place: TileId,
pub current_biome: Biome, pub current_biome: Biome,
pub prev_biome: Biome, pub prev_biome: Biome,
pub worldgen: Worldgen,
} }
#[derive(PartialEq, Eq, Clone, Copy)] #[derive(PartialEq, Eq, Clone, Copy)]
@ -33,7 +35,7 @@ impl GameState {
pub(crate) fn draw_world(&mut self, rw: &mut RenderWindow, res: &Res) { pub(crate) fn draw_world(&mut self, rw: &mut RenderWindow, res: &Res) {
let mut s = Sprite::with_texture(&res.tile_atlas); let mut s = Sprite::with_texture(&res.tile_atlas);
for_each_tile_on_screen(self.camera_offset, |tp, sp| { for_each_tile_on_screen(self.camera_offset, |tp, sp| {
let tile = self.world.tile_at_mut(tp); let tile = self.world.tile_at_mut(tp, &self.worldgen);
s.set_position(sp.to_sf_vec()); s.set_position(sp.to_sf_vec());
if tile.bg != Tile::EMPTY { if tile.bg != Tile::EMPTY {
s.set_texture_rect(Rect::new((tile.bg - 1) as i32 * 32, 0, 32, 32)); s.set_texture_rect(Rect::new((tile.bg - 1) as i32 * 32, 0, 32, 32));
@ -97,6 +99,7 @@ impl Default for GameState {
tile_to_place: 1, tile_to_place: 1,
current_biome: Biome::Surface, current_biome: Biome::Surface,
prev_biome: Biome::Surface, prev_biome: Biome::Surface,
worldgen: Worldgen::default(),
} }
} }
} }

View file

@ -6,6 +6,7 @@ mod input;
mod math; mod math;
mod res; mod res;
mod world; mod world;
mod worldgen;
use app::App; use app::App;

View file

@ -1,12 +1,13 @@
use fnv::FnvHashMap; use fnv::FnvHashMap;
use rand::{thread_rng, Rng};
use crate::worldgen::Worldgen;
pub type ChunkPosScalar = u16; pub type ChunkPosScalar = u16;
#[derive(Hash, PartialEq, Eq, Debug, Clone, Copy)] #[derive(Hash, PartialEq, Eq, Debug, Clone, Copy)]
pub struct ChunkPos { pub struct ChunkPos {
x: ChunkPosScalar, pub x: ChunkPosScalar,
y: ChunkPosScalar, pub y: ChunkPosScalar,
} }
#[derive(Default)] #[derive(Default)]
@ -19,9 +20,12 @@ impl World {
/// Get mutable access to the tile at `pos`. /// Get mutable access to the tile at `pos`.
/// ///
/// Loads or generates the containing chunk if necessary. /// Loads or generates the containing chunk if necessary.
pub fn tile_at_mut(&mut self, pos: TilePos) -> &mut Tile { pub fn tile_at_mut(&mut self, pos: TilePos, worldgen: &Worldgen) -> &mut Tile {
let (chk, local) = pos.to_chunk_and_local(); let (chk, local) = pos.to_chunk_and_local();
let chk = self.chunks.entry(chk).or_insert_with(|| Chunk::gen(chk)); let chk = self
.chunks
.entry(chk)
.or_insert_with(|| Chunk::gen(chk, worldgen));
chk.at_mut(local) chk.at_mut(local)
} }
} }
@ -100,29 +104,19 @@ pub struct Chunk {
} }
impl Chunk { impl Chunk {
pub fn gen(pos: ChunkPos) -> Self { pub fn gen(pos: ChunkPos, worldgen: &Worldgen) -> Self {
let mut rng = thread_rng();
let mut tiles = [Tile { let mut tiles = [Tile {
bg: 0, bg: 0,
mid: 0, mid: 0,
fg: 0, fg: 0,
}; CHUNK_N_TILES]; }; CHUNK_N_TILES];
if pos.y == 156 { let noise = worldgen.chunk_noise(pos);
for (i, b) in tiles.iter_mut().enumerate() { if pos.y >= 156 {
if i / CHUNK_EXTENT as usize == 0 { for (i, t) in tiles.iter_mut().enumerate() {
b.fg = 8; let x = i % CHUNK_EXTENT as usize;
} let y = i / CHUNK_EXTENT as usize;
b.mid = 2; let noise = noise[x][y];
b.bg = 9; *t = noise;
}
}
if pos.y > 156 {
for b in &mut tiles {
b.bg = 7;
b.mid = 1;
if rng.gen_bool(0.1) {
b.fg = 6;
}
} }
} }
// Unbreakable layer at bottom // Unbreakable layer at bottom

76
src/worldgen.rs Normal file
View file

@ -0,0 +1,76 @@
use rand::{thread_rng, Rng};
use worldgen::{
constraint,
noise::perlin::PerlinNoise,
noisemap::{NoiseMap, NoiseMapGenerator, Seed, Step},
world::{
tile::{Constraint, ConstraintType},
Size, Tile, World,
},
};
use crate::world::{ChunkPos, Tile as Tl, CHUNK_EXTENT};
pub struct Worldgen {
world: World<crate::world::Tile>,
}
impl Default for Worldgen {
fn default() -> Self {
let noise = PerlinNoise::new();
let mut rng = thread_rng();
let nm1 = NoiseMap::new(noise)
.set(Seed::of(rng.gen::<i64>()))
.set(Step::of(0.005, 0.005));
let nm2 = NoiseMap::new(noise)
.set(Seed::of(rng.gen::<i64>()))
.set(Step::of(0.05, 0.05));
let nm = Box::new(nm1 + nm2 * 3);
let world = World::new()
.set(Size::of(CHUNK_EXTENT as i64, CHUNK_EXTENT as i64))
// Dirt coal
.add(
Tile::new(Tl {
bg: 9,
mid: 2,
fg: 6,
})
.when(constraint!(nm.clone(), < -0.8)),
)
// Dirt
.add(
Tile::new(Tl {
bg: 9,
mid: 2,
fg: 0,
})
.when(constraint!(nm.clone(), < -0.1)),
)
// Stone
.add(
Tile::new(Tl {
bg: 7,
mid: 1,
fg: 0,
})
.when(constraint!(nm.clone(), < 0.45)),
)
// Dirt wall
.add(Tile::new(Tl {
bg: 9,
mid: 0,
fg: 0,
}));
Self { world }
}
}
impl Worldgen {
pub fn chunk_noise(&self, pos: ChunkPos) -> Vec<Vec<Tl>> {
self.world.generate(pos.x as i64, pos.y as i64).unwrap()
}
}