more input info
This commit is contained in:
parent
2c200d6d11
commit
0fe73b6f3e
|
|
@ -1,141 +0,0 @@
|
||||||
import type { Message, InputState } from "../shared/types.js"
|
|
||||||
import { GameContext } from "../shared/game.js"
|
|
||||||
import { focusInput } from "./focus.js"
|
|
||||||
import { $$, scrollback } from "./dom.js"
|
|
||||||
import { randomId } from "../shared/utils.js"
|
|
||||||
import { setStatus, addOutput } from "./scrollback.js"
|
|
||||||
import { browserCommands } from "./commands.js"
|
|
||||||
|
|
||||||
const FPS = 30
|
|
||||||
const HEIGHT = 540
|
|
||||||
const WIDTH = 980
|
|
||||||
|
|
||||||
type Game = { init?: () => void, update?: (delta: number, input: InputState) => void, draw?: (ctx: GameContext) => void }
|
|
||||||
|
|
||||||
let oldMode = "cinema"
|
|
||||||
let running = false
|
|
||||||
let canvas: HTMLCanvasElement
|
|
||||||
const pressedStack = new Set<string>()
|
|
||||||
|
|
||||||
let pressed: InputState = {
|
|
||||||
key: "",
|
|
||||||
shift: false,
|
|
||||||
ctrl: false,
|
|
||||||
meta: false,
|
|
||||||
pressed: pressedStack
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function handleGameStart(msg: Message) {
|
|
||||||
const msgId = msg.id as string
|
|
||||||
const name = msg.data as string
|
|
||||||
|
|
||||||
let game
|
|
||||||
try {
|
|
||||||
game = await import(`/command/${name}`)
|
|
||||||
} catch (err: any) {
|
|
||||||
setStatus(msgId, "error")
|
|
||||||
addOutput(msgId, `Error: ${err.message ? err.message : err}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.body.dataset.mode === "tall") {
|
|
||||||
browserCommands.mode?.()
|
|
||||||
oldMode = "tall"
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas = createCanvas()
|
|
||||||
canvas.focus()
|
|
||||||
setStatus(msgId, "ok")
|
|
||||||
canvas.addEventListener("keydown", handleKeydown)
|
|
||||||
canvas.addEventListener("keyup", handleKeyup)
|
|
||||||
window.addEventListener("resize", resizeCanvas)
|
|
||||||
resizeCanvas()
|
|
||||||
gameLoop(new GameContext(canvas.getContext("2d")!), game)
|
|
||||||
}
|
|
||||||
|
|
||||||
function createCanvas(): HTMLCanvasElement {
|
|
||||||
const canvas = $$("canvas.game.active") as HTMLCanvasElement
|
|
||||||
canvas.id = randomId()
|
|
||||||
canvas.height = HEIGHT
|
|
||||||
canvas.width = WIDTH
|
|
||||||
canvas.tabIndex = 0
|
|
||||||
|
|
||||||
const main = document.querySelector("main")
|
|
||||||
main?.parentNode?.insertBefore(canvas, main)
|
|
||||||
|
|
||||||
return canvas
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleKeydown(e: KeyboardEvent) {
|
|
||||||
e.preventDefault()
|
|
||||||
|
|
||||||
if (e.key === "Escape" || (e.ctrlKey && e.key === "c")) {
|
|
||||||
endGame()
|
|
||||||
} else {
|
|
||||||
pressedStack.add(e.key)
|
|
||||||
pressed.key = e.key
|
|
||||||
pressed.ctrl = e.ctrlKey
|
|
||||||
pressed.shift = e.shiftKey
|
|
||||||
pressed.meta = e.metaKey
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleKeyup(e: KeyboardEvent) {
|
|
||||||
pressedStack.delete(e.key)
|
|
||||||
if (pressedStack.size === 0) {
|
|
||||||
pressed.key = ""
|
|
||||||
pressed.ctrl = false
|
|
||||||
pressed.shift = false
|
|
||||||
pressed.meta = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function resizeCanvas() {
|
|
||||||
const scale = Math.min(
|
|
||||||
window.innerWidth / 960,
|
|
||||||
window.innerHeight / 540
|
|
||||||
)
|
|
||||||
|
|
||||||
canvas.width = 960 * scale
|
|
||||||
canvas.height = 540 * scale
|
|
||||||
|
|
||||||
const ctx = canvas.getContext("2d")!
|
|
||||||
ctx.setTransform(scale, 0, 0, scale, 0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
function gameLoop(ctx: GameContext, game: Game) {
|
|
||||||
running = true
|
|
||||||
let last = 0
|
|
||||||
|
|
||||||
if (game.init) game.init()
|
|
||||||
|
|
||||||
function loop(ts: number) {
|
|
||||||
if (!running) return
|
|
||||||
|
|
||||||
const delta = ts - last
|
|
||||||
if (delta >= 1000 / FPS) {
|
|
||||||
if (game.update) game.update(delta, pressed)
|
|
||||||
if (game.draw) game.draw(ctx)
|
|
||||||
last = ts
|
|
||||||
}
|
|
||||||
requestAnimationFrame(loop)
|
|
||||||
}
|
|
||||||
|
|
||||||
requestAnimationFrame(loop)
|
|
||||||
}
|
|
||||||
|
|
||||||
function endGame() {
|
|
||||||
running = false
|
|
||||||
|
|
||||||
if (oldMode === "tall") browserCommands.mode?.()
|
|
||||||
|
|
||||||
canvas.classList.remove("active")
|
|
||||||
canvas.style.height = HEIGHT / 2 + "px"
|
|
||||||
canvas.style.width = WIDTH / 2 + "px"
|
|
||||||
|
|
||||||
const output = $$("li.output")
|
|
||||||
output.append(canvas)
|
|
||||||
scrollback.append(output)
|
|
||||||
|
|
||||||
focusInput()
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,13 @@
|
||||||
export type InputState = { key: string, shift: boolean, ctrl: boolean, meta: boolean, pressed: Set<string> }
|
export type InputState = {
|
||||||
|
key: string,
|
||||||
|
shift: boolean,
|
||||||
|
ctrl: boolean,
|
||||||
|
meta: boolean,
|
||||||
|
pressed: Set<string>,
|
||||||
|
prevPressed: Set<string>,
|
||||||
|
justPressed: Set<string>,
|
||||||
|
justReleased: Set<string>
|
||||||
|
}
|
||||||
|
|
||||||
export class GameContext {
|
export class GameContext {
|
||||||
constructor(public ctx: CanvasRenderingContext2D) { }
|
constructor(public ctx: CanvasRenderingContext2D) { }
|
||||||
|
|
@ -8,7 +17,7 @@ export class GameContext {
|
||||||
|
|
||||||
clear(color?: string) {
|
clear(color?: string) {
|
||||||
if (color)
|
if (color)
|
||||||
this.rectfill(0, 0, this.ctx.canvas.width, this.ctx.canvas.height, color)
|
this.rectfill(0, 0, this.width, this.height, color)
|
||||||
else
|
else
|
||||||
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height)
|
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user