Raccoon walks around badly
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								src/art/tilesets/drips.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/art/tilesets/drips.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 240 B | 
							
								
								
									
										3
									
								
								src/datatypes.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/datatypes.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
|  | ||||
| export type Stat = "AGI" | "INT" | "CHA" | "PSI"; | ||||
| export const ALL_STATS: Array<Stat> = ["AGI", "INT", "CHA", "PSI"]; | ||||
| @@ -1,15 +1,47 @@ | ||||
| import {D, I} from "./engine/public.ts"; | ||||
| import {Rect} from "./engine/datatypes.ts"; | ||||
|  | ||||
| export class DrawPile { | ||||
|   readonly #draws: {depth: number, op: () => void}[] | ||||
|   readonly #draws: {depth: number, op: () => void, onClick?: () => void}[] | ||||
|   #hoveredIndex: number | null; | ||||
|  | ||||
|   constructor() { | ||||
|     this.#draws = [] | ||||
|     this.#hoveredIndex = null; | ||||
|   } | ||||
|  | ||||
|   add(depth: number, op: () => void) { | ||||
|     this.#draws.push({depth, op}); | ||||
|   } | ||||
|  | ||||
|   execute() { | ||||
|   addClickable(depth: number, op: (hover: boolean) => void, rect: Rect, enabled: boolean, onClick: () => void) { | ||||
|     let position = I.mousePosition?.offset(D.camera); | ||||
|     let hovered = false; | ||||
|     if (position != null) { | ||||
|       hovered = rect.contains(position); | ||||
|     } | ||||
|     if (!enabled) { | ||||
|       hovered = false; | ||||
|     } | ||||
|     if (hovered) { | ||||
|       this.#hoveredIndex = this.#draws.length; | ||||
|     } | ||||
|     this.#draws.push({depth, op: (() => op(hovered)), onClick: onClick}) | ||||
|   } | ||||
|  | ||||
|   executeOnClick() { | ||||
|     if (I.isMouseClicked("leftMouse")) { | ||||
|       let hi = this.#hoveredIndex; | ||||
|       if (hi != null) { | ||||
|         let cb = this.#draws[hi]?.onClick; | ||||
|         if (cb != null) { | ||||
|           cb(); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   draw() { | ||||
|     let draws = [...this.#draws]; | ||||
|     draws.sort( | ||||
|       (d0, d1) => d0.depth - d1.depth | ||||
|   | ||||
| @@ -82,6 +82,20 @@ export class Size { | ||||
|   } | ||||
| } | ||||
|  | ||||
| export class Rect { | ||||
|   readonly top: Point; | ||||
|   readonly size: Size; | ||||
|  | ||||
|   constructor(top: Point, size: Size) { | ||||
|     this.top = top; | ||||
|     this.size = size; | ||||
|   } | ||||
|  | ||||
|   contains(other: Point) { | ||||
|     return (other.x >= this.top.x && other.y >= this.top.y && other.x < this.top.x + this.size.w && other.y < this.top.y + this.size.h); | ||||
|   } | ||||
| } | ||||
|  | ||||
| export class Grid<T> { | ||||
|   readonly size: Size; | ||||
|   #data: T[][]; | ||||
|   | ||||
| @@ -71,7 +71,7 @@ class Drawing { | ||||
|     return mainFont.measureText({text, forceWidth}) | ||||
|   } | ||||
|  | ||||
|   drawSprite(sprite: Sprite, position: Point, ix?: number, options?: {xScale?: number, yScale: number, angle: number}) { | ||||
|   drawSprite(sprite: Sprite, position: Point, ix?: number, options?: {xScale?: number, yScale: number, angle?: number}) { | ||||
|     position = this.camera.negate().offset(position); | ||||
|  | ||||
|     let ctx = getScreen().unsafeMakeContext(); | ||||
|   | ||||
							
								
								
									
										238
									
								
								src/game.ts
									
									
									
									
									
								
							
							
						
						
									
										238
									
								
								src/game.ts
									
									
									
									
									
								
							| @@ -1,10 +1,11 @@ | ||||
| import {desiredHeight, desiredWidth, getScreen} from "./engine/internal/screen.ts"; | ||||
| import {BG_INSET, BG_OUTER, FG_TEXT} from "./colors.ts"; | ||||
| import {checkGrid, ConceptualCell, maps, mapSzX, mapSzY} from "./maps.ts"; | ||||
| import {D, I} from "./engine/public.ts"; | ||||
| import {Grid, IGame, Point, Size} from "./engine/datatypes.ts"; | ||||
| import {sprRaccoonWalking, sprStatPickup} from "./sprites.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"; | ||||
|  | ||||
| class MenuCamera { | ||||
|   // measured in whole screens | ||||
| @@ -45,6 +46,7 @@ export class Game implements IGame { | ||||
|   camera: MenuCamera; | ||||
|   state: GameState; | ||||
|   huntMode: HuntMode; | ||||
|   gameplayDrawPile: DrawPile | null; | ||||
|   frame: number; | ||||
|  | ||||
|   constructor() { | ||||
| @@ -55,6 +57,7 @@ export class Game implements IGame { | ||||
|     this.state = "Gameplay"; | ||||
|  | ||||
|     this.huntMode = HuntMode.generate({depth: 1}); | ||||
|     this.gameplayDrawPile = null; | ||||
|     this.frame = 0; | ||||
|   } | ||||
|  | ||||
| @@ -120,199 +123,142 @@ export class Game implements IGame { | ||||
|         size: new Size(smallPaneW, smallPaneH), | ||||
|       } | ||||
|     } | ||||
|  | ||||
|   } | ||||
|  | ||||
|   updateGameplay() { | ||||
|  | ||||
|   } | ||||
|  | ||||
|   drawGameplay() { | ||||
|   #moveCameraForGameplayDrawpile(cb: () => void) { | ||||
|     let region = this.getPaneRegionForGameState("Gameplay") | ||||
|     // TODO: Draw | ||||
|  | ||||
|     let oldCamera = D.camera; | ||||
|     D.camera = D.camera.offset(region.small.position.negate()); | ||||
|  | ||||
|     let drawpile = new DrawPile(); | ||||
|  | ||||
|     let globalOffset = | ||||
|       new Point(this.huntMode.player.x * 32, this.huntMode.player.y * 32).offset( | ||||
|         new Point(-192, -128) | ||||
|       ) | ||||
|  | ||||
|  | ||||
|     for (let y = 0; y < mapSzY; y += 1) { | ||||
|       for (let x = 0; x < mapSzX; x += 1) { | ||||
|         let cellOffset = new Point(x * 32, y * 32).offset(globalOffset.negate()); | ||||
|         let cellData = this.huntMode.cells.get(new Point(x, y)) | ||||
|  | ||||
|         this.#drawMapCell(drawpile, cellOffset, new Point(x, y), cellData); | ||||
|       } | ||||
|     } | ||||
|     this.#drawPlayer(drawpile, globalOffset); | ||||
|  | ||||
|     drawpile.execute(); | ||||
|  | ||||
|     D.drawText("hello", new Point(0, 0), FG_TEXT); | ||||
|     cb(); | ||||
|  | ||||
|     D.camera = oldCamera; | ||||
|   } | ||||
|  | ||||
|   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.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 = cellOffset.y; | ||||
|     const depth = mapPosition.y; | ||||
|     const onFloor = OFFSET_FLOOR + depth; | ||||
|     const inAir = OFFSET_AIR + depth; | ||||
|  | ||||
|     if (cellData.content.type == "block") { | ||||
|       return; | ||||
|     } | ||||
|     /* | ||||
|     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.add(onFloor, () => | ||||
|       D.fillRect(cellOffset.offset(new Size(-16, -26)), new Size(32, 32), BG_INSET) | ||||
|     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 (!cellData.revealed) { | ||||
|       // TODO: draw some kind of question mark | ||||
|       D.drawText("?", cellOffset.offset(new Point(12, 8)), FG_TEXT); | ||||
|       return | ||||
|     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 = 0; // Math.sin(this.frame / 50 + mapPosition.x * 2+ mapPosition.y * 0.75) * 6 - 3; | ||||
|       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) | ||||
|           ALL_STATS.indexOf(content.stat), | ||||
|           { | ||||
|             xScale: 3, | ||||
|             yScale: 3, | ||||
|           } | ||||
|         ) | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   #drawPlayer(drawpile: DrawPile, globalOffset: Point) { | ||||
|     let cellOffset = new Point(this.huntMode.player.x * 32, this.huntMode.player.y * 32).offset(globalOffset.negate()) | ||||
|     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 | ||||
|         cellOffset.offset(new Point(0, 22)), | ||||
|         0, { | ||||
|           xScale: 3, | ||||
|           yScale: 3 | ||||
|         } | ||||
|       ) | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|  | ||||
| type Stat = "AGI" | "INT" | "CHA" | "PSI"; | ||||
| const ALL_STATS: Array<Stat> = ["AGI", "INT", "CHA", "PSI"]; | ||||
| type MapCellContent = | ||||
|   {type: "statPickup", stat: Stat} | | ||||
|   {type: "stairs"} | | ||||
|   {type: "empty"} | | ||||
|   {type: "block"} | ||||
| const MAP_CELL_ONSCREEN_SIZE: Size = new Size(96, 48) | ||||
|  | ||||
| type MapCell = { | ||||
|   content: MapCellContent, | ||||
|   isValidSpawn: boolean, | ||||
|   revealed: boolean | ||||
| } | ||||
|  | ||||
| class HuntMode { | ||||
|   depth: number | ||||
|   cells: Grid<MapCell> | ||||
|   player: Point | ||||
|  | ||||
|   constructor({depth, cells, player}: {depth: number, cells: Grid<MapCell>, player: Point }) { | ||||
|     this.depth = depth; | ||||
|     this.cells = cells; | ||||
|     this.player = player; | ||||
|  | ||||
|     checkGrid(this.cells); | ||||
|   } | ||||
|  | ||||
|   static generate({depth}: {depth: number}) { | ||||
|     let mapNames: Array<string> = Object.keys(maps); | ||||
|     let mapName = mapNames[Math.floor(Math.random() * mapNames.length)]; | ||||
|     let map = maps[mapName]; | ||||
|  | ||||
|     let cells = map.map((ccell, _xy) => { | ||||
|       return this.#generateCell(ccell); | ||||
|     }) | ||||
|  | ||||
|     let validSpawns = []; | ||||
|     for (let x = 0; x < cells.size.w; x++) { | ||||
|       for (let y = 0; y < cells.size.h; y++) { | ||||
|         let position = new Point(x, y); | ||||
|         if (cells.get(position).isValidSpawn)  { | ||||
|           validSpawns.push(position); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     let player = choose(validSpawns); | ||||
|     cells.get(player).content = {type: "empty"}; | ||||
|  | ||||
|     if (Math.random() < 0.75) { | ||||
|       while (true) { | ||||
|         let x = Math.floor(Math.random() * mapSzX); | ||||
|         let y = Math.floor(Math.random() * mapSzY); | ||||
|         let xy = new Point(x, y); | ||||
|  | ||||
|         let item = cells.get(new Point(x, y)); | ||||
|         if (player.equals(xy)) { | ||||
|           continue; | ||||
|         } | ||||
|         if (item.content.type == "block") { | ||||
|           continue; | ||||
|         } | ||||
|         item.content = {type: "stairs"} | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return new HuntMode({depth, cells, player}) | ||||
|   } | ||||
|  | ||||
|   static #generateCell(conceptual: ConceptualCell): MapCell { | ||||
|     switch (conceptual) { | ||||
|       case "X": | ||||
|         return { content: {type: "block"}, revealed: true, isValidSpawn: false}; | ||||
|       case " ": | ||||
|         return { content: HuntMode.#generateContent(), revealed: false, isValidSpawn: false }; | ||||
|       case ".": | ||||
|         return { content: HuntMode.#generateContent(), revealed: false, isValidSpawn: true }; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   static #generateContent(): MapCellContent { | ||||
|     // stat pickup | ||||
|     let gsp = (): MapCellContent => { | ||||
|       return {type: "statPickup", stat: choose(ALL_STATS)} | ||||
|     }; | ||||
|     // TODO: Other objects? | ||||
|     return choose([ | ||||
|       gsp, gsp, gsp, gsp | ||||
|     ])(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| function choose<T>(array: Array<T>): T  { | ||||
|   if (array.length == 0) { | ||||
|     throw `array cannot have length 0 for choose` | ||||
|   } | ||||
|   return array[Math.floor(Math.random() * array.length)] | ||||
| } | ||||
|  | ||||
| export let game = new Game(); | ||||
							
								
								
									
										151
									
								
								src/huntmode.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								src/huntmode.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | ||||
| import {Grid, Point, Size} from "./engine/datatypes.ts"; | ||||
| import {ConceptualCell, maps} from "./maps.ts"; | ||||
| import {ALL_STATS, Stat} from "./datatypes.ts"; | ||||
|  | ||||
| export type MapCellContent = | ||||
|   {type: "statPickup", stat: Stat} | | ||||
|   {type: "stairs"} | | ||||
|   {type: "empty"} | | ||||
|   {type: "block"} | ||||
|  | ||||
| export type MapCell = { | ||||
|   content: MapCellContent, | ||||
|   isValidSpawn: boolean, | ||||
|   revealed: boolean, | ||||
|   nextMoveAccessible: boolean, | ||||
| } | ||||
|  | ||||
| export class HuntMode { | ||||
|   depth: number | ||||
|   cells: Grid<MapCell> | ||||
|   player: Point | ||||
|  | ||||
|   constructor({depth, cells, player}: {depth: number, cells: Grid<MapCell>, player: Point }) { | ||||
|     this.depth = depth; | ||||
|     this.cells = cells; | ||||
|     this.player = player; | ||||
|   } | ||||
|  | ||||
|   // == map generator == | ||||
|   static generate({depth}: {depth: number}) { | ||||
|     let mapNames: Array<string> = Object.keys(maps); | ||||
|     let mapName = mapNames[Math.floor(Math.random() * mapNames.length)]; | ||||
|     let map = maps[mapName]; | ||||
|  | ||||
|     let baseCells = map.map((ccell, _xy) => { | ||||
|       return this.#generateCell(ccell); | ||||
|     }) | ||||
|  | ||||
|     let cells = new Grid( | ||||
|       new Size(baseCells.size.w + 2, baseCells.size.h + 2), (xy) => { | ||||
|         let offset = xy.offset(new Point(-1, -1)); | ||||
|         if (offset.x == -1 || offset.y == -1 || offset.x == baseCells.size.w || offset.y == baseCells.size.h) { | ||||
|           return this.#generateBoundaryCell(); | ||||
|         } | ||||
|         return baseCells.get(offset) | ||||
|       } | ||||
|     ) | ||||
|  | ||||
|     let validSpawns = []; | ||||
|     for (let x = 0; x < cells.size.w; x++) { | ||||
|       for (let y = 0; y < cells.size.h; y++) { | ||||
|         let position = new Point(x, y); | ||||
|         if (cells.get(position).isValidSpawn)  { | ||||
|           validSpawns.push(position); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     let player = choose(validSpawns); | ||||
|     cells.get(player).content = {type: "empty"}; | ||||
|  | ||||
|     if (Math.random() < 0.75) { | ||||
|       while (true) { | ||||
|         let x = Math.floor(Math.random() * cells.size.w); | ||||
|         let y = Math.floor(Math.random() * cells.size.h); | ||||
|         let xy = new Point(x, y); | ||||
|  | ||||
|         let item = cells.get(new Point(x, y)); | ||||
|         if (player.equals(xy)) { | ||||
|           continue; | ||||
|         } | ||||
|         if (item.content.type == "block") { | ||||
|           continue; | ||||
|         } | ||||
|         item.content = {type: "stairs"} | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     let hm = new HuntMode({depth, cells, player}) | ||||
|     hm.#updateVisibilityAndPossibleMoves(); | ||||
|     return hm; | ||||
|   } | ||||
|  | ||||
|   static #generateCell(conceptual: ConceptualCell): MapCell { | ||||
|     switch (conceptual) { | ||||
|       case "X": | ||||
|         return { content: {type: "block"}, revealed: false, isValidSpawn: false, nextMoveAccessible: false}; | ||||
|       case " ": | ||||
|         return { content: HuntMode.#generateContent(), revealed: false, isValidSpawn: false, nextMoveAccessible: false }; | ||||
|       case ".": | ||||
|         return { content: HuntMode.#generateContent(), revealed: false, isValidSpawn: true, nextMoveAccessible: false }; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   static #generateBoundaryCell() { | ||||
|     return this.#generateCell("X"); | ||||
|   } | ||||
|  | ||||
|   static #generateContent(): MapCellContent { | ||||
|     // stat pickup | ||||
|     let gsp = (): MapCellContent => { | ||||
|       return {type: "statPickup", stat: choose(ALL_STATS)} | ||||
|     }; | ||||
|     // TODO: Other objects? | ||||
|     return choose([ | ||||
|       gsp, gsp, gsp, gsp | ||||
|     ])(); | ||||
|   } | ||||
|  | ||||
|   // == update logic == | ||||
|   #updateVisibilityAndPossibleMoves() { | ||||
|     for (let x = 0; x < this.cells.size.w; x++) { | ||||
|       for (let y = 0; y < this.cells.size.h; y++) { | ||||
|         let position = new Point(x, y); | ||||
|         let data = this.cells.get(position); | ||||
|  | ||||
|         data.nextMoveAccessible = false; | ||||
|         if ( | ||||
|           Math.abs(x - this.player.x) <= 1 && | ||||
|           Math.abs(y - this.player.y) <= 1 | ||||
|         ) { | ||||
|           data.revealed = true; | ||||
|           if (!this.player.equals(position)) { | ||||
|             data.nextMoveAccessible = true; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   #collectResources() { | ||||
|     let present = this.cells.get(this.player); | ||||
|     if (present.content.type == "statPickup") { | ||||
|       present.content = {type: "empty"}; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   movePlayerTo(newPosition: Point) { | ||||
|     this.player = newPosition; | ||||
|     this.#updateVisibilityAndPossibleMoves(); | ||||
|     this.#collectResources(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| function choose<T>(array: Array<T>): T  { | ||||
|   if (array.length == 0) { | ||||
|     throw `array cannot have length 0 for choose` | ||||
|   } | ||||
|   return array[Math.floor(Math.random() * array.length)] | ||||
| } | ||||
							
								
								
									
										10
									
								
								src/maps.ts
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/maps.ts
									
									
									
									
									
								
							| @@ -1,15 +1,5 @@ | ||||
| import {Grid} from "./engine/datatypes.ts"; | ||||
|  | ||||
| export const mapSzX = 12; | ||||
| export const mapSzY= 9; | ||||
|  | ||||
| export function checkGrid<T>(grid: Grid<T>): Grid<T> { | ||||
|   if (grid.size.w != mapSzX || grid.size.h != mapSzY) { | ||||
|     throw `map must be ${mapSzX}x${mapSzY}, not ${grid.size}` | ||||
|   } | ||||
|   return grid; | ||||
| } | ||||
|  | ||||
| export type ConceptualCell = "X" | "." | " "; | ||||
|  | ||||
| function loadMap(map: Array<string>): Grid<ConceptualCell> { | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import imgSnake from "./art/characters/snake.png"; | ||||
| import imgRaccoon from "./art/characters/raccoon.png"; | ||||
| import imgRaccoonWalking from "./art/characters/raccoon_walking.png"; | ||||
| import imgStatPickup from "./art/pickups/stats.png"; | ||||
| import imgDrips from "./art/tilesets/drips.png"; | ||||
| import {Point, Size} from "./engine/datatypes.ts"; | ||||
|  | ||||
| /* | ||||
| @@ -29,6 +30,11 @@ export let sprRaccoonWalking = new Sprite( | ||||
| ); | ||||
|  | ||||
| export let sprStatPickup = new Sprite( | ||||
|   imgStatPickup, new Size(32, 32), new Point(16, 26), | ||||
|   imgStatPickup, new Size(32, 32), new Point(16, 16), | ||||
|   new Size(4, 1), 4 | ||||
| ); | ||||
|  | ||||
| export let sprDrips = new Sprite( | ||||
|   imgDrips, new Size(32, 24), new Point(16, 0), | ||||
|   new Size(2, 1), 2 | ||||
| ); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user