diff options
Diffstat (limited to 'test-client/visual.ts')
-rw-r--r-- | test-client/visual.ts | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/test-client/visual.ts b/test-client/visual.ts new file mode 100644 index 00000000..4bbfac6c --- /dev/null +++ b/test-client/visual.ts @@ -0,0 +1,172 @@ +import { ItemData, PLAYER_SIZE, camera, canvas, ctx, data, get_interact_target, interact_target_anim, items_removed, keys_down, players, tiles } from "./main.ts"; +import { Message } from "./protocol.ts"; +import { FALLBACK_TILE, ITEMS, TILES, FALLBACK_ITEM } from "./tiles.ts"; +import { V2, ceil_v2, floor_v2 } from "./util.ts"; + +let camera_zoom = 0.1 +let scale = 0 + +export function draw_wait(text: string) { + ctx.fillStyle = "#444" + ctx.fillRect(0, 0, canvas.width, canvas.height) + ctx.fillStyle = "#555" + ctx.font = "50px sans-serif" + ctx.strokeStyle = "black" + ctx.fillStyle = "white" + ctx.lineWidth = 10 + ctx.textAlign = "center" + ctx.textBaseline = "middle" + ctx.lineJoin = "round" + ctx.lineCap = "round" + ctx.strokeText(text, canvas.width / 2, canvas.height / 2) + ctx.fillText(text, canvas.width / 2, canvas.height / 2) +} + + +export function draw_ingame() { + ctx.fillStyle = "#111" + ctx.fillRect(0, 0, canvas.width, canvas.height) + + scale = Math.min(canvas.width, canvas.height) * camera_zoom; + ctx.save() + ctx.translate(canvas.width / 2, canvas.height / 2) + ctx.scale(scale, scale) + ctx.translate(-camera.x, -camera.y) + + draw_grid() + + for (const [_, tile] of tiles) { + ctx.save() + ctx.translate(tile.x + 0.5, tile.y + 0.5) + const comps = TILES[data.tile_names[tile.kind]] ?? FALLBACK_TILE + for (const c of comps) { + c(ctx) + } + ctx.restore() + } + + for (const [_, player] of players) { + { + ctx.save() + ctx.translate(player.x, player.y) + { + ctx.save() + ctx.rotate(-player.rot) + draw_character(player.character) + ctx.restore() + } + if (player.message) draw_message(player.message) + ctx.restore() + } + if (player.item) draw_item(player.item) + } + + for (const item of items_removed) { + draw_item(item) + } + for (const [_, tile] of tiles) { + if (tile.item) draw_item(tile.item) + } + + draw_interact_target() + + ctx.restore() + + if (keys_down.has("KeyP")) { + camera_zoom = 0.05 + ctx.fillStyle = "white" + ctx.textAlign = "left" + ctx.textBaseline = "bottom" + ctx.font = "20px sans-serif" + ctx.fillText(`interact = ${JSON.stringify(get_interact_target())}`, 10, 30) + } else { camera_zoom = 0.1 } +} + +function draw_item(item: ItemData) { + ctx.save() + ctx.translate(item.x, item.y) + if (item.remove_anim) ctx.scale(1 - item.remove_anim, 1 - item.remove_anim) + const comps = ITEMS[data.item_names[item.kind]] ?? FALLBACK_ITEM + for (const c of comps) { + c(ctx) + } + if (item.progress !== null && item.progress !== undefined) { + ctx.fillStyle = "rgba(115, 230, 58, 0.66)" + ctx.fillRect(-0.5, -0.5, 1, item.progress) + } + ctx.restore() +} + +function draw_interact_target() { + ctx.save() + ctx.translate(interact_target_anim.x, interact_target_anim.y) + + ctx.lineCap = "round" + ctx.lineJoin = "round" + ctx.lineWidth = 0.06 + 0.03 * Math.sin(Date.now() / 100) + ctx.strokeStyle = "rgb(84, 122, 236)" + ctx.strokeRect(0, 0, 1, 1) + + ctx.restore() +} + +function draw_grid() { + ctx.strokeStyle = "#333" + ctx.lineWidth = 0.01 + ctx.beginPath() + const min = floor_v2(map_screen_to_world({ x: 0, y: 0 })) + const max = ceil_v2(map_screen_to_world({ x: canvas.width, y: canvas.height })) + for (let x = min.x; x < max.x; x++) { + ctx.moveTo(x, min.y) + ctx.lineTo(x, max.y) + } + for (let y = min.y; y < max.y; y++) { + ctx.moveTo(min.x, y) + ctx.lineTo(max.x, y) + } + ctx.stroke() +} + +function draw_character(character: number) { + ctx.fillStyle = `hsl(${character}rad, 50%, 50%)` + ctx.beginPath() + ctx.arc(0, 0, PLAYER_SIZE, 0, Math.PI * 2) + ctx.fill() + + ctx.fillStyle = `hsl(${character}rad, 80%, 10%)` + ctx.beginPath() + ctx.arc(0, -0.2, PLAYER_SIZE, 0, Math.PI * 2) + ctx.fill() + + ctx.fillStyle = `hsl(${character}rad, 80%, 70%)` + ctx.beginPath() + ctx.moveTo(-0.04, 0.25) + ctx.lineTo(0.04, 0.25) + ctx.lineTo(0, 0.4) + ctx.fill() +} + +function draw_message(m: Message) { + ctx.save() + ctx.translate(0, -1) + if ("item" in m) { + ctx.fillStyle = "#fffa" + ctx.beginPath() + ctx.moveTo(0, 0.7) + ctx.arc(0, 0, 0.5, Math.PI / 4, Math.PI - Math.PI / 4, true) + ctx.closePath() + ctx.fill() + + const comps = ITEMS[data.item_names[m.item]] ?? FALLBACK_ITEM + for (const c of comps) c(ctx) + } + ctx.restore() +} + +function map_screen_to_world(screen: V2): V2 { + return { + x: ((screen.x - canvas.width / 2) / scale) + camera.x, + y: ((screen.y - canvas.height / 2) / scale) + camera.y, + } +} + |