diff options
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | game/Cargo.toml | 5 | ||||
| -rw-r--r-- | game/src/main.rs | 68 | ||||
| -rw-r--r-- | game/www/index.html | 111 | ||||
| -rw-r--r-- | game/www/style.css | 121 |
5 files changed, 231 insertions, 76 deletions
@@ -12,7 +12,7 @@ EMCC_CFLAGS := -O3 \ -sWASM=1 \ -sASYNCIFY \ -sGL_ENABLE_GET_PROC_ADDRESS=1 \ - -sEXPORTED_RUNTIME_METHODS=HEAPF32,ccall,cwrap + -sEXPORTED_RUNTIME_METHODS=HEAPF32,ccall,cwrap,callMain web: dist $(ASSETS_DST) diff --git a/game/Cargo.toml b/game/Cargo.toml index 0e64d0e..5cdf4af 100644 --- a/game/Cargo.toml +++ b/game/Cargo.toml @@ -8,6 +8,7 @@ publish.workspace = true rust-version.workspace = true [dependencies] +argh.workspace = true dungeon.workspace = true graphics.workspace = true @@ -20,7 +21,3 @@ x11 = ["graphics/x11"] wayland = ["graphics/wayland"] sdl = ["graphics/sdl"] static = ["graphics/static"] - -# desktop dependencies -[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))'.dependencies] -argh.workspace = true diff --git a/game/src/main.rs b/game/src/main.rs index a44f317..1ab49fe 100644 --- a/game/src/main.rs +++ b/game/src/main.rs @@ -1,49 +1,29 @@ -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] -mod arch { - use argh::FromArgs; - use game::Game; - use graphics::WindowBuilder; +use argh::FromArgs; +use game::Game; +use graphics::WindowBuilder; - /// Play a dungeon crawl game - #[derive(FromArgs)] - struct Args { - /// enable vsync - #[argh(switch)] - vsync: bool, - /// enable verbose logging - #[argh(switch, short = 'v')] - verbose: bool, - /// set the map seed - #[argh(option)] - seed: Option<u64>, - } - - pub fn main() -> graphics::Result<()> { - // Parse arguments - let args: Args = argh::from_env(); - // Load the window - let window = WindowBuilder::new() - .vsync(args.vsync) - .verbose(args.verbose) - .build()?; - Game::new(window, args.seed).run(); - Ok(()) - } -} - -#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] -mod arch { - use game::Game; - use graphics::WindowBuilder; - - pub fn main() -> graphics::Result<()> { - // Load the window - let window = WindowBuilder::new().build()?; - Game::new(window, None).run(); - Ok(()) - } +/// Play a dungeon crawl game +#[derive(FromArgs)] +struct Args { + /// enable vsync + #[argh(switch)] + vsync: bool, + /// enable verbose logging + #[argh(switch, short = 'v')] + verbose: bool, + /// set the map seed + #[argh(option)] + seed: Option<u64>, } pub fn main() -> graphics::Result<()> { - arch::main() + // Parse arguments + let args: Args = argh::from_env(); + // Load the window + let window = WindowBuilder::new() + .vsync(args.vsync) + .verbose(args.verbose) + .build()?; + Game::new(window, args.seed).run(); + Ok(()) } diff --git a/game/www/index.html b/game/www/index.html index 2181c25..123f6a3 100644 --- a/game/www/index.html +++ b/game/www/index.html @@ -7,38 +7,95 @@ <meta property="og:title" content="Dungeon Crawl"> <meta property="og:description" content="Dungeon Crawl game!"> <title>Dungeon Crawl</title> - <style> - * { - margin: 0; - padding: none; - border: none; + <link rel="stylesheet" href="/style.css"> + </head> + <body id="body"> + <div id="options"> + <details id="logs_details"> + <summary>Logs</summary> + <div class="menu"> + <label>Logs</label> + <div id="logs"></div> + </div> + </details> + + <button onclick="sendKey(114)">Toggle Debug</button> + + <form onsubmit="play(event)" autocomplete="off"> + <input placeholder="Seed" id="seed" /><button type="submit">Play</button> + </form> + </div> + + <canvas id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas> + + <script type='text/javascript'> + var canvas = document.querySelector('#canvas'); + var logs = document.querySelector('#logs'); + var seed = document.querySelector('#seed'); + var loaded = false; + + function outputLog(...args) { + let text = args.join(' '); + let span = document.createElement('span'); + span.innerText = text; + logs.appendChild(span); + console.log(text) + } + + function errorLog(...args) { + let text = args.join(' '); + let span = document.createElement('span'); + span.innerText = text; + span.classList.add('error') + logs.appendChild(span); + console.error(text) + document.querySelector('#logs_details').open = true; + } + + function sendKey(keyCode) { + canvas.dispatchEvent(new KeyboardEvent("keydown", {keyCode})); + setTimeout(() => { + canvas.dispatchEvent(new KeyboardEvent("keyup", {keyCode})); + }, 100); + } + + function onRuntimeInitialized() { + loaded = true; + } + + function play(e) { + e.preventDefault(); + + let seed_text = seed.value.trim(); + let seed_num = Number(seed_text); + let args = []; + + if (seed_text != '' && Number.isInteger(seed_num)) { + args.push('--seed'); + args.push(String(seed_num)); + } + + outputLog('Using args:', args) + + if (!loaded) { + errorLog("Game has not yet loaded") + } + + seed.parentElement.remove(); + + Module.callMain(args) } - canvas { - width: 100%; - height: 100%; - display: block; - background: black; - } - </style> - </head> - <body> - <canvas id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas> - <script type='text/javascript'> var Module = { - canvas: (function () { - var canvas = document.querySelector('#canvas'); - canvas.addEventListener("webglcontextlost", function (e) { - alert('WebGL context lost. You will need to reload the page.'); - e.preventDefault(); - }, false); - return canvas; - })(), - print: console.log, - printErr: console.error, - setStatus: console.debug, + canvas, + print: outputLog, + printErr: errorLog, + noInitialRun: true, + onRuntimeInitialized, }; </script> <script src="game.js"></script> + <script> + </script> </body> </html> diff --git a/game/www/style.css b/game/www/style.css new file mode 100644 index 0000000..3adf108 --- /dev/null +++ b/game/www/style.css @@ -0,0 +1,121 @@ +:root { + /* basic colors */ + --bg: #334; + --fg: #faf9f8; + --error: #f9a; + + /* button */ + --button-bg: #667; + --button-fg: var(--fg); + --button-border: #def; + --button-hover: #556; + + /* surface elements */ + --surface-bg: #445; + --surface-fg: var(--fg); +} + +* { + box-sizing: border-box; + font-family: monospace; + font-size: 16px; +} + +body, html { + height: 100%; + margin: 0; + padding: 0; + overflow: hidden; + background: black; +} + +#canvas { + width: 100%; +} + +#options { + background: var(--bg); + color: var(--fg); + position: relative; + width: 100%; + padding: 10px; + display: flex; + flex-direction: row; + + details, button { + background: var(--button-bg); + color: var(--button-fg); + border: 1px solid var(--button-bg); + width: fit-content; + margin-right: 10px; + + &:hover { + border: 1px solid var(--button-border); + background: var(--button-hover); + cursor: pointer; + } + } + + input { + margin: 0; + background: var(--surface-bg); + color: var(--surface-fg); + boder: none; + outline: none; + box-shadow: none; + } + + details summary, button, input { + padding: 10px; + font-weight: normal; + } + +} + +form { + padding: 0; + margin: 0; +} + +details { + ::marker { + content: ""; + } + + .menu { + pointer-events: all; + position: absolute; + margin: 10px; + padding: 10px; + top: 100%; + height: fit-content; + overflow: auto; + max-height: 40vh; + background: var(--bg); + color: var(--fg); + border-radius: 5px; + box-shadow: 0 0 4px 1px #00000088; + + label { + padding-bottom: 5px; + } + } +} + +#logs { + width: 40vw; + height: 200px; + font-size: 15px; + background-color: var(--surface-bg); + color: var(--surface-fg); + border: none; + padding: 5px; + display: flex; + flex-direction: column; + overflow-y: auto; + border-radius: 5px; + + .error { + color: var(--error); + } +} |