diff options
author | metamuffin <metamuffin@disroot.org> | 2024-06-18 19:36:36 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-06-23 19:21:22 +0200 |
commit | 48934ff63ee14d4759eda36512af87361dd915dd (patch) | |
tree | f7a80115eacfee7b6871040a87f5fb0087098ea8 /test-client/main.ts | |
parent | 6ec47d729509db83eaeb6a9d855ce2483d70f227 (diff) | |
download | hurrycurry-48934ff63ee14d4759eda36512af87361dd915dd.tar hurrycurry-48934ff63ee14d4759eda36512af87361dd915dd.tar.bz2 hurrycurry-48934ff63ee14d4759eda36512af87361dd915dd.tar.zst |
remodel game.
Diffstat (limited to 'test-client/main.ts')
-rw-r--r-- | test-client/main.ts | 161 |
1 files changed, 115 insertions, 46 deletions
diff --git a/test-client/main.ts b/test-client/main.ts index e0cc9b3c..4c755e55 100644 --- a/test-client/main.ts +++ b/test-client/main.ts @@ -1,9 +1,11 @@ /// <reference lib="dom" /> -import { Gamedata, ItemID, ItemIndex, PacketC, PacketS, PlayerID, TileIndex } from "./protocol.ts"; +import { Gamedata, ItemIndex, PacketC, PacketS, PlayerID, TileIndex } from "./protocol.ts"; import { FALLBACK_ITEM } from "./tiles.ts"; import { FALLBACK_TILE, ITEMS, TILES } from "./tiles.ts"; -import { V2, add_v2, ceil_v2, floor_v2, length, lerp_exp_v2_mut, normalize } from "./util.ts"; +import { V2, add_v2, ceil_v2, floor_v2, length, lerp_exp_v2_mut, normalize, aabb_circle_distance } from "./util.ts"; + +const PLAYER_SIZE = 0.4; let ctx: CanvasRenderingContext2D; let canvas: HTMLCanvasElement; @@ -33,14 +35,31 @@ document.addEventListener("DOMContentLoaded", () => { setInterval(tick_update, 1000 / 25); }) -interface PlayerData { x: number; y: number, name: string, rot: number, hand?: ItemID, facing: V2 } +interface ItemData { + kind: ItemIndex, + x: number, + y: number, + progress?: number +} +interface PlayerData { + x: number, + y: number, + name: string, + rot: number, + item?: ItemData, + facing: V2, + vel: { x: number, y: number } +} +interface TileData { + x: number + y: number + kind: TileIndex + item?: ItemData +} const players = new Map<PlayerID, PlayerData>() -interface ItemData { kind: ItemIndex, tile?: V2, player?: PlayerID, tracking_player: boolean, x: number, y: number } -const items = new Map<ItemID, ItemData>() -interface TileData { x: number; y: number, kind: TileIndex, items: ItemID[], active_progress?: number } const tiles = new Map<string, TileData>() -let data: Gamedata = { item_names: [], tile_names: [] } +let data: Gamedata = { item_names: [], tile_names: [], spawn: [0, 0] } let my_id: PlayerID = -1 const camera: V2 = { x: 0, y: 0 } @@ -55,10 +74,12 @@ function packet(p: PacketC) { my_id = p.id data = p.data break; - case "add_player": - if (p.hand) items.set(p.hand[0], { kind: p.hand[1], player: p.id, tracking_player: true, x: 0, y: 0 }) - players.set(p.id, { x: 0, y: 0, name: p.name, rot: 0, hand: p.hand?.[0], facing: { x: 0, y: 1 } }) + case "add_player": { + let item = undefined + if (p.item) item = { kind: p.item, x: 0, y: 0 }; + players.set(p.id, { x: data.spawn[0], y: data.spawn[1], name: p.name, rot: 0, item, facing: { x: 0, y: 1 }, vel: { x: 0, y: 0 } }) break; + } case "remove_player": players.delete(p.id) break; @@ -71,33 +92,34 @@ function packet(p: PacketC) { break; } case "take_item": { - const item = items.get(p.item)! - item.tracking_player = true - item.player = p.player + const player = players.get(p.player)! + const tile = tiles.get(p.tile.toString())! + player.item = tile.item; + tile.item = undefined break; } case "put_item": { - const item = items.get(p.item)! - item.tracking_player = false - item.tile = { x: p.pos[0], y: p.pos[1] } + const player = players.get(p.player)! + const tile = tiles.get(p.tile.toString())! + tile.item = player.item; + player.item = undefined break; } - case "produce_item": - items.set(p.id, { kind: p.kind, x: p.pos[0] + 0.5, y: p.pos[1] + 0.5, tracking_player: false, tile: { x: p.pos[0], y: p.pos[1] } }) - tiles.get(p.pos.toString())!.items.push(p.id) + case "produce_item": { + const item = { kind: p.item, x: p.tile[0] + 0.5, y: p.tile[1] + 0.5 } + tiles.get(p.tile.toString())!.item = item break; + } case "consume_item": { - const t = tiles.get(p.pos.toString())! - t.items.splice(t.items.indexOf(p.id)) - items.delete(p.id) + tiles.get(p.tile.toString())!.item = undefined break; } case "set_active": { - tiles.get(p.tile.toString())!.active_progress = p.progress + tiles.get(p.tile.toString())!.item!.progress = p.progress break; } case "update_map": - tiles.set(p.pos.toString(), { x: p.pos[0], y: p.pos[1], kind: p.tile, items: [] }) + tiles.set(p.pos.toString(), { x: p.pos[0], y: p.pos[1], kind: p.tile }) break; default: console.warn("unknown packet", p); @@ -136,6 +158,7 @@ function tick_update() { send({ type: "position", pos: [p.x, p.y], rot: p.rot }) } + function frame_update(dt: number) { const p = players.get(my_id) if (!p) return @@ -147,26 +170,37 @@ function frame_update(dt: number) { if (length(input) > 0.1) lerp_exp_v2_mut(p.facing, input, dt * 10.) p.rot = Math.atan2(p.facing.x, p.facing.y) - p.x += input.x * dt * 5 - p.y += input.y * dt * 5 + p.vel.x += input.x * dt * 0.5 + p.vel.y += input.y * dt * 0.5 + p.x += p.vel.x + p.y += p.vel.y + collide_player(p) + lerp_exp_v2_mut(p.vel, { x: 0, y: 0 }, dt * 5.) + - for (const [_, i] of items) { - lerp_exp_v2_mut(i, i.tracking_player ? players.get(i.player!)! : add_v2(i.tile!, 0.5), dt * 10.) + const update_item = (item: ItemData, parent: V2) => { + lerp_exp_v2_mut(item, parent, dt * 10.) + } + for (const [_, player] of players) { + if (player.item) update_item(player.item, player) } + for (const [_, tile] of tiles) { + if (tile.item) update_item(tile.item, add_v2(tile, 0.5)) + } + lerp_exp_v2_mut(interact_target_anim, get_interact_target() ?? { x: 0, y: 0 }, dt * 15.) lerp_exp_v2_mut(camera, p, dt * 10.) } - function resize() { canvas.width = globalThis.innerWidth canvas.height = globalThis.innerHeight } -let last_frame = Date.now() +let last_frame = performance.now() function draw() { - const now = Date.now() + const now = performance.now() frame_update((now - last_frame) / 1000) last_frame = now; if (ws.readyState == ws.CONNECTING) draw_wait("Connecting...") @@ -226,29 +260,26 @@ function draw_ingame() { ctx.save() ctx.translate(player.x, player.y) ctx.rotate(-player.rot) + ctx.fillStyle = "rgb(226, 176, 26)" - const psize = 0.6; - ctx.fillRect(-psize / 2, -psize / 2, psize, psize) - ctx.restore() - } + ctx.beginPath() + ctx.arc(0, 0, PLAYER_SIZE, 0, Math.PI * 2) + ctx.fill() + + ctx.fillStyle = "rgb(103, 79, 7)" + ctx.beginPath() + ctx.arc(0, -0.2, PLAYER_SIZE, 0, Math.PI * 2) + ctx.fill() - for (const [_, item] of items) { - ctx.save() - ctx.translate(item.x, item.y) - const comps = ITEMS[data.item_names[item.kind]] ?? FALLBACK_ITEM - for (const c of comps) { - c(ctx) - } ctx.restore() + + if (player.item) draw_item(player.item) } for (const [_, tile] of tiles) { ctx.save() ctx.translate(tile.x, tile.y) - if (tile.active_progress !== null && tile.active_progress !== undefined) { - ctx.fillStyle = "rgba(115, 230, 58, 0.66)" - ctx.fillRect(0, 0, 1, tile.active_progress) - } + if (tile.item) draw_item(tile.item) ctx.restore() } @@ -257,6 +288,20 @@ function draw_ingame() { ctx.restore() } +function draw_item(item: ItemData) { + ctx.save() + ctx.translate(item.x, item.y) + 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, 0, 1, item.progress) + } + ctx.restore() +} + function draw_interact_target() { ctx.save() ctx.translate(interact_target_anim.x, interact_target_anim.y) @@ -286,3 +331,27 @@ function draw_grid() { } ctx.stroke() } + +function collide_player(p: PlayerData) { + const tiles_ignored = ["floor", "door", "chair"].map(t => data.tile_names.indexOf(t)) + for (const [_, tile] of tiles) { + if (tiles_ignored.includes(tile.kind)) continue + const d = aabb_circle_distance(tile.x, tile.y, tile.x + 1, tile.y + 1, p.x, p.y) + if (d > PLAYER_SIZE) continue + + const h = 0.01 + const d_sample_x = aabb_circle_distance(tile.x, tile.y, tile.x + 1, tile.y + 1, p.x + h, p.y) + const d_sample_y = aabb_circle_distance(tile.x, tile.y, tile.x + 1, tile.y + 1, p.x, p.y + h) + const grad_x = (d_sample_x - d) / h + const grad_y = (d_sample_y - d) / h + + p.x += (PLAYER_SIZE - d) * grad_x + p.y += (PLAYER_SIZE - d) * grad_y + + const vdotn = (grad_x * p.vel.x) + (grad_y * p.vel.y) + p.vel.x -= grad_x * vdotn + p.vel.y -= grad_y * vdotn + + + } +} |