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",
"sfml",
"sfml-xt",
"worldgen",
]
[[package]]
@ -1159,3 +1160,9 @@ checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28"
dependencies = [
"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"
rfd = "0.11.3"
sfml = "0.20.0"
worldgen = "0.5.3"
[dependencies.s2dc]
git = "https://github.com/crumblingstatue/s2dc.git"

View file

@ -100,7 +100,7 @@ impl App {
.clamp(-terminal_velocity, terminal_velocity);
let mut on_screen_tile_ents = Vec::new();
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 {
return;
}
@ -163,11 +163,11 @@ impl App {
self.game.player.col_en.en.pos.y = wpos.y as i32;
}
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.fg = 0;
} 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 {
t.mid = self.game.tile_to_place;
} else {

View file

@ -9,6 +9,7 @@ use crate::{
math::{wp_to_tp, WorldPos},
res::Res,
world::{Tile, TileId, TilePos, World},
worldgen::Worldgen,
};
use self::player::Player;
@ -21,6 +22,7 @@ pub struct GameState {
pub tile_to_place: TileId,
pub current_biome: Biome,
pub prev_biome: Biome,
pub worldgen: Worldgen,
}
#[derive(PartialEq, Eq, Clone, Copy)]
@ -33,7 +35,7 @@ impl GameState {
pub(crate) fn draw_world(&mut self, rw: &mut RenderWindow, res: &Res) {
let mut s = Sprite::with_texture(&res.tile_atlas);
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());
if tile.bg != Tile::EMPTY {
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,
current_biome: Biome::Surface,
prev_biome: Biome::Surface,
worldgen: Worldgen::default(),
}
}
}

View file

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

View file

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