Further hunt mode refactors
This commit is contained in:
		
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 643 B After Width: | Height: | Size: 431 B | 
| @@ -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}); | ||||
|   } | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
							
								
								
									
										139
									
								
								src/game.ts
									
									
									
									
									
								
							
							
						
						
									
										139
									
								
								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(); | ||||
							
								
								
									
										129
									
								
								src/huntmode.ts
									
									
									
									
									
								
							
							
						
						
									
										129
									
								
								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<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` | ||||
|   | ||||
		Reference in New Issue
	
	Block a user