Created
November 5, 2020 17:22
-
-
Save redblobgames/01966bd070c920d05c6b0ae178d9f222 to your computer and use it in GitHub Desktop.
Experiment: Legion ECS vs using Rust enum + pattern matching
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use legion::*; | |
use rltk::{GameState, Rltk, VirtualKeyCode, RGB}; | |
use std::cmp::{max, min}; | |
mod map; | |
pub use map::*; | |
struct Player {} | |
#[derive(PartialEq, Copy, Clone)] | |
struct Position { | |
x: i32, | |
y: i32, | |
} | |
struct Renderable { | |
glyph: rltk::FontCharType, | |
fg: RGB, | |
bg: RGB, | |
} | |
struct State { | |
world: World, | |
resources: Resources, | |
schedule: Schedule, | |
} | |
impl GameState for State { | |
fn tick(&mut self, rltk: &mut Rltk) { | |
// Simulation | |
player_input(self, rltk); | |
self.schedule.execute(&mut self.world, &mut self.resources); | |
// Rendering | |
rltk.cls(); | |
draw_map(&self.resources.get::<GameMap>().unwrap(), rltk); | |
let mut query = <(&Position, &Renderable)>::query(); | |
for (pos, render) in query.iter(&self.world) { | |
rltk.set(pos.x, pos.y, render.fg, render.bg, render.glyph); | |
} | |
rltk.print(1, 1, "Hello Rust World"); | |
} | |
} | |
fn draw_map(map: &GameMap, rltk: &mut Rltk) { | |
for y in 0..map.h { | |
for x in 0..map.w { | |
let (fg, bg, ch) = match map.get(x, y) { | |
TileType::Floor => (RGB::from_f32(0.5, 0.5, 0.5), RGB::from_f32(0., 0., 0.), '.'), | |
TileType::Wall => (RGB::from_f32(0.7, 0.7, 0.5), RGB::from_f32(0., 0., 0.), '#'), | |
}; | |
rltk.set(x, y, fg, bg, rltk::to_cp437(ch)); | |
} | |
} | |
} | |
fn try_move_player(delta_x: i32, delta_y: i32, world: &mut World, game_map: &GameMap) { | |
let mut query = <(&Player, &mut Position)>::query(); | |
for (_player, pos) in query.iter_mut(world) { | |
let new_x = min(game_map.w - 1, max(0, pos.x + delta_x)); | |
let new_y = min(game_map.h - 1, max(0, pos.y + delta_y)); | |
if game_map.get(new_x, new_y) != TileType::Wall { | |
pos.x = new_x; | |
pos.y = new_y; | |
} | |
} | |
} | |
fn player_input(gs: &mut State, rltk: &mut Rltk) { | |
let game_map = &gs.resources.get::<GameMap>().unwrap(); | |
if let Some(key) = rltk.key { | |
match key { | |
VirtualKeyCode::H | | |
VirtualKeyCode::Left => try_move_player(-1, 0, &mut gs.world, game_map), | |
VirtualKeyCode::L | | |
VirtualKeyCode::Right => try_move_player(1, 0, &mut gs.world, game_map), | |
VirtualKeyCode::K | | |
VirtualKeyCode::Up => try_move_player(0, -1, &mut gs.world, game_map), | |
VirtualKeyCode::J | | |
VirtualKeyCode::Down => try_move_player(0, 1, &mut gs.world, game_map), | |
_ => {} | |
} | |
} | |
} | |
fn main() -> rltk::BError { | |
use rltk::RltkBuilder; | |
let context = RltkBuilder::simple80x50() | |
.with_title("Roguelike Tutorial") | |
.build()?; | |
let mut gs = State { | |
world: World::default(), | |
resources: Resources::default(), | |
schedule: Schedule::builder().build(), | |
}; | |
gs.resources.insert(GameMap::new()); | |
let player = gs.world.push(( | |
Player {}, | |
Position { | |
x: 80 / 2, | |
y: 50 / 2, | |
}, | |
Renderable { | |
glyph: rltk::to_cp437('@'), | |
fg: RGB::named(rltk::YELLOW), | |
bg: RGB::named(rltk::BLACK), | |
}, | |
)); | |
for i in 0..10 { | |
gs.world.push(( | |
Position { x: i * 7, y: 20 }, | |
Renderable { | |
glyph: rltk::to_cp437('☺'), | |
fg: RGB::named(rltk::RED), | |
bg: RGB::named(rltk::BLACK), | |
}, | |
)); | |
} | |
rltk::main_loop(context, gs) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use rltk::{GameState, Rltk, VirtualKeyCode, RGB}; | |
use std::cmp::{max, min}; | |
mod map; | |
pub use map::*; | |
#[derive(PartialEq, Copy, Clone)] | |
struct Position { | |
x: i32, | |
y: i32, | |
} | |
struct Renderable { | |
glyph: rltk::FontCharType, | |
fg: RGB, | |
bg: RGB, | |
} | |
struct GameObject { | |
is_player: bool, | |
pos: Option<Position>, | |
render: Option<Renderable>, | |
} | |
struct State { | |
world: Vec<GameObject>, | |
game_map: GameMap, | |
} | |
impl GameState for State { | |
fn tick(&mut self, rltk: &mut Rltk) { | |
// Simulation | |
player_input(self, rltk); | |
// Rendering | |
rltk.cls(); | |
draw_map(&self.game_map, rltk); | |
for game_object in self.world.iter() { | |
if let GameObject{pos: Some(pos), render: Some(render), ..} = game_object { | |
rltk.set(pos.x, pos.y, render.fg, render.bg, render.glyph); | |
} | |
} | |
rltk.print(1, 1, "Hello Rust World"); | |
} | |
} | |
fn draw_map(map: &GameMap, rltk: &mut Rltk) { | |
for y in 0..map.h { | |
for x in 0..map.w { | |
let (fg, bg, ch) = match map.get(x, y) { | |
TileType::Floor => (RGB::from_f32(0.5, 0.5, 0.5), RGB::from_f32(0., 0., 0.), '.'), | |
TileType::Wall => (RGB::from_f32(0.7, 0.7, 0.5), RGB::from_f32(0., 0., 0.), '#'), | |
}; | |
rltk.set(x, y, fg, bg, rltk::to_cp437(ch)); | |
} | |
} | |
} | |
fn try_move_player(delta_x: i32, delta_y: i32, world: &mut Vec<GameObject>, game_map: &GameMap) { | |
for game_object in world.iter_mut() { | |
if game_object.is_player { | |
let pos = game_object.pos.unwrap(); | |
let new_x = min(game_map.w - 1, max(0, pos.x + delta_x)); | |
let new_y = min(game_map.h - 1, max(0, pos.y + delta_y)); | |
if game_map.get(new_x, new_y) != TileType::Wall { | |
game_object.pos = Some(Position{x: new_x, y: new_y}); | |
} | |
} | |
} | |
} | |
fn player_input(gs: &mut State, rltk: &mut Rltk) { | |
if let Some(key) = rltk.key { | |
match key { | |
VirtualKeyCode::H | | |
VirtualKeyCode::Left => try_move_player(-1, 0, &mut gs.world, &gs.game_map), | |
VirtualKeyCode::L | | |
VirtualKeyCode::Right => try_move_player(1, 0, &mut gs.world, &gs.game_map), | |
VirtualKeyCode::K | | |
VirtualKeyCode::Up => try_move_player(0, -1, &mut gs.world, &gs.game_map), | |
VirtualKeyCode::J | | |
VirtualKeyCode::Down => try_move_player(0, 1, &mut gs.world, &gs.game_map), | |
_ => {} | |
} | |
} | |
} | |
fn main() -> rltk::BError { | |
use rltk::RltkBuilder; | |
let context = RltkBuilder::simple80x50() | |
.with_title("Roguelike Tutorial") | |
.build()?; | |
let mut gs = State { | |
world: vec![], | |
game_map: GameMap::new(), | |
}; | |
let player = gs.world.push(GameObject{ | |
is_player: true, | |
pos: Some(Position { | |
x: 80 / 2, | |
y: 50 / 2, | |
}), | |
render: Some(Renderable { | |
glyph: rltk::to_cp437('@'), | |
fg: RGB::named(rltk::YELLOW), | |
bg: RGB::named(rltk::BLACK), | |
}), | |
}); | |
for i in 0..10 { | |
gs.world.push(GameObject{ | |
is_player: false, | |
pos: Some(Position { x: i * 7, y: 20 }), | |
render: Some(Renderable { | |
glyph: rltk::to_cp437('☺'), | |
fg: RGB::named(rltk::RED), | |
bg: RGB::named(rltk::BLACK), | |
}), | |
}); | |
} | |
rltk::main_loop(context, gs) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment