Further hunt mode refactors

This commit is contained in:
Pyrex 2025-02-02 14:17:30 -08:00
parent dfae5b2405
commit 40ea1b909c
5 changed files with 152 additions and 132 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 643 B

After

Width:  |  Height:  |  Size: 431 B

View File

@ -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});
}

View File

@ -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) {

View File

@ -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,
}
)
this.#withHuntModeCamera(() => {
this.huntMode.draw();
});
}
}
#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
}
)
});
}
}
const MAP_CELL_ONSCREEN_SIZE: Size = new Size(96, 48)
export let game = new Game();

View File

@ -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<MapCell>
player: Point
drawpile: DrawPile
frame: number
constructor({depth, cells, player}: {depth: number, cells: Grid<MapCell>, 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<T>(array: Array<T>): T {
if (array.length == 0) {
throw `array cannot have length 0 for choose`