First attempt to add NPCs
This commit is contained in:
@@ -15,3 +15,4 @@ randomize = "5.0.0"
|
|||||||
getrandom = "0.2.15"
|
getrandom = "0.2.15"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
noise = "0.9"
|
noise = "0.9"
|
||||||
|
vec2d = "0.4"
|
||||||
13
src/cell.rs
13
src/cell.rs
@@ -1,3 +1,6 @@
|
|||||||
|
use core::fmt;
|
||||||
|
use std::fmt::write;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum CellVariance {
|
pub enum CellVariance {
|
||||||
VOID = 0,
|
VOID = 0,
|
||||||
@@ -5,6 +8,16 @@ pub enum CellVariance {
|
|||||||
NIGHT = 2
|
NIGHT = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for CellVariance {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
CellVariance::VOID => write!(f, "VOID"),
|
||||||
|
CellVariance::NIGHT => write!(f, "NIGHT"),
|
||||||
|
CellVariance::DAY => write!(f, "DAY")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for CellVariance {
|
impl Default for CellVariance {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::VOID
|
Self::VOID
|
||||||
|
|||||||
11
src/direction.rs
Normal file
11
src/direction.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Direction {
|
||||||
|
pub x: isize,
|
||||||
|
pub y: isize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Direction {
|
||||||
|
pub fn new(x: isize, y: isize) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/main.rs
48
src/main.rs
@@ -1,5 +1,7 @@
|
|||||||
mod cell;
|
mod cell;
|
||||||
mod stage;
|
mod stage;
|
||||||
|
mod npc;
|
||||||
|
mod direction;
|
||||||
|
|
||||||
use pixels::{Error, Pixels, SurfaceTexture};
|
use pixels::{Error, Pixels, SurfaceTexture};
|
||||||
use stage::Stage;
|
use stage::Stage;
|
||||||
@@ -11,9 +13,9 @@ use winit::{
|
|||||||
};
|
};
|
||||||
use winit_input_helper::WinitInputHelper;
|
use winit_input_helper::WinitInputHelper;
|
||||||
|
|
||||||
const WIDTH: u32 = 256;
|
const WIDTH: u32 = 350;
|
||||||
const HEIGHT: u32 = 256;
|
const HEIGHT: u32 = 350;
|
||||||
const SCALE_FACTOR: f64 = 4.0;
|
const SCALE_FACTOR: f64 = 3.0;
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
@@ -65,10 +67,50 @@ fn main() -> Result<(), Error> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if input.key_pressed(VirtualKeyCode::P) {
|
||||||
|
paused = !paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.key_pressed_os(VirtualKeyCode::Space) {
|
||||||
|
// Space is frame-step, so ensure we're paused
|
||||||
|
paused = true;
|
||||||
|
}
|
||||||
|
|
||||||
if input.key_pressed(VirtualKeyCode::R) {
|
if input.key_pressed(VirtualKeyCode::R) {
|
||||||
stage.scatter(stage::ScatterTypes::RANDOM);
|
stage.scatter(stage::ScatterTypes::RANDOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle mouse. This is a bit involved since support some simple
|
||||||
|
// line drawing (mostly because it makes nice looking patterns).
|
||||||
|
let (mouse_cell, mouse_prev_cell) = input
|
||||||
|
.mouse()
|
||||||
|
.map(|(mx, my)| {
|
||||||
|
let (dx, dy) = input.mouse_diff();
|
||||||
|
let prev_x = mx - dx;
|
||||||
|
let prev_y = my - dy;
|
||||||
|
|
||||||
|
let (mx_i, my_i) = pixels
|
||||||
|
.window_pos_to_pixel((mx, my))
|
||||||
|
.unwrap_or_else(|pos| pixels.clamp_pixel_pos(pos));
|
||||||
|
|
||||||
|
let (px_i, py_i) = pixels
|
||||||
|
.window_pos_to_pixel((prev_x, prev_y))
|
||||||
|
.unwrap_or_else(|pos| pixels.clamp_pixel_pos(pos));
|
||||||
|
|
||||||
|
(
|
||||||
|
(mx_i as isize, my_i as isize),
|
||||||
|
(px_i as isize, py_i as isize),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
if input.mouse_pressed(0) {
|
||||||
|
println!("Mouse click at {mouse_cell:?}");
|
||||||
|
stage.spawn_npc(mouse_cell.0, mouse_cell.1);
|
||||||
|
|
||||||
|
stage.update();
|
||||||
|
}
|
||||||
|
|
||||||
// Resize the window
|
// Resize the window
|
||||||
if let Some(size) = input.window_resized() {
|
if let Some(size) = input.window_resized() {
|
||||||
if let Err(err) = pixels.resize_surface(size.width, size.height) {
|
if let Err(err) = pixels.resize_surface(size.width, size.height) {
|
||||||
|
|||||||
26
src/npc.rs
Normal file
26
src/npc.rs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
use vec2d::{Coord, Vec2D};
|
||||||
|
|
||||||
|
use crate::{cell::CellVariance, direction::Direction};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct NPC {
|
||||||
|
pub walk_on: CellVariance,
|
||||||
|
pub obstructed_from: Vec<CellVariance>,
|
||||||
|
pub pos_x: isize,
|
||||||
|
pub pos_y: isize,
|
||||||
|
pub direction: Direction
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NPC {
|
||||||
|
pub fn new(pos_x: isize, pos_y: isize, direction: Direction, walk_on: CellVariance, obstructed_from: Vec<CellVariance>) -> Self {
|
||||||
|
Self { walk_on, obstructed_from, pos_x, pos_y, direction }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_day(pos_x: isize, pos_y: isize, direction: Direction) -> Self {
|
||||||
|
Self { walk_on: CellVariance::DAY, obstructed_from: vec![CellVariance::NIGHT], pos_x, pos_y, direction }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_night(pos_x: isize, pos_y: isize, direction: Direction) -> Self {
|
||||||
|
Self { walk_on: CellVariance::NIGHT, obstructed_from: vec![CellVariance::DAY], pos_x, pos_y, direction }
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/stage.rs
68
src/stage.rs
@@ -1,22 +1,20 @@
|
|||||||
use noise::core::value;
|
|
||||||
use noise::core::value::value_2d;
|
|
||||||
use noise::permutationtable::PermutationTable;
|
|
||||||
use noise::utils::NoiseMapBuilder;
|
use noise::utils::NoiseMapBuilder;
|
||||||
use noise::utils::PlaneMapBuilder;
|
use noise::utils::PlaneMapBuilder;
|
||||||
use noise::BasicMulti;
|
use noise::BasicMulti;
|
||||||
use noise::Fbm;
|
use noise::MultiFractal;
|
||||||
use noise::Perlin;
|
use noise::Perlin;
|
||||||
use noise::Seedable;
|
|
||||||
use randomize::Gen32;
|
|
||||||
use randomize::PCG32;
|
use randomize::PCG32;
|
||||||
|
|
||||||
use crate::cell::Cell;
|
use crate::cell::Cell;
|
||||||
use crate::cell::CellVariance;
|
use crate::cell::CellVariance;
|
||||||
|
use crate::direction::Direction;
|
||||||
|
use crate::npc::NPC;
|
||||||
pub struct Stage {
|
pub struct Stage {
|
||||||
cells: Vec<Cell>,
|
cells: Vec<Cell>,
|
||||||
|
|
||||||
/// Used for temporary work item. Replaces `cells` once done.
|
/// Used for temporary work item. Replaces `cells` once done.
|
||||||
cells_dup: Vec<Cell>,
|
cells_dup: Vec<Cell>,
|
||||||
|
npcs: Vec<NPC>,
|
||||||
width: usize,
|
width: usize,
|
||||||
height: usize,
|
height: usize,
|
||||||
}
|
}
|
||||||
@@ -33,6 +31,7 @@ impl Stage {
|
|||||||
Self {
|
Self {
|
||||||
cells: vec![Cell::default(); size],
|
cells: vec![Cell::default(); size],
|
||||||
cells_dup: vec![Cell::default(); size],
|
cells_dup: vec![Cell::default(); size],
|
||||||
|
npcs: vec![],
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
}
|
}
|
||||||
@@ -59,7 +58,9 @@ impl Stage {
|
|||||||
let seed = Self::generate_seed();
|
let seed = Self::generate_seed();
|
||||||
let mut rng: randomize::PCG32 = PCG32::new(seed.0, seed.1);
|
let mut rng: randomize::PCG32 = PCG32::new(seed.0, seed.1);
|
||||||
|
|
||||||
let basicmulti = BasicMulti::<Perlin>::new(rng.next_u32());
|
let basicmulti = BasicMulti::<Perlin>::new(rng.next_u32())
|
||||||
|
.set_octaves(2)
|
||||||
|
.set_frequency(0.5);
|
||||||
|
|
||||||
let plane = PlaneMapBuilder::new(basicmulti)
|
let plane = PlaneMapBuilder::new(basicmulti)
|
||||||
.set_size(self.width, self.height)
|
.set_size(self.width, self.height)
|
||||||
@@ -88,6 +89,28 @@ impl Stage {
|
|||||||
self.update();
|
self.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn spawn_npc(&mut self, pos_x: isize, pos_y: isize) {
|
||||||
|
let cell = self.get_cell(pos_x, pos_y);
|
||||||
|
|
||||||
|
let npc: NPC;
|
||||||
|
match cell.variance {
|
||||||
|
CellVariance::DAY => {
|
||||||
|
npc = NPC::new_day(pos_x, pos_y, Direction::new(-1, -1));
|
||||||
|
},
|
||||||
|
CellVariance::NIGHT => {
|
||||||
|
npc = NPC::new_night(pos_x, pos_y, Direction::new(-1, -1));
|
||||||
|
},
|
||||||
|
CellVariance::VOID => {
|
||||||
|
// Ignore this stupid request.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Spawn NPC at ({}, {}) as {}", pos_x, pos_y, npc.walk_on);
|
||||||
|
|
||||||
|
self.npcs.push(npc);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn draw(&self, screen: &mut [u8]) {
|
pub fn draw(&self, screen: &mut [u8]) {
|
||||||
debug_assert_eq!(screen.len(), 4 * self.cells.len());
|
debug_assert_eq!(screen.len(), 4 * self.cells.len());
|
||||||
for (c, pix) in self.cells.iter().zip(screen.chunks_exact_mut(4)) {
|
for (c, pix) in self.cells.iter().zip(screen.chunks_exact_mut(4)) {
|
||||||
@@ -98,9 +121,40 @@ impl Stage {
|
|||||||
};
|
};
|
||||||
pix.copy_from_slice(&color);
|
pix.copy_from_slice(&color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (n, pix) in self.npcs.iter().zip(screen.chunks_exact_mut(4)) {
|
||||||
|
let color = match n.walk_on {
|
||||||
|
CellVariance::DAY => [0x10, 0x41, 0x4F, 0xFF],
|
||||||
|
CellVariance::NIGHT => [0xD3, 0xE3, 0xD3, 0xFF],
|
||||||
|
_ => {
|
||||||
|
panic!("This NPC shouldn't even exist!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pix.copy_from_slice(&color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_cell(&self, pos_x: isize, pos_y: isize) -> Cell {
|
||||||
|
self.cells[(pos_x + pos_y) as usize * self.width]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self) {
|
pub fn update(&mut self) {
|
||||||
|
// TODO: Flying balls
|
||||||
|
|
||||||
|
for y in 0..self.height {
|
||||||
|
for x in 0..self.width {
|
||||||
|
let idx = x + y * self.width;
|
||||||
|
// Write into scratch_cells, since we're still reading from `self.cells`
|
||||||
|
|
||||||
|
self.cells_dup[idx] = self.cells[idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::mem::swap(&mut self.cells_dup, &mut self.cells);
|
std::mem::swap(&mut self.cells_dup, &mut self.cells);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_cells(&self) -> &Vec<Cell> {
|
||||||
|
&self.cells
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user