WIP
This commit is contained in:
parent
0befb6d183
commit
a15c31d241
1779
Cargo.lock
generated
Normal file
1779
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -6,3 +6,5 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bracket-lib = "0.8.1"
|
||||||
|
getrandom = { version = "0.2", features = ["js"] }
|
||||||
|
|
11
makefile
Normal file
11
makefile
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
build: ; cargo build
|
||||||
|
|
||||||
|
build-release: ; cargo build --release
|
||||||
|
|
||||||
|
build-wasm:
|
||||||
|
cargo build --release --target wasm32-unknown-unknown
|
||||||
|
wasm-bindgen target/wasm32-unknown-unknown/release/dungeoncrawl.wasm --out-dir target/dungeoncrawl --no-modules --no-typescript
|
||||||
|
cp src/index.html target/dungeoncrawl
|
||||||
|
upload target/dungeoncrawl
|
||||||
|
|
||||||
|
format: ; cargo fmt
|
73
src/index.html
Normal file
73
src/index.html
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
|
||||||
|
<title>Dungeon Crawl by lyte.dev</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="canvas" width="640" height="480"></canvas>
|
||||||
|
<section id="about">
|
||||||
|
<h1>Dungeon Crawl</h1>
|
||||||
|
<p>
|
||||||
|
A tiny roguelike written in rust for funsies and compiled to
|
||||||
|
webassembly so you can play it in your browser without having to
|
||||||
|
download <em>anything</em>.
|
||||||
|
</p>
|
||||||
|
<h3>Links</h3>
|
||||||
|
<ul>
|
||||||
|
<li><a href="//git.lyte.dev/lytedev/rust-dungeoncrawl">Source Code</a></li>
|
||||||
|
<li><a href="//files.lyte.dev/uploads/dungeoncrawl">Play</a></li>
|
||||||
|
</ul>
|
||||||
|
<h3>Controls</h3>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
WASD -> Move
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
<script src="./dungeoncrawl.js"></script>
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", async () => {
|
||||||
|
await wasm_bindgen("./dungeoncrawl_bg.wasm");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body, html {
|
||||||
|
background-color: #111;
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
max-width: 100vw;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
font-family: sans-serif;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
canvas { max-height: 100vh; max-width: 100vw; }
|
||||||
|
a { color: #0af; margin-bottom: 1em; }
|
||||||
|
section#about {
|
||||||
|
width: 60ch;
|
||||||
|
text-align: left;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
section#about > * {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
section#about > h1,
|
||||||
|
section#about > h2,
|
||||||
|
section#about > h3,
|
||||||
|
section#about > h4,
|
||||||
|
section#about > h5,
|
||||||
|
section#about > h6 {
|
||||||
|
margin-top: 1.5em;
|
||||||
|
}
|
||||||
|
ul, ol {
|
||||||
|
padding-left: 1.2em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</body>
|
||||||
|
</html>
|
48
src/main.rs
48
src/main.rs
|
@ -1,3 +1,47 @@
|
||||||
fn main() {
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
println!("Hello, world!");
|
|
||||||
|
mod map;
|
||||||
|
mod player;
|
||||||
|
|
||||||
|
mod prelude {
|
||||||
|
pub use bracket_lib::prelude::*;
|
||||||
|
pub const SCREEN_WIDTH: i32 = 80;
|
||||||
|
pub const SCREEN_HEIGHT: i32 = 50;
|
||||||
|
pub use crate::map::*;
|
||||||
|
pub use crate::player::*;
|
||||||
|
}
|
||||||
|
|
||||||
|
use prelude::*;
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
map: Map,
|
||||||
|
player: Player,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
map: Map::new(None, None),
|
||||||
|
player: Player::new(Point::new(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GameState for State {
|
||||||
|
fn tick(&mut self, ctx: &mut BTerm) {
|
||||||
|
ctx.cls();
|
||||||
|
self.map.render(ctx);
|
||||||
|
self.player.render(ctx);
|
||||||
|
self.player.update(ctx, &self.map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> BError {
|
||||||
|
let context = BTermBuilder::simple80x50()
|
||||||
|
.with_title("Dungeon Crawler")
|
||||||
|
.with_fps_cap(60.0)
|
||||||
|
.build()?;
|
||||||
|
|
||||||
|
println!("Game starting...");
|
||||||
|
main_loop(context, State::new())
|
||||||
}
|
}
|
||||||
|
|
82
src/map.rs
Normal file
82
src/map.rs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub enum TileKind {
|
||||||
|
Wall,
|
||||||
|
Floor,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Tile {
|
||||||
|
kind: TileKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tile {
|
||||||
|
pub fn new(kind: TileKind) -> Self {
|
||||||
|
Self {
|
||||||
|
kind,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_point(&self, ctx: &mut BTerm, p: Point) {
|
||||||
|
self.render(ctx, p.x, p.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self, ctx: &mut BTerm, x: i32, y: i32) {
|
||||||
|
match self.kind {
|
||||||
|
TileKind::Floor => ctx.set(x, y, WHITE, BLACK, to_cp437(' ')),
|
||||||
|
TileKind::Wall => ctx.set(x, y, WHITE, BLACK, to_cp437('#')),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn can_enter(&self) -> bool {
|
||||||
|
match self.kind {
|
||||||
|
TileKind::Floor => true,
|
||||||
|
TileKind::Wall => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Map {
|
||||||
|
pub tiles: Vec<Tile>,
|
||||||
|
pub width: i32,
|
||||||
|
pub height: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Map {
|
||||||
|
pub fn new(width: Option<i32>, height: Option<i32>) -> Self {
|
||||||
|
let actual_width = width.unwrap_or(SCREEN_WIDTH);
|
||||||
|
let actual_height = height.unwrap_or(SCREEN_HEIGHT);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
tiles: vec![Tile::new(TileKind::Floor); (actual_width * actual_height) as usize],
|
||||||
|
width: actual_width,
|
||||||
|
height: actual_height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tile_at_point(&self, p: Point) -> &Tile {
|
||||||
|
self.tile_at(p.x, p.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tile_at(&self, x: i32, y: i32) -> &Tile {
|
||||||
|
&(self.tiles[((y * self.width) + x) as usize])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_in_bounds_point(&self, p: Point) -> bool {
|
||||||
|
self.is_in_bounds(p.x, p.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_in_bounds(&self, x: i32, y: i32) -> bool {
|
||||||
|
x >= 0 && x < self.width && y >= 0 && y < self.height
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this will need a given set of coords to look at?
|
||||||
|
pub fn render(&self, ctx: &mut BTerm) {
|
||||||
|
for y in 0..SCREEN_HEIGHT {
|
||||||
|
for x in 0..SCREEN_WIDTH {
|
||||||
|
self.tile_at(x, y).render(ctx, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
src/player.rs
Normal file
35
src/player.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub struct Player {
|
||||||
|
pub position: Point,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Player {
|
||||||
|
pub fn new(position: Point) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self, ctx: &mut BTerm) {
|
||||||
|
ctx.set(self.position.x, self.position.y, GREEN, BLACK, to_cp437('@'));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, ctx: &mut BTerm, map: &Map) {
|
||||||
|
if let Some(key) = ctx.key {
|
||||||
|
let delta = match key {
|
||||||
|
VirtualKeyCode::A => Point::new(-1, 0),
|
||||||
|
VirtualKeyCode::S => Point::new(0, 1),
|
||||||
|
VirtualKeyCode::D => Point::new(1, 0),
|
||||||
|
VirtualKeyCode::W => Point::new(0, -1),
|
||||||
|
_ => Point::zero(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_position = self.position + delta;
|
||||||
|
|
||||||
|
if map.is_in_bounds_point(new_position) && map.tile_at_point(new_position).can_enter() {
|
||||||
|
self.position = new_position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue