Door locking
This commit is contained in:
parent
c793d0a20c
commit
8146782fec
|
|
@ -6,6 +6,7 @@ export default class Character extends Item {
|
||||||
public health: number;
|
public health: number;
|
||||||
public inventory: Item[] = [];
|
public inventory: Item[] = [];
|
||||||
public tile: Tile = new Tile([0, 0], 1);
|
public tile: Tile = new Tile([0, 0], 1);
|
||||||
|
public lastDoor: Tile | undefined;
|
||||||
|
|
||||||
constructor(type: ItemTypeImage) {
|
constructor(type: ItemTypeImage) {
|
||||||
super(type);
|
super(type);
|
||||||
|
|
@ -76,6 +77,15 @@ export default class Character extends Item {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public hasItem(item: Item | null | undefined): boolean {
|
||||||
|
if (!item) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const itemIndex = this.inventory.findIndex(i => i === item);
|
||||||
|
|
||||||
|
return itemIndex >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** @returns true, if action was performed */
|
/** @returns true, if action was performed */
|
||||||
public handleSpin(action: SpinnerAction): boolean {
|
public handleSpin(action: SpinnerAction): boolean {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { createCanvas } from "@common/display/canvas";
|
||||||
import Spinner from "./spinner";
|
import Spinner from "./spinner";
|
||||||
import type Entity from "./entity";
|
import type Entity from "./entity";
|
||||||
import { getRealPoint } from "@common/dom";
|
import { getRealPoint } from "@common/dom";
|
||||||
import { nextFrame } from "@common/utils";
|
import { clamp, nextFrame } from "@common/utils";
|
||||||
import bgImg from './assets/bg.jpg';
|
import bgImg from './assets/bg.jpg';
|
||||||
import TileMap from "./tilemap";
|
import TileMap from "./tilemap";
|
||||||
import Inventory from "./inventory";
|
import Inventory from "./inventory";
|
||||||
|
|
@ -11,18 +11,18 @@ const MAP_SIZE = 12;
|
||||||
const MAP_PIXEL_SIZE = window.innerHeight;
|
const MAP_PIXEL_SIZE = window.innerHeight;
|
||||||
const MAP_PADDING = 10;
|
const MAP_PADDING = 10;
|
||||||
const TILE_SIZE = (MAP_PIXEL_SIZE - MAP_PADDING * 2) / MAP_SIZE;
|
const TILE_SIZE = (MAP_PIXEL_SIZE - MAP_PADDING * 2) / MAP_SIZE;
|
||||||
const SIDEBAR_SIZE = Math.min((window.innerWidth - window.innerHeight) / 2, 400);
|
const SIDEBAR_SIZE = clamp((window.innerWidth - window.innerHeight) / 2, 300, 600);
|
||||||
|
|
||||||
const canvas = createCanvas(MAP_PIXEL_SIZE + SIDEBAR_SIZE * 2, MAP_PIXEL_SIZE);
|
const canvas = createCanvas(MAP_PIXEL_SIZE + SIDEBAR_SIZE * 2, MAP_PIXEL_SIZE);
|
||||||
const map = new TileMap(
|
const map = new TileMap(
|
||||||
[MAP_PADDING, MAP_PADDING],
|
[MAP_PADDING + SIDEBAR_SIZE, MAP_PADDING],
|
||||||
MAP_SIZE,
|
MAP_SIZE,
|
||||||
TILE_SIZE,
|
TILE_SIZE,
|
||||||
);
|
);
|
||||||
const spinner = new Spinner([MAP_PIXEL_SIZE, 0], [SIDEBAR_SIZE, SIDEBAR_SIZE]);
|
const spinner = new Spinner([MAP_PIXEL_SIZE + SIDEBAR_SIZE, 0], [SIDEBAR_SIZE, SIDEBAR_SIZE]);
|
||||||
const inventory = new Inventory(
|
const inventory = new Inventory(
|
||||||
map,
|
map,
|
||||||
[MAP_PIXEL_SIZE + SIDEBAR_SIZE, 0],
|
[0, 0],
|
||||||
[SIDEBAR_SIZE, MAP_PIXEL_SIZE],
|
[SIDEBAR_SIZE, MAP_PIXEL_SIZE],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -43,7 +43,7 @@ async function render(ctx: CanvasRenderingContext2D) {
|
||||||
ctx.fillStyle = 'white';
|
ctx.fillStyle = 'white';
|
||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
ctx.drawImage(bgImg, 0, 0, MAP_PIXEL_SIZE, MAP_PIXEL_SIZE);
|
ctx.drawImage(bgImg, SIDEBAR_SIZE, 0, MAP_PIXEL_SIZE, MAP_PIXEL_SIZE);
|
||||||
|
|
||||||
entities.forEach(entity => entity.render(ctx));
|
entities.forEach(entity => entity.render(ctx));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Pathfinding {
|
||||||
|
|
||||||
if (current !== start && current.items.length > 0) continue;
|
if (current !== start && current.items.length > 0) continue;
|
||||||
|
|
||||||
for (const neighbor of current.connections) {
|
for (const neighbor of current.activeConnections) {
|
||||||
// tentative gScore is current’s gScore plus cost to move to neighbor
|
// tentative gScore is current’s gScore plus cost to move to neighbor
|
||||||
const tentativeG = (gScore.get(current) ?? Infinity) + distance(current, neighbor);
|
const tentativeG = (gScore.get(current) ?? Infinity) + distance(current, neighbor);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ export default class Tile extends Entity {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected draw(ctx: CanvasRenderingContext2D) {
|
protected draw(ctx: CanvasRenderingContext2D) {
|
||||||
|
ctx.font = '0.2px Arial';
|
||||||
|
|
||||||
if (this.hovered) {
|
if (this.hovered) {
|
||||||
ctx.fillStyle = `rgba(255, 255, 255, 0.2)`;
|
ctx.fillStyle = `rgba(255, 255, 255, 0.2)`;
|
||||||
ctx.fillRect(0, 0, 1, 1);
|
ctx.fillRect(0, 0, 1, 1);
|
||||||
|
|
@ -41,30 +43,46 @@ export default class Tile extends Entity {
|
||||||
}
|
}
|
||||||
if (this.items.length > 0) {
|
if (this.items.length > 0) {
|
||||||
if (this.isOpen) {
|
if (this.isOpen) {
|
||||||
const item = this.items[0];
|
const item = this.enemy ?? this.items[0];
|
||||||
ctx.drawImage(item.type, 0.1, 0.1, 0.8, 0.8);
|
ctx.drawImage(item.type, 0.1, 0.1, 0.8, 0.8);
|
||||||
|
|
||||||
if (this.items.length > 1) {
|
if (this.items.length > 1) {
|
||||||
ctx.strokeStyle = 'red';
|
ctx.fillText('💀', 0.85, 0.15);
|
||||||
ctx.lineWidth = 2 / this.width;
|
|
||||||
|
|
||||||
ctx.strokeRect(0.1, 0.1, 0.8, 0.8);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx.fillStyle = 'white';
|
ctx.fillStyle = 'white';
|
||||||
ctx.fillRect(0.1, 0.1, 0.8, 0.8);
|
ctx.fillRect(0.1, 0.1, 0.8, 0.8);
|
||||||
|
|
||||||
ctx.fillStyle = 'black';
|
|
||||||
ctx.font = '0.2px Arial';
|
|
||||||
ctx.fillText('❓', 0.5, 0.5);
|
ctx.fillText('❓', 0.5, 0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.type === TileType.LOCKED_DOOR) {
|
||||||
|
const doorway = this.connections.find(t => t.type === TileType.DOORWAY);
|
||||||
|
let x = 0.5;
|
||||||
|
let y = 0.5;
|
||||||
|
|
||||||
|
if (doorway) {
|
||||||
|
x += (Number(this.left < doorway.left) - Number(doorway.left < this.left)) * 0.5;
|
||||||
|
y += (Number(this.top < doorway.top) - Number(doorway.top < this.top)) * 0.5;
|
||||||
|
}
|
||||||
|
ctx.font = `0.4px Arial`;
|
||||||
|
ctx.fillText('⛔', x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get enemy() {
|
get enemy() {
|
||||||
return this.items.find(i => i.isEnemy);
|
return this.items.find(i => i.isEnemy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get activeConnections() {
|
||||||
|
if (this.type === TileType.LOCKED_DOOR) {
|
||||||
|
return this.connections.filter(t => t.type !== TileType.DOORWAY);
|
||||||
|
}
|
||||||
|
if (this.type === TileType.DOORWAY) {
|
||||||
|
return this.connections.filter(t => t.type !== TileType.LOCKED_DOOR);
|
||||||
|
}
|
||||||
|
return this.connections;
|
||||||
|
}
|
||||||
|
|
||||||
public open() {
|
public open() {
|
||||||
this.isOpen = true;
|
this.isOpen = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,7 @@ export default class TileMap extends Entity {
|
||||||
if (tile.isPointInBounds(x - this.left, y - this.top)) {
|
if (tile.isPointInBounds(x - this.left, y - this.top)) {
|
||||||
const path = Pathfinding.findPath(this.character.tile, tile);
|
const path = Pathfinding.findPath(this.character.tile, tile);
|
||||||
if (path.length > 1) {
|
if (path.length > 1) {
|
||||||
|
this.character.lastDoor = path.find(t => t.type === TileType.DOOR);
|
||||||
this.character.tile = tile;
|
this.character.tile = tile;
|
||||||
tile.open();
|
tile.open();
|
||||||
for (const item of tile.items.slice()) { // iterate remaining items
|
for (const item of tile.items.slice()) { // iterate remaining items
|
||||||
|
|
@ -274,14 +275,22 @@ export default class TileMap extends Entity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public handleItemUse(character: Character, item: Item) {
|
public handleItemUse(character: Character, item: Item) {
|
||||||
const success = character.removeItem(item);
|
let success = character.hasItem(item);
|
||||||
if (success) {
|
if (success) {
|
||||||
if (item.type === ItemType.ITEM_HEAL) {
|
if (item.type === ItemType.ITEM_HEAL) {
|
||||||
character.heal(character);
|
character.heal(character);
|
||||||
} else if (item.type === ItemType.WEAPON_GRENADE && this.state === GameState.FIGHT) {
|
} else if (item.type === ItemType.WEAPON_GRENADE && this.state === GameState.FIGHT) {
|
||||||
this.killEnemy();
|
this.killEnemy();
|
||||||
|
} else if (item.type === ItemType.ITEM_PLANKS && character.lastDoor?.items.length === 0) {
|
||||||
|
character.lastDoor.type = TileType.LOCKED_DOOR;
|
||||||
|
} else {
|
||||||
|
success = false;
|
||||||
|
console.warn(`Dont know how to use ${item}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (success) {
|
||||||
|
character.removeItem(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private findAvailableTiles(moveDistance: number = 1) {
|
private findAvailableTiles(moveDistance: number = 1) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue