Static World Gen and Display for the Overworld #5

Merged
msrd0 merged 21 commits from overworld-house-gen into main 2024-07-06 20:23:25 +00:00
3 changed files with 218 additions and 19 deletions
Showing only changes of commit f3b8d44034 - Show all commits

View file

@ -75,14 +75,14 @@ impl AssetsWriter {
for asset_name in root.assets.keys() { for asset_name in root.assets.keys() {
writeln!( writeln!(
file, file,
"{indent}\t{}: comfy::TextureHandle,", "pub {indent}\t{}: comfy::TextureHandle,",
asset_name.to_snake_case() asset_name.to_snake_case()
)?; )?;
} }
for group_name in root.groups.keys() { for group_name in root.groups.keys() {
writeln!( writeln!(
file, file,
"{indent}\t{group_name}: &'static {group_name}::Assets," "pub {indent}\t{group_name}: &'static {group_name}::Assets,"
)?; )?;
} }
writeln!(file, "{indent}}}")?; writeln!(file, "{indent}}}")?;

View file

@ -7,7 +7,7 @@ pub mod worldgen;
pub fn draw(state: &crate::State, _engine: &comfy::EngineContext<'_>) { pub fn draw(state: &crate::State, _engine: &comfy::EngineContext<'_>) {
draw_circle(vec2(0.0, 0.0), 0.5, GREEN, 0); draw_circle(vec2(0.0, 0.0), 0.5, GREEN, 0);
for (coords, tile) in state.overworld.iter_tiles() { for (coords, tile) in state.overworld.iter_tiles() {
for (i, texture) in tile.textures.iter().rev().enumerate() { for (i, texture) in tile.textures().iter().rev().enumerate() {
let i = i as i32; let i = i as i32;
draw_sprite( draw_sprite(
*texture, *texture,

View file

@ -1,5 +1,5 @@
use crate::assets::ASSETS;
use comfy::{IVec2, TextureHandle, UVec2}; use comfy::{IVec2, TextureHandle, UVec2};
use std::collections::HashMap; use std::collections::HashMap;
pub enum MovementCost { pub enum MovementCost {
@ -13,12 +13,66 @@ pub enum MovementCost {
Obstacle Obstacle
} }
#[derive(Debug)] #[derive(Clone, Copy, Debug)]
pub struct Tile { pub enum Tile {
pub textures: Vec<TextureHandle> Grass,
Path {
left: bool,
right: bool,
top: bool,
bottom: bool
},
House {
texture: TextureHandle,
door: bool
}
} }
impl Tile { impl Tile {
pub fn textures(&self) -> Vec<TextureHandle> {
match self {
Self::Grass => vec![ASSETS.overworld.grass],
Self::Path {
left,
right,
top,
bottom
} => {
let path_texture = match (left, right, top, bottom) {
(true, true, false, false) => ASSETS.overworld.path_horiz,
(false, false, true, true) => ASSETS.overworld.path_vert,
(true, false, true, false) => ASSETS.overworld.path_top_left,
(true, false, false, true) => ASSETS.overworld.path_bottom_left,
(false, true, true, false) => ASSETS.overworld.path_top_right,
(false, true, false, true) => ASSETS.overworld.path_bottom_right,
(true, true, true, false) => ASSETS.overworld.path_top_left_right,
(true, true, false, true) => ASSETS.overworld.path_bottom_left_right,
(true, false, true, true) => ASSETS.overworld.path_top_left_bottom,
(false, true, true, true) => ASSETS.overworld.path_top_right_bottom,
(true, true, true, true) => ASSETS.overworld.path_crossing,
(true, false, false, false)
| (false, true, false, false)
| (false, false, true, false)
| (false, false, false, true) => panic!("We don't have no dead ends"),
(false, false, false, false) => panic!("I think you meant grass?!?")
};
vec![ASSETS.overworld.grass, path_texture]
},
Self::House { texture, .. } => {
vec![ASSETS.overworld.grass, *texture]
}
}
}
pub fn can_stand_inside(&self) -> bool { pub fn can_stand_inside(&self) -> bool {
unimplemented!() unimplemented!()
} }
@ -45,6 +99,7 @@ const CHUNK_SIZE: u32 = 100;
/// Chunks /// Chunks
#[derive(Debug)] #[derive(Debug)]
#[allow(dead_code)]
pub struct Chunk { pub struct Chunk {
/// All tiles within this chunk. /// All tiles within this chunk.
tiles: [Tile; (CHUNK_SIZE * CHUNK_SIZE) as usize], tiles: [Tile; (CHUNK_SIZE * CHUNK_SIZE) as usize],
@ -59,6 +114,137 @@ pub struct Chunk {
} }
impl Chunk { impl Chunk {
pub fn generate_chunk() -> Self {
// TODO real worldgen
// for the time being we just copy this pre-made house block into the chunk
fn path(left: bool, right: bool, top: bool, bottom: bool) -> Tile {
Tile::Path {
left,
right,
top,
bottom
}
}
fn house(texture: TextureHandle) -> Tile {
Tile::House {
texture,
door: false
}
}
let path_horiz = path(true, true, false, false);
let path_vert = path(false, false, true, true);
let path_crossing = path(true, true, true, true);
let grass = Tile::Grass;
let block = [
[
path_crossing,
path_horiz,
path_horiz,
path_horiz,
path_horiz,
path_horiz,
path_horiz,
path_horiz,
path_horiz,
path_horiz,
path_crossing
],
[
path_vert,
grass,
grass,
grass,
house(ASSETS.overworld.house_roof_top),
grass,
grass,
grass,
grass,
grass,
path_vert
],
[
path_vert,
grass,
grass,
house(ASSETS.overworld.house_roof_mid_left),
house(ASSETS.overworld.house_mid_window),
house(ASSETS.overworld.house_roof_mid_right),
grass,
grass,
grass,
grass,
path_vert
],
[
path_vert,
grass,
house(ASSETS.overworld.house_roof_left),
house(ASSETS.overworld.house_mid_window),
house(ASSETS.overworld.house_mid),
house(ASSETS.overworld.house_mid_window),
house(ASSETS.overworld.house_roof_right),
grass,
grass,
grass,
path_vert
],
[
path_vert,
grass,
house(ASSETS.overworld.house_bottom_left),
house(ASSETS.overworld.house_bottom_door),
house(ASSETS.overworld.house_bottom_window),
house(ASSETS.overworld.house_bottom_window),
house(ASSETS.overworld.house_bottom_right),
grass,
grass,
grass,
path_vert
],
[
path_vert,
grass,
grass,
path(false, true, true, false),
path_horiz,
path_horiz,
path_horiz,
path_horiz,
path_horiz,
path_horiz,
path(true, false, true, true)
],
[
path_vert, grass, grass, grass, grass, grass, grass, grass, grass, grass,
path_vert
],
[
path_vert, grass, grass, grass, grass, grass, grass, grass, grass, grass,
path_vert
]
];
// and then we copy this pre-made block into our chunk
let mut tiles = [Tile::Grass; (CHUNK_SIZE * CHUNK_SIZE) as usize];
for y in 0 .. CHUNK_SIZE {
for x in 0 .. CHUNK_SIZE {
let row = block[y as usize % block.len()];
tiles[(y * CHUNK_SIZE + x) as usize] = row[x as usize % row.len()];
}
}
Self {
tiles,
paths_left: vec![],
paths_right: vec![],
paths_bottom: vec![],
paths_top: vec![]
}
}
pub fn get_tile(&self, local_chunk_coords: UVec2) -> Option<&Tile> { pub fn get_tile(&self, local_chunk_coords: UVec2) -> Option<&Tile> {
self.tiles self.tiles
.get((local_chunk_coords.y * CHUNK_SIZE + local_chunk_coords.x) as usize) .get((local_chunk_coords.y * CHUNK_SIZE + local_chunk_coords.x) as usize)
@ -78,25 +264,38 @@ pub struct Overworld {
chunks: HashMap<IVec2, Chunk> chunks: HashMap<IVec2, Chunk>
} }
fn world_to_chunk_and_local_coords(world_coords: IVec2) -> (IVec2, UVec2) {
let chunk_coords = IVec2 {
x: world_coords.x.div_euclid(CHUNK_SIZE as _),
y: world_coords.y.div_euclid(CHUNK_SIZE as _)
};
let local_chunk_coords = UVec2 {
x: world_coords.x.rem_euclid(CHUNK_SIZE as _) as _,
y: world_coords.y.rem_euclid(CHUNK_SIZE as _) as _
};
(chunk_coords, local_chunk_coords)
}
impl Overworld { impl Overworld {
/// Return a [`Tile`] at the given world coordinates, or `None` if that tile has not /// Return a [`Tile`] at the given world coordinates, or `None` if that tile has not
/// been generated yet. /// been generated yet.
pub fn get_tile(&self, world_coords: IVec2) -> Option<&Tile> { pub fn get_tile(&self, world_coords: IVec2) -> Option<&Tile> {
let tile_coords = IVec2 { let (chunk_coords, local_chunk_coords) =
x: world_coords.x.div_euclid(CHUNK_SIZE as _), world_to_chunk_and_local_coords(world_coords);
y: world_coords.y.div_euclid(CHUNK_SIZE as _)
};
let local_coords = UVec2 {
x: world_coords.x.rem_euclid(CHUNK_SIZE as _) as _,
y: world_coords.y.rem_euclid(CHUNK_SIZE as _) as _
};
let chunk = self.chunks.get(&tile_coords)?; let chunk = self.chunks.get(&chunk_coords)?;
chunk.get_tile(local_coords) chunk.get_tile(local_chunk_coords)
} }
fn get_or_generate_tile(&self, world_coords: IVec2) -> &Tile { fn get_or_generate_tile(&mut self, world_coords: IVec2) -> &Tile {
unimplemented!() let (chunk_coords, local_chunk_coords) =
world_to_chunk_and_local_coords(world_coords);
let chunk = self
.chunks
.entry(chunk_coords)
.or_insert_with(Chunk::generate_chunk);
chunk.get_tile(local_chunk_coords).unwrap()
} }
/// iterate over all tiles and its global coords /// iterate over all tiles and its global coords