Skip to content

Instantly share code, notes, and snippets.

@AndrewJakubowicz
Last active December 20, 2022 15:05
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AndrewJakubowicz/3cc636d10bd1dfe1abd08b990472b822 to your computer and use it in GitHub Desktop.
Save AndrewJakubowicz/3cc636d10bd1dfe1abd08b990472b822 to your computer and use it in GitHub Desktop.
Specs Roguelike
[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();
}
}
@kasparsbergs
Copy link

  Compiling parking_lot v0.6.4
error: failed to run custom build command for `tcod-sys v5.0.0`
process didn't exit successfully: `/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-b43a76a86185cb38/build-script-build` (exit code: 101)
--- stdout
TARGET = Some("x86_64-unknown-linux-gnu")
OPT_LEVEL = Some("0")
HOST = Some("x86_64-unknown-linux-gnu")
CC_x86_64-unknown-linux-gnu = None
CC_x86_64_unknown_linux_gnu = None
HOST_CC = None
CC = None
CFLAGS_x86_64-unknown-linux-gnu = None
CFLAGS_x86_64_unknown_linux_gnu = None
HOST_CFLAGS = None
CFLAGS = None
CRATE_CC_NO_DEFAULTS = None
DEBUG = Some("true")
CARGO_CFG_TARGET_FEATURE = Some("fxsr,sse,sse2")
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/adler32.o" "-c" "libtcod/src/zlib/adler32.c"
exit code: 0
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/crc32.o" "-c" "libtcod/src/zlib/crc32.c"
exit code: 0
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/deflate.o" "-c" "libtcod/src/zlib/deflate.c"
exit code: 0
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/infback.o" "-c" "libtcod/src/zlib/infback.c"
exit code: 0
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/inffast.o" "-c" "libtcod/src/zlib/inffast.c"
exit code: 0
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/inflate.o" "-c" "libtcod/src/zlib/inflate.c"
exit code: 0
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/inftrees.o" "-c" "libtcod/src/zlib/inftrees.c"
exit code: 0
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/trees.o" "-c" "libtcod/src/zlib/trees.c"
exit code: 0
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/zutil.o" "-c" "libtcod/src/zlib/zutil.c"
exit code: 0
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/compress.o" "-c" "libtcod/src/zlib/compress.c"
exit code: 0
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/uncompr.o" "-c" "libtcod/src/zlib/uncompr.c"
exit code: 0
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/gzclose.o" "-c" "libtcod/src/zlib/gzclose.c"
exit code: 0
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/gzlib.o" "-c" "libtcod/src/zlib/gzlib.c"
exit code: 0
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/gzread.o" "-c" "libtcod/src/zlib/gzread.c"
exit code: 0
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-w" "-o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/gzwrite.o" "-c" "libtcod/src/zlib/gzwrite.c"
exit code: 0
AR_x86_64-unknown-linux-gnu = None
AR_x86_64_unknown_linux_gnu = None
HOST_AR = None
AR = None
running: "ar" "crs" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libz.a" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/adler32.o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/crc32.o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/deflate.o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/infback.o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/inffast.o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/inflate.o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/inftrees.o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/trees.o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/zutil.o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/compress.o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/uncompr.o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/gzclose.o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/gzlib.o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/gzread.o" "/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out/libtcod/src/zlib/gzwrite.o"
exit code: 0
cargo:rustc-link-lib=static=z
cargo:rustc-link-search=native=/home/kb/practice/rust/specs_roguelike/target/debug/build/tcod-sys-965b83fccad6f959/out
cargo:rustc-link-lib=static=tcod

--- stderr
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "`\"pkg-config\" \"--libs\" \"--cflags\" \"sdl2\"` did not exit successfully: exit code: 1\n--- stderr\nPackage sdl2 was not found in the pkg-config search path.\nPerhaps you should add the directory containing `sdl2.pc\'\nto the PKG_CONFIG_PATH environment variable\nNo package \'sdl2\' found\n"', src/libcore/result.rs:997:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

warning: build failed, waiting for other jobs to finish...
error: build failed

I did not make any modifications, but somehow the build fails :(
rustc 1.34.1

@kasparsbergs
Copy link

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:
 ...

@wyhinton
Copy link

wyhinton commented Jul 8, 2021

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();
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment