save
This commit is contained in:
parent
5cfaf975d1
commit
2fd0fb9fc3
281
assets/horse.svg
Normal file
281
assets/horse.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 468 KiB |
@ -7,14 +7,14 @@ use crate::state::State;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Zeroable, Pod, Debug)]
|
||||
pub struct Vertex {
|
||||
pub pos: [f32; 3],
|
||||
pub pos: [f32; 2],
|
||||
pub color: [f32; 4]
|
||||
}
|
||||
impl Vertex {
|
||||
const DESC: VertexBufferLayout<'static> = VertexBufferLayout {
|
||||
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
|
||||
step_mode: wgpu::VertexStepMode::Vertex,
|
||||
attributes: &wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x4],
|
||||
attributes: &wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x4],
|
||||
};
|
||||
}
|
||||
|
||||
@ -33,13 +33,6 @@ impl Default for Uniforms {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Uniforms {
|
||||
const DESC: VertexBufferLayout<'static> = VertexBufferLayout {
|
||||
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
|
||||
step_mode: wgpu::VertexStepMode::Vertex,
|
||||
attributes: &wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32],
|
||||
};
|
||||
}
|
||||
|
||||
pub struct Graphics<'a> {
|
||||
state: State,
|
||||
@ -91,13 +84,13 @@ impl<'a> Graphics<'a> {
|
||||
|
||||
let vertex_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Vertex Buffer"),
|
||||
contents: &[bytemuck::cast_slice::<Vertex, _>(&state.vertices), &[0; 1024]].concat(),
|
||||
contents: &[bytemuck::cast_slice::<Vertex, _>(&state.vertices), &[0; 100000]].concat(),
|
||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||
});
|
||||
|
||||
let index_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Index Buffer"),
|
||||
contents: &[bytemuck::cast_slice::<u32, _>(&state.indices), &[0; 1024]].concat(),
|
||||
contents: &[bytemuck::cast_slice::<u32, _>(&state.indices), &[0; 100000]].concat(),
|
||||
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
|
||||
});
|
||||
|
||||
|
@ -11,13 +11,13 @@ struct VertexOutput {
|
||||
|
||||
@vertex
|
||||
fn vs_main(
|
||||
@location(0) pos: vec3f,
|
||||
@location(0) pos: vec2f,
|
||||
@location(1) color: vec4f
|
||||
) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.color = color;
|
||||
// out.color[3] -= uniforms.darkness;
|
||||
out.pos = vec4f(pos.xy-uniforms.camera.xy, pos.z, uniforms.camera.z);
|
||||
out.pos = vec4f((pos.xy-uniforms.camera.xy)/uniforms.camera.z, 0, 1);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
249
src/state.rs
249
src/state.rs
@ -1,23 +1,23 @@
|
||||
use std::time::Instant;
|
||||
use log::info;
|
||||
use noise::{Fbm, MultiFractal, NoiseFn, Perlin};
|
||||
use rand::prelude::*;
|
||||
use voronoice::{BoundingBox, Point, Voronoi, VoronoiBuilder};
|
||||
use winit::{event::{DeviceEvent, Event, MouseButton, MouseScrollDelta, WindowEvent}, window::Window};
|
||||
use winit::{event::{DeviceEvent, ElementState, Event, KeyEvent, MouseButton, MouseScrollDelta, RawKeyEvent, WindowEvent}, keyboard::{KeyCode, PhysicalKey}, window::Window};
|
||||
|
||||
use crate::graphics::{Uniforms, Vertex};
|
||||
|
||||
const FRAMERATE: usize = 10; // Update per second
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum CellKind {
|
||||
Void,
|
||||
Sea,
|
||||
Plain,
|
||||
Beach,
|
||||
Forest,
|
||||
Dirt,
|
||||
Stone
|
||||
Stone,
|
||||
Grass
|
||||
}
|
||||
|
||||
struct CellData {
|
||||
@ -41,11 +41,11 @@ impl CellData {
|
||||
match self.kind {
|
||||
CellKind::Void => [0.; 4],
|
||||
CellKind::Sea => [0., 0., 1., 1.],
|
||||
CellKind::Plain => [0., 1., 0., 1.],
|
||||
CellKind::Beach => [0.82, 0.84, 0.51, 1.],
|
||||
CellKind::Forest => [0., 0.5 - (self.moisture*0.4), 0., 1.],
|
||||
CellKind::Dirt => [0.53 - (self.moisture*0.4), 0.38-(self.moisture*0.4), 0.29-(self.moisture*0.4), 1.],
|
||||
CellKind::Stone => [0.5, 0.5, 0.5, 1.]
|
||||
CellKind::Stone => [0.5, 0.5, 0.5, 1.],
|
||||
CellKind::Grass => [(136./255.) - (self.moisture*0.4), (204./255.) - (self.moisture*0.4), (59./255.) - (self.moisture*0.4), 1.]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -105,11 +105,165 @@ impl Map {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum EntityKind {
|
||||
Horse
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum EntityState {
|
||||
Walking(Instant), // Start of walk
|
||||
Resting
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Entity {
|
||||
pos: [f32; 3],
|
||||
kind: EntityKind,
|
||||
start: Instant,
|
||||
state: EntityState
|
||||
}
|
||||
impl Entity {
|
||||
fn new(pos: [f32; 3], kind: EntityKind) -> Self {
|
||||
Self {
|
||||
pos,
|
||||
kind,
|
||||
start: Instant::now(),
|
||||
state: EntityState::Resting
|
||||
}
|
||||
}
|
||||
fn render(&self, vertices: &mut Vec<Vertex>, indices: &mut Vec<u32>) {
|
||||
match self.kind {
|
||||
EntityKind::Horse => {
|
||||
let color = [171./255., 122./255., 50./255., 1.];
|
||||
let dark = [color[0]-0.3, color[1]-0.3, color[2]-0.3, 1.];
|
||||
let (vs, is) = match self.state {
|
||||
EntityState::Walking(now) => {
|
||||
let now = now.elapsed().as_secs_f32()*5.;
|
||||
(
|
||||
[
|
||||
// back left leg
|
||||
Vertex { pos: [-0.5, 0.3], color: dark },
|
||||
Vertex { pos: [-0.4 + (now.sin()*0.1), -0.7 + (now.cos().max(-0.5)*0.1)], color: dark },
|
||||
Vertex { pos: [-0.25, 0.1], color: dark },
|
||||
|
||||
// back right leg
|
||||
Vertex { pos: [-0.5, 0.3], color },
|
||||
Vertex { pos: [-0.4 + ((now + 1.).sin()*0.1), -0.7 + ((now + 1.).cos().max(-0.5)*0.1)], color },
|
||||
Vertex { pos: [-0.25, 0.1], color },
|
||||
|
||||
// front left leg
|
||||
Vertex { pos: [0.3, 0.2], color: dark },
|
||||
Vertex { pos: [0.4 + ((now-1.).sin()*0.1), -0.7 + ((now-1.).cos().max(-0.5)*0.1)], color: dark },
|
||||
Vertex { pos: [0.5, 0.3], color: dark },
|
||||
|
||||
// front right leg
|
||||
Vertex { pos: [0.3, 0.2], color },
|
||||
Vertex { pos: [0.4 + ((now-2.).sin()*0.1), -0.7 + ((now-2.).cos().max(-0.5)*0.1)], color },
|
||||
Vertex { pos: [0.5, 0.3], color },
|
||||
|
||||
// body
|
||||
// 3
|
||||
Vertex { pos: [-0.3, 0.], color },
|
||||
Vertex { pos: [0.4, -0.1], color },
|
||||
// 11
|
||||
Vertex { pos: [0.3, 0.4], color },
|
||||
],
|
||||
[
|
||||
0,1,2,
|
||||
3,4,5,
|
||||
6,7,8,
|
||||
9,10,11,
|
||||
3,12,13,
|
||||
3,13,11,
|
||||
3,11,14
|
||||
]
|
||||
)
|
||||
},
|
||||
EntityState::Resting => {
|
||||
(
|
||||
[
|
||||
// back left leg
|
||||
Vertex { pos: [-0.5, 0.3], color: dark },
|
||||
Vertex { pos: [-0.4, -0.75], color: dark },
|
||||
Vertex { pos: [-0.25, 0.1], color: dark },
|
||||
|
||||
// back right leg
|
||||
Vertex { pos: [-0.5, 0.3], color },
|
||||
Vertex { pos: [-0.4, -0.75], color },
|
||||
Vertex { pos: [-0.25, 0.1], color },
|
||||
|
||||
// front left leg
|
||||
Vertex { pos: [0.3, 0.2], color: dark },
|
||||
Vertex { pos: [0.4, -0.75], color: dark },
|
||||
Vertex { pos: [0.5, 0.3], color: dark },
|
||||
|
||||
// front right leg
|
||||
Vertex { pos: [0.3, 0.2], color },
|
||||
Vertex { pos: [0.4, -0.75], color },
|
||||
Vertex { pos: [0.5, 0.3], color },
|
||||
|
||||
// body
|
||||
// 3
|
||||
Vertex { pos: [-0.3, 0.], color },
|
||||
Vertex { pos: [0.4, -0.1], color },
|
||||
// 11
|
||||
Vertex { pos: [0.3, 0.4], color },
|
||||
],
|
||||
[
|
||||
0,1,2,
|
||||
3,4,5,
|
||||
6,7,8,
|
||||
9,10,11,
|
||||
3,12,13,
|
||||
3,13,11,
|
||||
3,11,14
|
||||
]
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
vertices.reserve(vs.len());
|
||||
let base = vertices.len() as u32;
|
||||
for mut v in vs {
|
||||
v.pos[0] = v.pos[0]/50. + self.pos[0];
|
||||
v.pos[1] = (v.pos[1] + 0.75)/50. + self.pos[1];
|
||||
vertices.push(v)
|
||||
}
|
||||
|
||||
indices.reserve(is.len());
|
||||
for i in is {
|
||||
indices.push(base + i);
|
||||
}
|
||||
|
||||
// let vs = vec![
|
||||
// Vertex { pos: [-0.5, 0.3, 0.], color },
|
||||
// Vertex { pos: [-0.3, 0., 0.], color },
|
||||
// Vertex { pos: [0.4, -0.1, 0.], color },
|
||||
// Vertex { pos: [0.5, 0.3, 0.], color },
|
||||
// Vertex { pos: [0.3, 0.4, 0.], color },
|
||||
// ];
|
||||
// let i = self.vertices.len() as u32;
|
||||
// for v in vs.iter() {
|
||||
// self.vertices.push(*v);
|
||||
// }
|
||||
// for v in 1..(vs.len()-1) as u32 {
|
||||
// self.indices.push(i);
|
||||
// self.indices.push(i+v);
|
||||
// self.indices.push(i+v+1);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
pub vertices: Vec<Vertex>,
|
||||
pub indices: Vec<u32>,
|
||||
pub uniforms: Uniforms,
|
||||
map: Map,
|
||||
entities: Vec<Entity>,
|
||||
start: Instant,
|
||||
frame: usize,
|
||||
selected_tile: usize,
|
||||
@ -124,6 +278,7 @@ impl State {
|
||||
start: Instant::now(),
|
||||
frame: 0,
|
||||
map: Map::new(0),
|
||||
entities: Vec::new(),
|
||||
selected_tile: 0,
|
||||
mouse_pressed: false
|
||||
};
|
||||
@ -153,17 +308,19 @@ impl State {
|
||||
Event::WindowEvent { event: WindowEvent::CursorMoved { position, .. }, ..} => {
|
||||
let w_size = window.inner_size();
|
||||
let pos = Point {
|
||||
x: ((2.*position.x/(w_size.width as f64))-1.)*(self.uniforms.camera[2] as f64),
|
||||
y: (1.-(2.*position.y/(w_size.height as f64)))*(self.uniforms.camera[2] as f64)
|
||||
x: ((2.*position.x/(w_size.width as f64))-1.)*(self.uniforms.camera[2] as f64) + self.uniforms.camera[0] as f64,
|
||||
y: (1.-(2.*position.y/(w_size.height as f64)))*(self.uniforms.camera[2] as f64) + self.uniforms.camera[1] as f64
|
||||
};
|
||||
let c = self.map.voronoi.cell(self.selected_tile);
|
||||
if self.mouse_pressed {
|
||||
for i in c.iter_path(pos) {
|
||||
for i in c.iter_path(pos.clone()) {
|
||||
self.selected_tile = i;
|
||||
let cd = &mut self.map.cells_data[self.selected_tile];
|
||||
if let CellKind::Dirt = cd.kind {
|
||||
cd.kind = CellKind::Forest;
|
||||
}
|
||||
|
||||
self.entities.push(Entity::new([pos.x as f32, pos.y as f32, 0.9], EntityKind::Horse));
|
||||
}
|
||||
} else {
|
||||
self.selected_tile = c.iter_path(pos).last().unwrap();
|
||||
@ -174,15 +331,36 @@ impl State {
|
||||
MouseScrollDelta::PixelDelta(pos) => pos.y as f32,
|
||||
MouseScrollDelta::LineDelta(_, y) => y
|
||||
};
|
||||
self.uniforms.camera[2] = self.uniforms.camera[2].clamp(0.1, 1.);
|
||||
},
|
||||
Event::WindowEvent { event: WindowEvent::KeyboardInput { event: KeyEvent { physical_key: PhysicalKey::Code(kc), state, .. }, .. }, .. } => {
|
||||
if state.is_pressed() {
|
||||
match kc {
|
||||
KeyCode::KeyW => {
|
||||
self.uniforms.camera[1] += 0.1;
|
||||
},
|
||||
KeyCode::KeyS => {
|
||||
self.uniforms.camera[1] -= 0.1;
|
||||
},
|
||||
KeyCode::KeyA => {
|
||||
self.uniforms.camera[0] -= 0.1;
|
||||
},
|
||||
KeyCode::KeyD => {
|
||||
self.uniforms.camera[0] += 0.1;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
pub fn render(&mut self) {
|
||||
info!("render");
|
||||
self.vertices = Vec::new();
|
||||
self.indices = Vec::new();
|
||||
|
||||
for (c, cd) in self.map.voronoi.iter_cells().zip(self.map.cells_data.iter()) {
|
||||
for (c, cd) in self.map.voronoi.iter_cells().zip(self.map.cells_data.iter()).filter(|(_,cd)| cd.kind != CellKind::Forest) {
|
||||
let mut color = cd.color();
|
||||
if c.site() == self.selected_tile {
|
||||
color[0] = (color[0]+0.4).clamp(0., 1.);
|
||||
@ -192,7 +370,30 @@ impl State {
|
||||
let vs = c.iter_vertices().collect::<Vec<_>>();
|
||||
let i = self.vertices.len() as u32;
|
||||
for v in vs.iter() {
|
||||
self.vertices.push(Vertex { pos: [v.x as f32, v.y as f32, cd.z], color });
|
||||
self.vertices.push(Vertex { pos: [v.x as f32, v.y as f32], color });
|
||||
}
|
||||
for v in 1..(vs.len()-1) as u32 {
|
||||
self.indices.push(i);
|
||||
self.indices.push(i+v);
|
||||
self.indices.push(i+v+1);
|
||||
}
|
||||
}
|
||||
|
||||
for e in self.entities.iter() {
|
||||
e.render(&mut self.vertices, &mut self.indices);
|
||||
}
|
||||
|
||||
for (c, cd) in self.map.voronoi.iter_cells().zip(self.map.cells_data.iter()).filter(|(_,cd)| cd.kind == CellKind::Forest) {
|
||||
let mut color = cd.color();
|
||||
if c.site() == self.selected_tile {
|
||||
color[0] = (color[0]+0.4).clamp(0., 1.);
|
||||
color[1] = (color[1]+0.4).clamp(0., 1.);
|
||||
color[2] = (color[2]+0.4).clamp(0., 1.);
|
||||
}
|
||||
let vs = c.iter_vertices().collect::<Vec<_>>();
|
||||
let i = self.vertices.len() as u32;
|
||||
for v in vs.iter() {
|
||||
self.vertices.push(Vertex { pos: [v.x as f32, v.y as f32], color });
|
||||
}
|
||||
for v in 1..(vs.len()-1) as u32 {
|
||||
self.indices.push(i);
|
||||
@ -207,22 +408,30 @@ impl State {
|
||||
}
|
||||
}
|
||||
pub fn update(&mut self) {
|
||||
info!("update");
|
||||
let mut rng = thread_rng();
|
||||
let mut new_forest = Vec::new();
|
||||
let mut new_kind = Vec::new();
|
||||
for cd in self.map.cells_data.iter() {
|
||||
if let CellKind::Forest = cd.kind {
|
||||
if rng.gen::<f32>() < (0.03*cd.moisture) {
|
||||
if cd.kind == CellKind::Forest || cd.kind == CellKind::Grass {
|
||||
let r = rng.gen::<f32>();
|
||||
if r < (0.035*cd.moisture) {
|
||||
let c = self.map.voronoi.cell(cd.cell);
|
||||
let n = c.iter_neighbors().choose(&mut rng).unwrap();
|
||||
new_forest.push(n);
|
||||
let k = if r < (0.005*cd.moisture) && (self.map.cells_data[n].kind == CellKind::Dirt || self.map.cells_data[n].kind == CellKind::Grass) && cd.kind == CellKind::Forest {
|
||||
Some(CellKind::Forest)
|
||||
} else if self.map.cells_data[n].kind == CellKind::Dirt {
|
||||
Some(CellKind::Grass)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(k) = k {
|
||||
new_kind.push((n, k));
|
||||
}
|
||||
}
|
||||
}
|
||||
for i in new_forest {
|
||||
let cd = &mut self.map.cells_data[i];
|
||||
if let CellKind::Dirt = cd.kind {
|
||||
cd.kind = CellKind::Forest;
|
||||
}
|
||||
for (n, k) in new_kind {
|
||||
self.map.cells_data[n].kind = k;
|
||||
}
|
||||
|
||||
self.frame += 1;
|
||||
|
Loading…
Reference in New Issue
Block a user