Download and place your font here. https://github.com/libtcod/python-tcod/tree/master/fonts/libtcod
VIDEO: https://youtu.be/1oSnLVE3YbA
Download and place your font here. https://github.com/libtcod/python-tcod/tree/master/fonts/libtcod
VIDEO: https://youtu.be/1oSnLVE3YbA
[package] | |
name = "specs-roguelike" | |
version = "0.1.0" | |
authors = ["youCodeThings"] | |
edition = "2018" | |
[dependencies] | |
tcod = "0.13" | |
specs = "0.14.0" |
use specs::{ | |
world::Builder, Component, Read, ReadStorage, System, SystemData, VecStorage, World, WriteStorage, | |
}; | |
use tcod::colors; | |
use tcod::console::*; | |
use tcod::input::{Key, KeyCode}; | |
const SCREEN_WIDTH: i32 = 40; | |
const SCREEN_HEIGHT: i32 = 25; | |
const LIMIT_FPS: i32 = 20; | |
#[derive(Debug, PartialEq)] | |
struct Position { | |
x: i32, | |
y: i32, | |
} | |
impl Component for Position { | |
type Storage = VecStorage<Self>; | |
} | |
struct CharacterGlyph { | |
glyph: char, | |
} | |
impl Component for CharacterGlyph { | |
type Storage = VecStorage<Self>; | |
} | |
#[derive(Debug, Default)] | |
struct PrintMeTag; | |
impl Component for PrintMeTag { | |
type Storage = specs::NullStorage<Self>; | |
} | |
#[derive(Debug, Default)] | |
struct PlayerController; | |
impl Component for PlayerController { | |
type Storage = specs::NullStorage<Self>; | |
} | |
#[derive(Debug, Default)] | |
struct GameState { | |
end: bool, | |
keyPress: Option<KeyCode>, | |
} | |
struct PrintingSystem; | |
impl<'a> System<'a> for PrintingSystem { | |
type SystemData = ( | |
ReadStorage<'a, Position>, | |
ReadStorage<'a, PrintMeTag>, | |
Read<'a, GameState>, | |
); | |
fn run(&mut self, data: Self::SystemData) { | |
use specs::Join; | |
let (position, print_me, game_state) = data; | |
println!("{:?}", *game_state); | |
for (pos, _) in (&position, &print_me).join() { | |
println!("{:?}", pos); | |
} | |
} | |
} | |
struct PlayerMove; | |
impl<'a> System<'a> for PlayerMove { | |
type SystemData = ( | |
WriteStorage<'a, Position>, | |
ReadStorage<'a, PlayerController>, | |
Read<'a, GameState>, | |
); | |
fn run(&mut self, data: Self::SystemData) { | |
use specs::Join; | |
use KeyCode::*; | |
let (mut position, player_controlled, game_state) = data; | |
if let Some(key) = game_state.keyPress { | |
for (pos, _) in (&mut position, &player_controlled).join() { | |
match key { | |
Up => pos.y -= 1, | |
Down => pos.y += 1, | |
Left => pos.x -= 1, | |
Right => pos.x += 1, | |
_ => {} | |
} | |
} | |
} | |
} | |
} | |
struct TcodSystem { | |
window: Root, | |
} | |
impl<'a> System<'a> for TcodSystem { | |
type SystemData = ( | |
ReadStorage<'a, CharacterGlyph>, | |
ReadStorage<'a, Position>, | |
specs::Write<'a, GameState>, | |
); | |
fn run(&mut self, data: Self::SystemData) { | |
use specs::Join; | |
use KeyCode::*; | |
let root = &mut self.window; | |
let (sprites, positions, mut game_state) = data; | |
root.clear(); | |
for (sprite, pos) in (&sprites, &positions).join() { | |
root.put_char(pos.x, pos.y, sprite.glyph, BackgroundFlag::None); | |
} | |
root.flush(); | |
let key = root.wait_for_keypress(false); | |
let key_press = match key { | |
Key { code: Escape, .. } => { | |
game_state.end = true; | |
None | |
} | |
Key { code: Up, .. } => Some(Up), | |
Key { code: Down, .. } => Some(Down), | |
Key { code: Left, .. } => Some(Left), | |
Key { code: Right, .. } => Some(Right), | |
_ => None, | |
}; | |
game_state.keyPress = key_press; | |
game_state.end = game_state.end || root.window_closed(); | |
} | |
} | |
fn main() { | |
let mut root = Root::initializer() | |
.font("terminal16x16_gs_ro.png", FontLayout::AsciiInRow) | |
.font_type(FontType::Greyscale) | |
.size(SCREEN_WIDTH, SCREEN_HEIGHT) | |
.title("Roguelike using specs") | |
.init(); | |
root.set_default_foreground(colors::WHITE); | |
tcod::system::set_fps(LIMIT_FPS); | |
let mut world = World::new(); | |
world.add_resource(GameState::default()); | |
let mut dispatcher = specs::DispatcherBuilder::new() | |
.with(PrintingSystem, "print_sys", &[]) | |
.with(PlayerMove, "player_move", &[]) | |
.with_thread_local(TcodSystem { window: root }) | |
.build(); | |
dispatcher.setup(&mut world.res); | |
world | |
.create_entity() | |
.with(Position { x: 10, y: 10 }) | |
.with(CharacterGlyph { glyph: 'y' }) | |
.build(); | |
world | |
.create_entity() | |
.with(Position { x: 23, y: 10 }) | |
.with(CharacterGlyph { glyph: 'x' }) | |
.build(); | |
world | |
.create_entity() | |
.with(Position { x: 1, y: 3 }) | |
.with(CharacterGlyph { glyph: 'A' }) | |
.build(); | |
world | |
.create_entity() | |
.with(Position { x: 11, y: 22 }) | |
.with(CharacterGlyph { glyph: '@' }) | |
.with(PlayerController {}) | |
.build(); | |
loop { | |
dispatcher.dispatch(&mut world.res); | |
println!("press key"); | |
{ | |
let game_state = world.read_resource::<GameState>(); | |
if game_state.end { | |
break; | |
} | |
} | |
world.maintain(); | |
} | |
} |
I found a solution, my system had broken packages.
Instead of trying to install all the packages with apt-get
I used Aptitude and it offered to downgrade some packages to fix the issue and it worked.
$ sudo aptitude install libsdl2-dev
The following NEW packages will be installed:
...
The following packages have unmet dependencies:
...
The following actions will resolve these dependencies:
...
Keep the following packages at their current version:
1) libasound2-dev [Not Installed]
2) libpulse-dev [Not Installed]
3) libsdl2-dev [Not Installed]
4) libudev-dev [Not Installed]
Accept this solution? [Y/n/q/?] n
The following actions will resolve these dependencies:
...
Downgrade the following packages:
...
Accept this solution? [Y/n/q/?] Y
The following packages will be DOWNGRADED:
...
This works out of the box with the latest specs version as of writing, 0.17.0
use specs::{
prelude::*, world::Builder, Component, Read, ReadStorage, System, SystemData, VecStorage, World, WriteStorage,
};
use tcod::colors;
use tcod::console::*;
use tcod::input::{Key, KeyCode};
const SCREEN_WIDTH: i32 = 40;
const SCREEN_HEIGHT: i32 = 25;
const LIMIT_FPS: i32 = 20;
#[derive(Debug, PartialEq)]
struct Position {
x: i32,
y: i32,
}
impl Component for Position {
type Storage = VecStorage<Self>;
}
struct CharacterGlyph {
glyph: char,
}
impl Component for CharacterGlyph {
type Storage = VecStorage<Self>;
}
#[derive(Debug, Default)]
struct PrintMeTag;
impl Component for PrintMeTag {
type Storage = specs::NullStorage<Self>;
}
#[derive(Debug, Default)]
struct PlayerController;
impl Component for PlayerController {
type Storage = specs::NullStorage<Self>;
}
#[derive(Debug, Default)]
struct GameState {
end: bool,
keyPress: Option<KeyCode>,
}
struct PrintingSystem;
impl<'a> System<'a> for PrintingSystem {
type SystemData = (
ReadStorage<'a, Position>,
ReadStorage<'a, PrintMeTag>,
Read<'a, GameState>,
);
fn run(&mut self, data: Self::SystemData) {
use specs::Join;
let (position, print_me, game_state) = data;
println!("{:?}", *game_state);
for (pos, _) in (&position, &print_me).join() {
println!("{:?}", pos);
}
}
}
struct PlayerMove;
impl<'a> System<'a> for PlayerMove {
type SystemData = (
WriteStorage<'a, Position>,
ReadStorage<'a, PlayerController>,
Read<'a, GameState>,
);
fn run(&mut self, data: Self::SystemData) {
use specs::Join;
use KeyCode::*;
let (mut position, player_controlled, game_state) = data;
if let Some(key) = game_state.keyPress {
for (pos, _) in (&mut position, &player_controlled).join() {
match key {
Up => pos.y -= 1,
Down => pos.y += 1,
Left => pos.x -= 1,
Right => pos.x += 1,
_ => {}
}
}
}
}
}
struct TcodSystem {
window: Root,
}
impl<'a> System<'a> for TcodSystem {
type SystemData = (
ReadStorage<'a, CharacterGlyph>,
ReadStorage<'a, Position>,
specs::Write<'a, GameState>,
);
fn run(&mut self, data: Self::SystemData) {
use specs::Join;
use KeyCode::*;
let root = &mut self.window;
let (sprites, positions, mut game_state) = data;
root.clear();
for (sprite, pos) in (&sprites, &positions).join() {
root.put_char(pos.x, pos.y, sprite.glyph, BackgroundFlag::None);
}
root.flush();
let key = root.wait_for_keypress(false);
let key_press = match key {
Key { code: Escape, .. } => {
game_state.end = true;
None
}
Key { code: Up, .. } => Some(Up),
Key { code: Down, .. } => Some(Down),
Key { code: Left, .. } => Some(Left),
Key { code: Right, .. } => Some(Right),
_ => None,
};
game_state.keyPress = key_press;
game_state.end = game_state.end || root.window_closed();
}
}
fn main() {
let mut root = Root::initializer()
.font("terminal16x16_gs_ro.png", FontLayout::AsciiInRow)
.font_type(FontType::Greyscale)
.size(SCREEN_WIDTH, SCREEN_HEIGHT)
.title("Roguelike using specs")
.init();
root.set_default_foreground(colors::WHITE);
tcod::system::set_fps(LIMIT_FPS);
let mut world = World::new();
world.insert(GameState::default());
let mut dispatcher = specs::DispatcherBuilder::new()
.with(PrintingSystem, "print_sys", &[])
.with(PlayerMove, "player_move", &[])
.with_thread_local(TcodSystem { window: root })
.build();
dispatcher.setup(&mut world);
world
.create_entity()
.with(Position { x: 10, y: 10 })
.with(CharacterGlyph { glyph: 'y' })
.build();
world
.create_entity()
.with(Position { x: 23, y: 10 })
.with(CharacterGlyph { glyph: 'x' })
.build();
world
.create_entity()
.with(Position { x: 1, y: 3 })
.with(CharacterGlyph { glyph: 'A' })
.build();
world
.create_entity()
.with(Position { x: 11, y: 22 })
.with(CharacterGlyph { glyph: '@' })
.with(PlayerController {})
.build();
loop {
dispatcher.dispatch(&mut world);
println!("press key");
{
let game_state = world.read_resource::<GameState>();
if game_state.end {
break;
}
}
world.maintain();
}
}
I did not make any modifications, but somehow the build fails :(
rustc 1.34.1