more world gen
This commit is contained in:
parent
f64a757ec6
commit
99f61fbd70
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
mod found_town;
|
||||
mod world_genesis;
|
||||
|
||||
pub use found_town::FoundTown;
|
||||
pub use world_genesis::WorldGenesis;
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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..]
|
||||
}
|
||||
}
|
78
src/main.rs
78
src/main.rs
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
iron
|
||||
copper
|
||||
silver
|
||||
gold
|
||||
wood
|
||||
frost
|
||||
summer
|
||||
winter
|
||||
spring
|
||||
dagger
|
||||
sword
|
||||
hammer
|
|
@ -0,0 +1,12 @@
|
|||
iron
|
||||
copper
|
||||
silver
|
||||
gold
|
||||
wood
|
||||
frost
|
||||
summer
|
||||
winter
|
||||
spring
|
||||
dagger
|
||||
sword
|
||||
hammer
|
|
@ -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],
|
||||
}
|
86
src/state.rs
86
src/state.rs
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
12
src/world.rs
12
src/world.rs
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue