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:
2024-01-16 22:29:34 -05:00
commit f8a9cc5d75
5 changed files with 270 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/.idea
/target

64
Cargo.lock generated Normal file
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

195
src/main.rs Normal file
View 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
}