it's alive
This commit is contained in:
parent
68db4a923f
commit
419a8328fc
|
|
@ -1,7 +1,8 @@
|
||||||
/// <reference lib="dom" />
|
/// <reference lib="dom" />
|
||||||
export const game = true
|
export const game = true
|
||||||
|
|
||||||
import type { GameContext, InputState } from "@/shared/types"
|
import type { InputState } from "@/shared/types"
|
||||||
|
import type { GameContext } from "@/shared/game"
|
||||||
import { rng } from "@/shared/utils.ts"
|
import { rng } from "@/shared/utils.ts"
|
||||||
|
|
||||||
const WIDTH = 960
|
const WIDTH = 960
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import type { Message, InputState } from "../shared/types.js"
|
import type { Message, InputState } from "../shared/types.js"
|
||||||
import { GameContext } from "../shared/types.js"
|
import { GameContext } from "../shared/game.js"
|
||||||
import { focusInput } from "./focus.js"
|
import { focusInput } from "./focus.js"
|
||||||
import { $ } from "./dom.js"
|
import { $ } from "./dom.js"
|
||||||
import { randomId } from "../shared/utils.js"
|
import { randomId } from "../shared/utils.js"
|
||||||
|
|
@ -8,7 +8,7 @@ import { browserCommands } from "./commands.js"
|
||||||
|
|
||||||
const FPS = 30
|
const FPS = 30
|
||||||
let oldMode = "cinema"
|
let oldMode = "cinema"
|
||||||
let stopGame = false
|
let running = false
|
||||||
let canvas: HTMLCanvasElement
|
let canvas: HTMLCanvasElement
|
||||||
type Game = { init?: () => void, update?: (delta: number, input: InputState) => void, draw?: (ctx: GameContext) => void }
|
type Game = { init?: () => void, update?: (delta: number, input: InputState) => void, draw?: (ctx: GameContext) => void }
|
||||||
|
|
||||||
|
|
@ -56,7 +56,7 @@ function handleKeydown(e: KeyboardEvent) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
if (e.key === "Escape" || (e.ctrlKey && e.key === "c")) {
|
if (e.key === "Escape" || (e.ctrlKey && e.key === "c")) {
|
||||||
stopGame = true
|
running = false
|
||||||
if (oldMode === "tall") browserCommands.mode?.()
|
if (oldMode === "tall") browserCommands.mode?.()
|
||||||
canvas.classList.remove("active")
|
canvas.classList.remove("active")
|
||||||
canvas.style.height = canvas.height / 2 + "px"
|
canvas.style.height = canvas.height / 2 + "px"
|
||||||
|
|
@ -81,12 +81,13 @@ function handleKeyup(e: KeyboardEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function gameLoop(ctx: GameContext, game: Game) {
|
function gameLoop(ctx: GameContext, game: Game) {
|
||||||
|
running = true
|
||||||
let last = 0
|
let last = 0
|
||||||
|
|
||||||
if (game.init) game.init()
|
if (game.init) game.init()
|
||||||
|
|
||||||
function loop(ts: number) {
|
function loop(ts: number) {
|
||||||
if (stopGame) return
|
if (!running) return
|
||||||
|
|
||||||
const delta = ts - last
|
const delta = ts - last
|
||||||
if (delta >= 1000 / FPS) {
|
if (delta >= 1000 / FPS) {
|
||||||
|
|
|
||||||
143
app/src/shared/game.ts
Normal file
143
app/src/shared/game.ts
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
|
||||||
|
export class GameContext {
|
||||||
|
constructor(public ctx: CanvasRenderingContext2D) { }
|
||||||
|
|
||||||
|
get width() { return this.ctx.canvas.width }
|
||||||
|
get height() { return this.ctx.canvas.height }
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
circ(x: number, y: number, r: number, color = "black") {
|
||||||
|
const c = this.ctx
|
||||||
|
c.save()
|
||||||
|
c.beginPath()
|
||||||
|
c.strokeStyle = color
|
||||||
|
c.arc(x, y, r, 0, Math.PI * 2)
|
||||||
|
c.stroke()
|
||||||
|
c.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
circfill(x: number, y: number, r: number, color = "black") {
|
||||||
|
const c = this.ctx
|
||||||
|
c.save()
|
||||||
|
c.beginPath()
|
||||||
|
c.fillStyle = color
|
||||||
|
c.arc(x, y, r, 0, Math.PI * 2)
|
||||||
|
c.fill()
|
||||||
|
c.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
line(x0: number, y0: number, x1: number, y1: number, color = "black") {
|
||||||
|
const c = this.ctx
|
||||||
|
c.save()
|
||||||
|
c.beginPath()
|
||||||
|
c.strokeStyle = color
|
||||||
|
c.moveTo(x0, y0)
|
||||||
|
c.lineTo(x1, y1)
|
||||||
|
c.stroke()
|
||||||
|
c.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
oval(x0: number, y0: number, x1: number, y1: number, color = "black") {
|
||||||
|
const c = this.ctx
|
||||||
|
const w = x1 - x0
|
||||||
|
const h = y1 - y0
|
||||||
|
c.save()
|
||||||
|
c.beginPath()
|
||||||
|
c.strokeStyle = color
|
||||||
|
c.ellipse(x0 + w / 2, y0 + h / 2, Math.abs(w) / 2, Math.abs(h) / 2, 0, 0, Math.PI * 2)
|
||||||
|
c.stroke()
|
||||||
|
c.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
ovalfill(x0: number, y0: number, x1: number, y1: number, color = "black") {
|
||||||
|
const c = this.ctx
|
||||||
|
const w = x1 - x0
|
||||||
|
const h = y1 - y0
|
||||||
|
c.save()
|
||||||
|
c.beginPath()
|
||||||
|
c.fillStyle = color
|
||||||
|
c.ellipse(x0 + w / 2, y0 + h / 2, Math.abs(w) / 2, Math.abs(h) / 2, 0, 0, Math.PI * 2)
|
||||||
|
c.fill()
|
||||||
|
c.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
rect(x0: number, y0: number, x1: number, y1: number, color = "black") {
|
||||||
|
const c = this.ctx
|
||||||
|
c.save()
|
||||||
|
c.beginPath()
|
||||||
|
c.strokeStyle = color
|
||||||
|
c.rect(x0, y0, x1 - x0, y1 - y0)
|
||||||
|
c.stroke()
|
||||||
|
c.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
rectfill(x0: number, y0: number, x1: number, y1: number, color = "black") {
|
||||||
|
const c = this.ctx
|
||||||
|
c.save()
|
||||||
|
this.ctx.fillStyle = color
|
||||||
|
this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0)
|
||||||
|
c.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
rrect(x: number, y: number, w: number, h: number, r: number, color = "black") {
|
||||||
|
const c = this.ctx
|
||||||
|
c.save()
|
||||||
|
c.beginPath()
|
||||||
|
c.strokeStyle = color
|
||||||
|
this.roundRectPath(x, y, w, h, r)
|
||||||
|
c.stroke()
|
||||||
|
c.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
rrectfill(x: number, y: number, w: number, h: number, r: number, color = "black") {
|
||||||
|
const c = this.ctx
|
||||||
|
c.save()
|
||||||
|
c.beginPath()
|
||||||
|
c.fillStyle = color
|
||||||
|
this.roundRectPath(x, y, w, h, r)
|
||||||
|
c.fill()
|
||||||
|
c.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
trianglefill(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, color = "black") {
|
||||||
|
return this.polygonfill(
|
||||||
|
[
|
||||||
|
[x0, y0],
|
||||||
|
[x1, y1],
|
||||||
|
[x2, y2]
|
||||||
|
],
|
||||||
|
color
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
polygonfill(points: [number, number][], color = "black") {
|
||||||
|
if (points.length < 3) return // need at least a triangle
|
||||||
|
const c = this.ctx
|
||||||
|
c.save()
|
||||||
|
c.beginPath()
|
||||||
|
c.fillStyle = color
|
||||||
|
c.moveTo(points[0]![0], points[0]![1])
|
||||||
|
for (let i = 1; i < points.length; i++) {
|
||||||
|
c.lineTo(points[i]![0], points[i]![1])
|
||||||
|
}
|
||||||
|
c.closePath()
|
||||||
|
c.fill()
|
||||||
|
c.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
private roundRectPath(x: number, y: number, w: number, h: number, r: number) {
|
||||||
|
const c = this.ctx
|
||||||
|
c.moveTo(x + r, y)
|
||||||
|
c.lineTo(x + w - r, y)
|
||||||
|
c.quadraticCurveTo(x + w, y, x + w, y + r)
|
||||||
|
c.lineTo(x + w, y + h - r)
|
||||||
|
c.quadraticCurveTo(x + w, y + h, x + w - r, y + h)
|
||||||
|
c.lineTo(x + r, y + h)
|
||||||
|
c.quadraticCurveTo(x, y + h, x, y + h - r)
|
||||||
|
c.lineTo(x, y + r)
|
||||||
|
c.quadraticCurveTo(x, y, x + r, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,146 +17,3 @@ export type CommandResult = {
|
||||||
}
|
}
|
||||||
|
|
||||||
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> }
|
||||||
|
|
||||||
export class GameContext {
|
|
||||||
constructor(public ctx: CanvasRenderingContext2D) { }
|
|
||||||
|
|
||||||
get width() { return this.ctx.canvas.width }
|
|
||||||
get height() { return this.ctx.canvas.height }
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
circ(x: number, y: number, r: number, color = "black") {
|
|
||||||
const c = this.ctx
|
|
||||||
c.save()
|
|
||||||
c.beginPath()
|
|
||||||
c.strokeStyle = color
|
|
||||||
c.arc(x, y, r, 0, Math.PI * 2)
|
|
||||||
c.stroke()
|
|
||||||
c.restore()
|
|
||||||
}
|
|
||||||
|
|
||||||
circfill(x: number, y: number, r: number, color = "black") {
|
|
||||||
const c = this.ctx
|
|
||||||
c.save()
|
|
||||||
c.beginPath()
|
|
||||||
c.fillStyle = color
|
|
||||||
c.arc(x, y, r, 0, Math.PI * 2)
|
|
||||||
c.fill()
|
|
||||||
c.restore()
|
|
||||||
}
|
|
||||||
|
|
||||||
line(x0: number, y0: number, x1: number, y1: number, color = "black") {
|
|
||||||
const c = this.ctx
|
|
||||||
c.save()
|
|
||||||
c.beginPath()
|
|
||||||
c.strokeStyle = color
|
|
||||||
c.moveTo(x0, y0)
|
|
||||||
c.lineTo(x1, y1)
|
|
||||||
c.stroke()
|
|
||||||
c.restore()
|
|
||||||
}
|
|
||||||
|
|
||||||
oval(x0: number, y0: number, x1: number, y1: number, color = "black") {
|
|
||||||
const c = this.ctx
|
|
||||||
const w = x1 - x0
|
|
||||||
const h = y1 - y0
|
|
||||||
c.save()
|
|
||||||
c.beginPath()
|
|
||||||
c.strokeStyle = color
|
|
||||||
c.ellipse(x0 + w / 2, y0 + h / 2, Math.abs(w) / 2, Math.abs(h) / 2, 0, 0, Math.PI * 2)
|
|
||||||
c.stroke()
|
|
||||||
c.restore()
|
|
||||||
}
|
|
||||||
|
|
||||||
ovalfill(x0: number, y0: number, x1: number, y1: number, color = "black") {
|
|
||||||
const c = this.ctx
|
|
||||||
const w = x1 - x0
|
|
||||||
const h = y1 - y0
|
|
||||||
c.save()
|
|
||||||
c.beginPath()
|
|
||||||
c.fillStyle = color
|
|
||||||
c.ellipse(x0 + w / 2, y0 + h / 2, Math.abs(w) / 2, Math.abs(h) / 2, 0, 0, Math.PI * 2)
|
|
||||||
c.fill()
|
|
||||||
c.restore()
|
|
||||||
}
|
|
||||||
|
|
||||||
rect(x0: number, y0: number, x1: number, y1: number, color = "black") {
|
|
||||||
const c = this.ctx
|
|
||||||
c.save()
|
|
||||||
c.beginPath()
|
|
||||||
c.strokeStyle = color
|
|
||||||
c.rect(x0, y0, x1 - x0, y1 - y0)
|
|
||||||
c.stroke()
|
|
||||||
c.restore()
|
|
||||||
}
|
|
||||||
|
|
||||||
rectfill(x0: number, y0: number, x1: number, y1: number, color = "black") {
|
|
||||||
const c = this.ctx
|
|
||||||
c.save()
|
|
||||||
this.ctx.fillStyle = color
|
|
||||||
this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0)
|
|
||||||
c.restore()
|
|
||||||
}
|
|
||||||
|
|
||||||
rrect(x: number, y: number, w: number, h: number, r: number, color = "black") {
|
|
||||||
const c = this.ctx
|
|
||||||
c.save()
|
|
||||||
c.beginPath()
|
|
||||||
c.strokeStyle = color
|
|
||||||
this.roundRectPath(x, y, w, h, r)
|
|
||||||
c.stroke()
|
|
||||||
c.restore()
|
|
||||||
}
|
|
||||||
|
|
||||||
rrectfill(x: number, y: number, w: number, h: number, r: number, color = "black") {
|
|
||||||
const c = this.ctx
|
|
||||||
c.save()
|
|
||||||
c.beginPath()
|
|
||||||
c.fillStyle = color
|
|
||||||
this.roundRectPath(x, y, w, h, r)
|
|
||||||
c.fill()
|
|
||||||
c.restore()
|
|
||||||
}
|
|
||||||
|
|
||||||
trianglefill(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, color = "black") {
|
|
||||||
return this.polygonfill(
|
|
||||||
[
|
|
||||||
[x0, y0],
|
|
||||||
[x1, y1],
|
|
||||||
[x2, y2]
|
|
||||||
],
|
|
||||||
color
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
polygonfill(points: [number, number][], color = "black") {
|
|
||||||
if (points.length < 3) return // need at least a triangle
|
|
||||||
const c = this.ctx
|
|
||||||
c.save()
|
|
||||||
c.beginPath()
|
|
||||||
c.fillStyle = color
|
|
||||||
c.moveTo(points[0]![0], points[0]![1])
|
|
||||||
for (let i = 1; i < points.length; i++) {
|
|
||||||
c.lineTo(points[i]![0], points[i]![1])
|
|
||||||
}
|
|
||||||
c.closePath()
|
|
||||||
c.fill()
|
|
||||||
c.restore()
|
|
||||||
}
|
|
||||||
|
|
||||||
private roundRectPath(x: number, y: number, w: number, h: number, r: number) {
|
|
||||||
const c = this.ctx
|
|
||||||
c.moveTo(x + r, y)
|
|
||||||
c.lineTo(x + w - r, y)
|
|
||||||
c.quadraticCurveTo(x + w, y, x + w, y + r)
|
|
||||||
c.lineTo(x + w, y + h - r)
|
|
||||||
c.quadraticCurveTo(x + w, y + h, x + w - r, y + h)
|
|
||||||
c.lineTo(x + r, y + h)
|
|
||||||
c.quadraticCurveTo(x, y + h, x, y + h - r)
|
|
||||||
c.lineTo(x, y + r)
|
|
||||||
c.quadraticCurveTo(x, y, x + r, y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user