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
|
||||
|
||||
[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() {
|
||||
println!("Hello, world!");
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
|
||||
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