diff --git a/src/art/pickups/stats.png b/src/art/pickups/stats.png index dd33da5..7301deb 100644 Binary files a/src/art/pickups/stats.png and b/src/art/pickups/stats.png differ diff --git a/src/drawpile.ts b/src/drawpile.ts index 44c87c2..5416a08 100644 --- a/src/drawpile.ts +++ b/src/drawpile.ts @@ -2,7 +2,7 @@ import {D, I} from "./engine/public.ts"; import {Rect} from "./engine/datatypes.ts"; export class DrawPile { - readonly #draws: {depth: number, op: () => void, onClick?: () => void}[] + #draws: {depth: number, op: () => void, onClick?: () => void}[] #hoveredIndex: number | null; constructor() { @@ -10,6 +10,11 @@ export class DrawPile { this.#hoveredIndex = null; } + clear() { + this.#draws = []; + this.#hoveredIndex = null; + } + add(depth: number, op: () => void) { this.#draws.push({depth, op}); } diff --git a/src/engine/internal/drawing.ts b/src/engine/internal/drawing.ts index 5c2f9ca..d90add5 100644 --- a/src/engine/internal/drawing.ts +++ b/src/engine/internal/drawing.ts @@ -10,6 +10,15 @@ class Drawing { this.camera = new Point(0, 0); } + withCamera(point: Point, cb: () => void) { + let oldCamera = this.camera; + this.camera = this.camera = point; + + cb(); + + this.camera = oldCamera; + } + get size() { return getScreen().size; } invertRect(position: Point, size: Size) { diff --git a/src/game.ts b/src/game.ts index 47f712f..8713232 100644 --- a/src/game.ts +++ b/src/game.ts @@ -1,11 +1,8 @@ import {desiredHeight, desiredWidth, getScreen} from "./engine/internal/screen.ts"; -import {BG_INSET, BG_OUTER, FG_TEXT} from "./colors.ts"; +import {BG_OUTER} from "./colors.ts"; import {D, I} from "./engine/public.ts"; -import {IGame, Point, Rect, Size} from "./engine/datatypes.ts"; -import {sprDrips, sprRaccoonWalking, sprStatPickup} from "./sprites.ts"; -import {DrawPile} from "./drawpile.ts"; -import {HuntMode, MapCell} from "./huntmode.ts"; -import {ALL_STATS} from "./datatypes.ts"; +import {IGame, Point, Size} from "./engine/datatypes.ts"; +import {HuntMode} from "./huntmode.ts"; class MenuCamera { // measured in whole screens @@ -46,7 +43,6 @@ export class Game implements IGame { camera: MenuCamera; state: GameState; huntMode: HuntMode; - gameplayDrawPile: DrawPile | null; frame: number; constructor() { @@ -57,7 +53,6 @@ export class Game implements IGame { this.state = "Gameplay"; this.huntMode = HuntMode.generate({depth: 1}); - this.gameplayDrawPile = null; this.frame = 0; } @@ -125,140 +120,24 @@ export class Game implements IGame { } } - #moveCameraForGameplayDrawpile(cb: () => void) { + #withHuntModeCamera(cb: () => void) { let region = this.getPaneRegionForGameState("Gameplay") - let oldCamera = D.camera; - D.camera = D.camera.offset(region.small.position.negate()); - - cb(); - - D.camera = oldCamera; + D.withCamera(D.camera.offset(region.small.position.negate()), cb) } updateGameplay() { - var drawpile = new DrawPile(); - - this.#moveCameraForGameplayDrawpile(() => { - let globalOffset = - new Point(this.huntMode.player.x * MAP_CELL_ONSCREEN_SIZE.w, this.huntMode.player.y * MAP_CELL_ONSCREEN_SIZE.h).offset( - new Point(-192, -192) - ) - - let map = this.huntMode.cells; - for (let y = 0; y < map.size.h; y += 1) { - for (let x = 0; x < map.size.w; x += 1) { - let cellOffset = new Point(x * MAP_CELL_ONSCREEN_SIZE.w, y * MAP_CELL_ONSCREEN_SIZE.h).offset(globalOffset.negate()); - let cellData = this.huntMode.cells.get(new Point(x, y)) - let belowIsBlock = true; - if (y < map.size.h - 1) { - let below = this.huntMode.cells.get(new Point(x, y + 1)); - belowIsBlock = !below.revealed || below.content.type == "block"; - } - - this.#drawMapCell(drawpile, cellOffset, new Point(x, y), cellData, belowIsBlock); - } - } - this.#drawPlayer(drawpile, globalOffset); - - drawpile.executeOnClick(); + this.#withHuntModeCamera(() => { + this.huntMode.update(); }); - - this.gameplayDrawPile = drawpile; } drawGameplay() { - // TODO: Draw - - this.#moveCameraForGameplayDrawpile(() => { - this.gameplayDrawPile?.draw(); - - // D.drawText("shapes", new Point(0, 0), FG_TEXT); - }); - } - - #drawMapCell( - drawpile: DrawPile, - cellOffset: Point, - mapPosition: Point, - cellData: MapCell, - belowIsBlock: boolean - ) { - const OFFSET_FLOOR = -256; - const OFFSET_AIR = 0; - const depth = mapPosition.y; - const onFloor = OFFSET_FLOOR + depth; - const inAir = OFFSET_AIR + depth; - - if (!cellData.revealed) { - return; - } - - let cellTopLeft = cellOffset.offset(new Size(-MAP_CELL_ONSCREEN_SIZE.w / 2, -MAP_CELL_ONSCREEN_SIZE.h / 2)); - let cellSize = MAP_CELL_ONSCREEN_SIZE; - - if (cellData.content.type == "block") { - if (!belowIsBlock) { - drawpile.add(inAir, () => { - D.drawSprite(sprDrips, cellOffset.offset(new Point(0, -cellSize.h)), 1, {xScale: 3, yScale: 3}) - }) - } - return; - } - - // draw inset zone - drawpile.addClickable(onFloor, - (hover: boolean) => { - D.fillRect(cellTopLeft, cellSize, hover ? FG_TEXT : BG_INSET) - }, - new Rect(cellTopLeft, cellSize), - cellData.nextMoveAccessible, - () => { - this.huntMode.movePlayerTo(mapPosition) - } - ); - - if (belowIsBlock) { - // draw the underhang - drawpile.add(onFloor, () => { - D.drawSprite(sprDrips, cellOffset.offset(new Point(0, cellSize.h/2)), 0, {xScale: 3, yScale: 3}) - }) - } - - if (cellData.content.type == "statPickup") { - let content = cellData.content; - let extraXOffset = 0; // Math.cos(this.frame / 80 + mapPosition.x + mapPosition.y) * 1; - let extraYOffset = Math.sin(this.frame / 50 + mapPosition.x * 2+ mapPosition.y * 0.75) * 6 - 18; - drawpile.add(inAir, () => { - D.drawSprite( - sprStatPickup, - cellOffset.offset(new Point(extraXOffset, extraYOffset)), - ALL_STATS.indexOf(content.stat), - { - xScale: 3, - yScale: 3, - } - ) - }); - } - } - - #drawPlayer(drawpile: DrawPile, globalOffset: Point) { - let cellOffset = new Point(this.huntMode.player.x * MAP_CELL_ONSCREEN_SIZE.w, this.huntMode.player.y * MAP_CELL_ONSCREEN_SIZE.h).offset(globalOffset.negate()) - drawpile.add(this.huntMode.player.y, () => { - D.drawSprite( - sprRaccoonWalking, - cellOffset.offset(new Point(0, 22)), - 0, { - xScale: 3, - yScale: 3 - } - ) + this.#withHuntModeCamera(() => { + this.huntMode.draw(); }); } } -const MAP_CELL_ONSCREEN_SIZE: Size = new Size(96, 48) - export let game = new Game(); \ No newline at end of file diff --git a/src/huntmode.ts b/src/huntmode.ts index 1591257..9c5936f 100644 --- a/src/huntmode.ts +++ b/src/huntmode.ts @@ -1,6 +1,10 @@ -import {Grid, Point, Size} from "./engine/datatypes.ts"; +import {Grid, Point, Rect, Size} from "./engine/datatypes.ts"; import {ConceptualCell, maps} from "./maps.ts"; import {ALL_STATS, Stat} from "./datatypes.ts"; +import {DrawPile} from "./drawpile.ts"; +import {D} from "./engine/public.ts"; +import {sprDrips, sprRaccoonWalking, sprStatPickup} from "./sprites.ts"; +import {BG_INSET, FG_TEXT} from "./colors.ts"; export type MapCellContent = {type: "statPickup", stat: Stat} | @@ -20,10 +24,16 @@ export class HuntMode { cells: Grid player: Point + drawpile: DrawPile + frame: number + constructor({depth, cells, player}: {depth: number, cells: Grid, player: Point }) { this.depth = depth; this.cells = cells; this.player = player; + + this.drawpile = new DrawPile(); + this.frame = 0; } // == map generator == @@ -141,8 +151,125 @@ export class HuntMode { this.#updateVisibilityAndPossibleMoves(); this.#collectResources(); } + + // draw: + update() { + this.frame += 1; + this.drawpile.clear(); + + let globalOffset = + new Point(this.player.x * MAP_CELL_ONSCREEN_SIZE.w, this.player.y * MAP_CELL_ONSCREEN_SIZE.h).offset( + new Point(-192, -192) + ) + + let map = this.cells; + for (let y = 0; y < map.size.h; y += 1) { + for (let x = 0; x < map.size.w; x += 1) { + let cellOffset = new Point(x * MAP_CELL_ONSCREEN_SIZE.w, y * MAP_CELL_ONSCREEN_SIZE.h).offset(globalOffset.negate()); + let cellData = this.cells.get(new Point(x, y)) + let belowIsBlock = true; + if (y < map.size.h - 1) { + let below = this.cells.get(new Point(x, y + 1)); + belowIsBlock = !below.revealed || below.content.type == "block"; + } + + this.#drawMapCell(cellOffset, new Point(x, y), cellData, belowIsBlock); + } + } + this.#drawPlayer(globalOffset); + + this.drawpile.executeOnClick(); + } + + draw() { + this.drawpile.draw() + } + + #drawMapCell( + cellOffset: Point, + mapPosition: Point, + cellData: MapCell, + belowIsBlock: boolean + ) { + const OFFSET_FLOOR = -256; + const OFFSET_AIR = 0; + const depth = mapPosition.y; + const onFloor = OFFSET_FLOOR + depth; + const inAir = OFFSET_AIR + depth; + + if (!cellData.revealed) { + return; + } + + let cellTopLeft = cellOffset.offset(new Size(-MAP_CELL_ONSCREEN_SIZE.w / 2, -MAP_CELL_ONSCREEN_SIZE.h / 2)); + let cellSize = MAP_CELL_ONSCREEN_SIZE; + + if (cellData.content.type == "block") { + if (!belowIsBlock) { + this.drawpile.add(inAir, () => { + D.drawSprite(sprDrips, cellOffset.offset(new Point(0, -cellSize.h)), 1, {xScale: 3, yScale: 3}) + }) + } + return; + } + + // draw inset zone + this.drawpile.addClickable(onFloor, + (hover: boolean) => { + D.fillRect(cellTopLeft, cellSize, hover ? FG_TEXT : BG_INSET) + }, + new Rect(cellTopLeft, cellSize), + cellData.nextMoveAccessible, + () => { + this.movePlayerTo(mapPosition) + } + ); + + if (belowIsBlock) { + // draw the underhang + this.drawpile.add(onFloor, () => { + D.drawSprite(sprDrips, cellOffset.offset(new Point(0, cellSize.h/2)), 0, {xScale: 3, yScale: 3}) + }) + } + + if (cellData.content.type == "statPickup") { + let content = cellData.content; + let extraXOffset = 0; // Math.cos(this.frame / 80 + mapPosition.x + mapPosition.y) * 1; + let extraYOffset = Math.sin(this.frame / 50 + mapPosition.x * 2+ mapPosition.y * 0.75) * 6 - 18; + this.drawpile.add(inAir, () => { + D.drawSprite( + sprStatPickup, + cellOffset.offset(new Point(extraXOffset, extraYOffset)), + ALL_STATS.indexOf(content.stat), + { + xScale: 3, + yScale: 3, + } + ) + }); + } + } + + #drawPlayer(globalOffset: Point) { + let cellOffset = new Point( + this.player.x * MAP_CELL_ONSCREEN_SIZE.w, + this.player.y * MAP_CELL_ONSCREEN_SIZE.h + ).offset(globalOffset.negate()) + this.drawpile.add(this.player.y, () => { + D.drawSprite( + sprRaccoonWalking, + cellOffset.offset(new Point(0, 22)), + 0, { + xScale: 3, + yScale: 3 + } + ) + }); + } } +const MAP_CELL_ONSCREEN_SIZE: Size = new Size(96, 48) + function choose(array: Array): T { if (array.length == 0) { throw `array cannot have length 0 for choose`