Browse Source

Add world chunks

master
Garrit Franke 3 years ago
parent
commit
af1cc56020
  1. 10
      src/crypto.rs
  2. 76
      src/main.rs
  3. 4
      src/map.rs

10
src/crypto.rs

@ -0,0 +1,10 @@
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
pub fn hash_to_number(s: impl Hash) -> u64 {
let mut hasher = DefaultHasher::new();
s.hash(&mut hasher);
hasher.finish()
}

76
src/main.rs

@ -4,13 +4,17 @@
//////////////////////////////////////////////////////////////
rltk::add_wasm_support!();
mod crypto;
mod map;
use crate::map::Chunk;
use map::TileType;
use rltk::prelude::*;
use std::collections::HashMap;
// Just like example 3, but we're adding an additional vector: visible
struct State {
map: Vec<map::TileType>,
view: Chunk,
loaded_chunks: HashMap<(i32, i32), Chunk>,
world_pos: (i32, i32),
player_position: usize,
visible: Vec<bool>,
@ -18,11 +22,31 @@ struct State {
impl State {
pub fn new() -> State {
let seed = RandomNumberGenerator::new().rand::<u64>();
// Same as example 3, but we've added the visible tiles
let mut chunks: HashMap<(i32, i32), Chunk> = HashMap::new();
// Coordinates of the current and surrounding chunks
let keys: Vec<(i32, i32)> = [
(-1, 1),
(0, 1),
(1, 1),
(-1, 0),
(0, 0),
(1, 0),
(-1, -1),
(0, -1),
(1, -1),
]
.into();
for key in keys {
let seed = RandomNumberGenerator::new().rand::<u64>();
let chunk = map::new_chunk(seed);
chunks.insert(key, chunk);
}
let state = State {
world_pos: (0, 0),
map: map::new_chunk(seed),
view: chunks.get(&(0, 0)).unwrap().to_vec(),
loaded_chunks: chunks,
player_position: (25 * 80) + 40, // Equivalent to point2d_to_index(40, 25) but we haven't initialized it yet
visible: vec![false; 80 * 50],
};
@ -30,12 +54,46 @@ impl State {
state
}
fn move_to_chunk(&mut self, delta: (i32, i32)) {
// Move world position by delta
self.world_pos = (self.world_pos.0 + delta.0, self.world_pos.1 + delta.1);
// Update loaded chunks
match self.loaded_chunks.get(&self.world_pos) {
Some(chunk) => self.view = chunk.to_vec(),
None => {
self.loaded_chunks.insert(
self.world_pos,
map::new_chunk(crypto::hash_to_number(&self.world_pos)),
);
}
};
}
pub fn move_player(&mut self, delta: Point) {
let current_position = self.index_to_point2d(self.player_position);
let new_position = current_position + delta;
let new_idx = self.point2d_to_index(new_position);
if self.map[new_idx] == TileType::Floor {
self.player_position = new_idx;
// Check if the user has left the chunk to either side.
// If that's the case, the current chunk is updated
// and the player position is updated
if new_position.x >= 80 {
self.move_to_chunk((1, 0));
self.move_player(Point::new(-79, 0));
} else if new_position.x < 0 {
self.move_to_chunk((-1, 0));
self.move_player(Point::new(79, 0));
} else if new_position.y >= 50 {
self.move_to_chunk((0, 1));
self.move_player(Point::new(0, -49));
} else if new_position.y < 0 {
self.move_to_chunk((0, -1));
self.move_player(Point::new(0, 49));
} else {
let new_idx = self.point2d_to_index(new_position);
if self.view[new_idx] == TileType::Floor {
self.player_position = new_idx;
}
}
}
}
@ -93,7 +151,7 @@ impl GameState for State {
// Iterate the map array, incrementing coordinates as we go.
let mut y = 0;
let mut x = 0;
for (i, tile) in self.map.iter().enumerate() {
for (i, tile) in self.view.iter().enumerate() {
// Render a tile depending upon the tile type; now we check visibility as well!
let mut fg;
let mut glyph = ".";
@ -138,7 +196,7 @@ impl GameState for State {
impl BaseMap for State {
// We'll use this one - if its a wall, we can't see through it
fn is_opaque(&self, idx: usize) -> bool {
self.map[idx as usize] == TileType::Wall
self.view[idx as usize] == TileType::Wall
}
}

4
src/map.rs

@ -1,12 +1,14 @@
use rltk::RandomNumberGenerator;
pub type Chunk = Vec<TileType>;
#[derive(PartialEq, Copy, Clone)]
pub enum TileType {
Wall,
Floor,
}
pub fn new_chunk(seed: u64) -> Vec<TileType> {
pub fn new_chunk(seed: u64) -> Chunk {
let mut map = vec![TileType::Floor; 80 * 50];
let count = map.len();

Loading…
Cancel
Save