Initial-ish commit
The first commit following this tutorial. My plan was to commit and push after each section, but I've already done two. Ooops. I'll be better from here on out, I promise.
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/.idea
|
||||
/target
|
||||
64
Cargo.lock
generated
Normal file
64
Cargo.lock
generated
Normal file
@@ -0,0 +1,64 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a6577517ecd0ee0934f48a7295a89aaef3e6dfafeac404f94c0b3448518ddfe"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a"
|
||||
|
||||
[[package]]
|
||||
name = "roguelike"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"tcod",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tcod"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44e518b0661949712e8dbc6d6d9d7c00a405dd88bc539102c1edfc2d22e5e144"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"lazy_static",
|
||||
"tcod-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tcod-sys"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "730fb27d2261f7c860ae7a61c3ae70277f0836173ceeccb594193abb4fa5f4aa"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "roguelike"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
tcod = "0.15"
|
||||
BIN
arial10x10.png
Normal file
BIN
arial10x10.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
195
src/main.rs
Normal file
195
src/main.rs
Normal file
@@ -0,0 +1,195 @@
|
||||
use tcod::colors::*;
|
||||
use tcod::console::*;
|
||||
|
||||
// actual size of the window
|
||||
const SCREEN_WIDTH: i32 = 80;
|
||||
const SCREEN_HEIGHT: i32 = 50;
|
||||
|
||||
// size of the map
|
||||
const MAP_WIDTH: i32 = 80;
|
||||
const MAP_HEIGHT: i32 = 45;
|
||||
const COLOR_DARK_WALL: Color = Color { r: 0, g: 0, b: 100 };
|
||||
const COLOR_DARK_GROUND: Color = Color {
|
||||
r: 50,
|
||||
g: 50,
|
||||
b: 150,
|
||||
};
|
||||
|
||||
// 20 FPS max
|
||||
const LIMIT_FPS: i32 = 20;
|
||||
|
||||
struct Tcod {
|
||||
root: Root,
|
||||
con: Offscreen,
|
||||
}
|
||||
fn main() {
|
||||
let root = Root::initializer()
|
||||
.font("arial10x10.png", FontLayout::Tcod)
|
||||
.font_type(FontType::Greyscale)
|
||||
.size(SCREEN_WIDTH, SCREEN_HEIGHT)
|
||||
.title("Rust/libtcod tutorial")
|
||||
.init();
|
||||
|
||||
let con = Offscreen::new(MAP_WIDTH, MAP_HEIGHT);
|
||||
|
||||
let mut tcod = Tcod { root, con };
|
||||
tcod::system::set_fps(LIMIT_FPS);
|
||||
|
||||
let mut player_x = SCREEN_WIDTH / 2;
|
||||
let mut player_y = SCREEN_HEIGHT / 2;
|
||||
|
||||
// create object representing the player
|
||||
let player = Object::new(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, '@', WHITE);
|
||||
// create an NPC
|
||||
let npc = Object::new(SCREEN_WIDTH / 2 - 5, SCREEN_HEIGHT / 2, '@', YELLOW);
|
||||
// the list of objects with the two above
|
||||
let mut objects = [player, npc];
|
||||
|
||||
// Generate map
|
||||
let game = Game { map: make_map() };
|
||||
|
||||
// Main game loop
|
||||
while !tcod.root.window_closed() {
|
||||
tcod.con.clear();
|
||||
render_all(&mut tcod, &game, &objects);
|
||||
|
||||
tcod.root.flush();
|
||||
tcod.root.wait_for_keypress(true);
|
||||
|
||||
// handle kepresses
|
||||
let player = &mut objects[0];
|
||||
let exit = handle_keys(&mut tcod, &game, player);
|
||||
if exit {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle_keys() handles inputs; returns a boolean - "should we exit the game?"
|
||||
fn handle_keys(tcod: &mut Tcod, game: &Game, player: &mut Object) -> bool {
|
||||
use tcod::input::Key;
|
||||
use tcod::input::KeyCode::*;
|
||||
|
||||
let key = tcod.root.wait_for_keypress(true);
|
||||
match key {
|
||||
// toggle fullscreen
|
||||
Key {
|
||||
code: Enter,
|
||||
alt: true,
|
||||
..
|
||||
} => {
|
||||
let fullscreen = tcod.root.is_fullscreen();
|
||||
tcod.root.set_fullscreen(!fullscreen);
|
||||
}
|
||||
// exit game
|
||||
Key { code: Escape, .. } => return true,
|
||||
// movement keys
|
||||
Key { code: Up, .. } => player.move_by(0, -1, game),
|
||||
Key { code: Down, .. } => player.move_by(0, 1, game),
|
||||
Key { code: Left, .. } => player.move_by(-1, 0, game),
|
||||
Key { code: Right, .. } => player.move_by(1, 0, game),
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn render_all(tcod: &mut Tcod, game: &Game, objects: &[Object]) {
|
||||
// draw all objects in the list
|
||||
for object in objects {
|
||||
object.draw(&mut tcod.con);
|
||||
}
|
||||
|
||||
// go through all tiles and set their background color
|
||||
for y in 0..MAP_HEIGHT {
|
||||
for x in 0..MAP_WIDTH {
|
||||
let wall = game.map[x as usize][y as usize].block_sight;
|
||||
if wall {
|
||||
tcod.con
|
||||
.set_char_background(x, y, COLOR_DARK_WALL, BackgroundFlag::Set);
|
||||
} else {
|
||||
tcod.con
|
||||
.set_char_background(x, y, COLOR_DARK_GROUND, BackgroundFlag::Set);
|
||||
}
|
||||
}
|
||||
}
|
||||
blit(
|
||||
&tcod.con,
|
||||
(0, 0),
|
||||
(SCREEN_WIDTH, SCREEN_HEIGHT),
|
||||
&mut tcod.root,
|
||||
(0, 0),
|
||||
1.0,
|
||||
1.0,
|
||||
);
|
||||
}
|
||||
// This is a generic object: the player, a monster, an item, the stairs...
|
||||
// It's always represented by a character on screen.
|
||||
#[derive(Debug)]
|
||||
struct Object {
|
||||
x: i32,
|
||||
y: i32,
|
||||
char: char,
|
||||
color: Color,
|
||||
}
|
||||
|
||||
impl Object {
|
||||
pub fn new(x: i32, y: i32, char: char, color: Color) -> Self {
|
||||
Object { x, y, char, color }
|
||||
}
|
||||
|
||||
// move by the given amount, if the destination is not blocked
|
||||
pub fn move_by(&mut self, dx: i32, dy: i32, game: &Game) {
|
||||
if !game.map[(self.x + dx) as usize][(self.y + dy) as usize].blocked {
|
||||
self.x += dx;
|
||||
self.y += dy;
|
||||
}
|
||||
}
|
||||
|
||||
// set the color and then draw the character that represents this object at its position
|
||||
pub fn draw(&self, con: &mut dyn Console) {
|
||||
con.set_default_foreground(self.color);
|
||||
con.put_char(self.x, self.y, self.char, BackgroundFlag::None);
|
||||
}
|
||||
}
|
||||
|
||||
// A tile of the map and its properties
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct Tile {
|
||||
blocked: bool,
|
||||
block_sight: bool,
|
||||
}
|
||||
|
||||
impl Tile {
|
||||
pub fn empty() -> Self {
|
||||
Tile {
|
||||
blocked: false,
|
||||
block_sight: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wall() -> Self {
|
||||
Tile {
|
||||
blocked: true,
|
||||
block_sight: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Map = Vec<Vec<Tile>>;
|
||||
|
||||
struct Game {
|
||||
map: Map,
|
||||
}
|
||||
|
||||
fn make_map() -> Map {
|
||||
// fill map with "unblocked" tiles
|
||||
let mut map = vec![vec![Tile::empty(); MAP_HEIGHT as usize]; MAP_WIDTH as usize];
|
||||
|
||||
// place two pillars to test the map
|
||||
map[30][22] = Tile::wall();
|
||||
map[50][22] = Tile::wall();
|
||||
|
||||
map
|
||||
}
|
||||
Reference in New Issue
Block a user