more world gen

This commit is contained in:
Niko Abeler 2022-12-31 08:54:18 +01:00
parent f64a757ec6
commit 99f61fbd70
11 changed files with 238 additions and 46 deletions

19
src/events/found_town.rs Normal file
View File

@ -0,0 +1,19 @@
use std::rc::Rc;
use crate::{state::Effect, world::{Town, Structure}, state::GameState};
pub struct FoundTown{
pub x: usize,
pub y: usize,
pub town: Rc<Town>,
}
impl Effect for FoundTown {
fn apply(&self, state: &mut GameState) {
state.world.add_structure(self.x, self.y, Structure::Town(self.town.clone()));
}
fn description(&self) -> String {
format!("{} was founded", self.town.name)
}
}

5
src/events/mod.rs Normal file
View File

@ -0,0 +1,5 @@
mod found_town;
mod world_genesis;
pub use found_town::FoundTown;
pub use world_genesis::WorldGenesis;

View File

@ -0,0 +1,13 @@
use crate::state::{GameState, Effect};
pub struct WorldGenesis;
impl Effect for WorldGenesis {
fn apply(&self, _state: &mut GameState) {
return;
}
fn description(&self) -> String {
"World was created".to_string()
}
}

18
src/generators.rs Normal file
View File

@ -0,0 +1,18 @@
use rand::seq::SliceRandom;
pub struct TownNameGenerator {
}
impl TownNameGenerator {
pub fn name() -> String {
let first = include_str!("names/towns/first.txt").split("\n").collect::<Vec<&str>>();
let second = include_str!("names/towns/second.txt").split("\n").collect::<Vec<&str>>();
let mut rng = rand::thread_rng();
let first = first.choose(&mut rng).unwrap();
let second = second.choose(&mut rng).unwrap();
let name = format!("{}{}", first, second);
// capitalize first letter
name[0..1].to_uppercase() + &name[1..]
}
}

View File

@ -1,10 +1,18 @@
mod world;
mod state;
mod events;
mod time;
mod generators;
use noise::{Perlin, ScalePoint, Add, NoiseFn, Multiply, ScaleBias};
use noise::{Perlin, ScalePoint, Add, NoiseFn, ScaleBias};
use noise::utils::{NoiseMapBuilder, PlaneMapBuilder};
use image::{RgbImage, Rgb};
use rand::prelude::*;
use world::World;
const N_TOWNS: usize = 10;
const WORLD_SIZE: usize = 256;
struct BorderNoise {
pub center: [f64; 2],
@ -36,14 +44,10 @@ impl NoiseFn<f64, 2> for BorderNoise {
}
}
fn main() {
let N_TOWNS = 10;
fn build_world() -> World {
let mut rng = rand::thread_rng();
let map_size = 256;
let map_center = map_size / 2;
let map_center = WORLD_SIZE / 2;
let height = Add::new(
ScaleBias::new(
Add::new(
@ -57,30 +61,23 @@ fn main() {
).set_scale(2000.0).set_bias(1000.0),
BorderNoise::new(
[map_center as f64, map_center as f64],
map_size as f64 * 0.4,
WORLD_SIZE as f64 * 0.4,
100.0
),
);
let plane = PlaneMapBuilder::<_, 2>::new(&height)
.set_size(map_size, map_size)
.set_x_bounds(0.0, map_size as f64)
.set_y_bounds(0.0, map_size as f64)
.set_size(WORLD_SIZE, WORLD_SIZE)
.set_x_bounds(0.0, WORLD_SIZE as f64)
.set_y_bounds(0.0, WORLD_SIZE as f64)
.build();
let min = plane.iter().fold(f64::MAX, |min, &val| val.min(min));
let max = plane.iter().fold(f64::MIN, |max, &val| val.max(max));
let mut img = RgbImage::new(WORLD_SIZE as u32, WORLD_SIZE as u32);
println!("Min: {}", min);
println!("Max: {}", max);
let mut world = world::World::new(WORLD_SIZE);
let mut img = RgbImage::new(map_size as u32, map_size as u32);
let mut world = world::World::new(map_size);
for x in 0..map_size {
for y in 0..map_size {
for x in 0..WORLD_SIZE {
for y in 0..WORLD_SIZE {
let h = plane.get_value(x, y);
let t = world::Terrain::from_height(h);
world.map[x][y] = world::WorldCell::new(t);
@ -88,27 +85,24 @@ fn main() {
}
}
let mut placed = 0;
while placed < N_TOWNS {
let x = rng.gen_range(0..map_size);
let y = rng.gen_range(0..map_size);
if
world.map[x][y].terrain == world::Terrain::Flats ||
world.map[x][y].terrain == world::Terrain::Hills
{
world.add_structure(x, y, world::Structure::Town(world::Town::new()));
placed += 1;
img.put_pixel(x as u32, y as u32, Rgb([255, 0, 0]));
}
world
}
fn main() {
let mut state = state::GameState::new(build_world());
let mut rng = rand::thread_rng();
for _ in 0..N_TOWNS {
state.step_n(rng.gen_range(0..360*3));
state.found_town();
}
let scaled = image::imageops::resize(
&img,
map_size as u32 * 4, map_size as u32 * 4,
image::imageops::FilterType::Nearest);
scaled.save("world.png").unwrap();
for event in &state.events {
println!("{}", event.description());
}
}

12
src/names/towns/first.txt Normal file
View File

@ -0,0 +1,12 @@
iron
copper
silver
gold
wood
frost
summer
winter
spring
dagger
sword
hammer

View File

@ -0,0 +1,12 @@
iron
copper
silver
gold
wood
frost
summer
winter
spring
dagger
sword
hammer

12
src/person.rs Normal file
View File

@ -0,0 +1,12 @@
pub enum Profession {
Peasant,
Adventurer,
Blacksmith,
}
pub struct Person {
pub name: String,
pub age: u32,
pub profession: Profession,
pub location: [usize; 2],
}

View File

@ -1,4 +1,88 @@
use crate::world::World;
use std::rc::Rc;
use rand::prelude::*;
use crate::time::Time;
use crate::world::{World, Terrain, Town};
use crate::events::{FoundTown, WorldGenesis};
pub struct GameState {
pub time: Time,
pub world: World,
pub events: Vec<Box<Event>>
}
pub struct Event {
pub time: Time,
pub effect: Box<dyn Effect>,
}
pub trait Effect {
fn apply(&self, state: &mut GameState);
fn description(&self) -> String;
}
impl Event {
pub fn description(&self) -> String {
format!("{}: {}", self.time, self.effect.description())
}
}
impl GameState {
pub fn new(world: World) -> GameState {
let mut events = Vec::new();
events.push(Box::new(Event {
time: Time { time: 0 },
effect: Box::new(WorldGenesis),
}));
GameState {
time: Time { time: 0 },
world: world,
events: events,
}
}
pub fn add_event(&mut self, event: Event) {
event.effect.apply(self);
self.events.push(Box::new(event));
}
pub fn step(&mut self) {
self.time.time += 1;
}
pub fn step_n(&mut self, n: u32) {
for _ in 0..n {
self.step();
}
}
pub fn step_year(&mut self) {
for _ in 0..360 {
self.step();
}
}
pub fn found_town(&mut self) {
let mut rng = rand::thread_rng();
loop {
let x = rng.gen_range(0..self.world.size);
let y = rng.gen_range(0..self.world.size);
if
self.world.map[x][y].terrain == Terrain::Flats ||
self.world.map[x][y].terrain == Terrain::Hills
{
self.add_event(Event {
time: self.time,
effect: Box::new(FoundTown {
x: x,
y: y,
town: Rc::new(Town::new()),
})
});
break;
}
}
}
}

17
src/time.rs Normal file
View File

@ -0,0 +1,17 @@
use std::fmt;
#[derive(Clone, Copy)]
pub struct Time{
pub time: u32,
}
impl fmt::Display for Time {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let year = self.time / 360;
let month = (self.time / 30) % 12;
let day = self.time % 30;
write!(f, "Year {}, {} of {}", year, day, month)
}
}

View File

@ -1,3 +1,8 @@
use std::rc::Rc;
use rand::prelude::*;
use crate::generators::TownNameGenerator;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Terrain {
Void,
@ -16,7 +21,7 @@ pub struct Town {
}
pub enum Structure {
Town(Town),
Town(Rc<Town>),
}
pub struct WorldCell {
@ -94,9 +99,10 @@ impl Terrain {
impl Town {
pub fn new() -> Town {
let mut rng = rand::thread_rng();
Town {
name: "Town".to_string(),
population: 100,
name: TownNameGenerator::name(),
population: rng.gen_range(100..500),
}
}
}