Use wall + floor assets from Pixel dungeon

This commit is contained in:
Peter Stockings
2026-01-04 16:46:49 +11:00
parent 6a050ac7a9
commit 42cd77998d
7 changed files with 152 additions and 131 deletions

BIN
public/assets/tiles0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -30,7 +30,7 @@ export const GAME_CONFIG = {
}, },
rendering: { rendering: {
tileSize: 24, tileSize: 16,
cameraZoom: 2, cameraZoom: 2,
wallColor: 0x2b2b2b, wallColor: 0x2b2b2b,
floorColor: 0x161616, floorColor: 0x161616,
@@ -45,6 +45,15 @@ export const GAME_CONFIG = {
visibleStrengthFactor: 0.65 visibleStrengthFactor: 0.65
}, },
terrain: {
empty: 1,
wall: 4,
water: 63,
emptyDeco: 24,
wallDeco: 12,
exit: 8
},
ui: { ui: {
minimapPanelWidth: 340, minimapPanelWidth: 340,
minimapPanelHeight: 220, minimapPanelHeight: 220,

View File

@@ -2,7 +2,7 @@ export type EntityId = number;
export type Vec2 = { x: number; y: number }; export type Vec2 = { x: number; y: number };
export type Tile = 0 | 1; // 0 = floor, 1 = wall export type Tile = number;
export type Action = export type Action =
| { type: "move"; dx: number; dy: number } | { type: "move"; dx: number; dy: number }

View File

@@ -19,7 +19,7 @@ interface Room {
export function generateWorld(level: number, runState: RunState): { world: World; playerId: EntityId } { export function generateWorld(level: number, runState: RunState): { world: World; playerId: EntityId } {
const width = GAME_CONFIG.map.width; const width = GAME_CONFIG.map.width;
const height = GAME_CONFIG.map.height; const height = GAME_CONFIG.map.height;
const tiles: Tile[] = new Array(width * height).fill(1); // Start with all walls const tiles: Tile[] = new Array(width * height).fill(GAME_CONFIG.terrain.wall); // Start with all walls
const random = seededRandom(level * 12345); const random = seededRandom(level * 12345);
@@ -52,6 +52,8 @@ export function generateWorld(level: number, runState: RunState): { world: World
placeEnemies(level, rooms, actors, random); placeEnemies(level, rooms, actors, random);
decorate(width, height, tiles, random, exit);
return { world: { width, height, tiles, actors, exit }, playerId }; return { world: { width, height, tiles, actors, exit }, playerId };
} }
@@ -99,7 +101,7 @@ function doesOverlap(newRoom: Room, rooms: Room[]): boolean {
function carveRoom(room: Room, tiles: Tile[], world: any): void { function carveRoom(room: Room, tiles: Tile[], world: any): void {
for (let x = room.x; x < room.x + room.width; x++) { for (let x = room.x; x < room.x + room.width; x++) {
for (let y = room.y; y < room.y + room.height; y++) { for (let y = room.y; y < room.y + room.height; y++) {
tiles[idx(world, x, y)] = 0; tiles[idx(world, x, y)] = GAME_CONFIG.terrain.empty;
} }
} }
} }
@@ -113,22 +115,95 @@ function carveCorridor(room1: Room, room2: Room, tiles: Tile[], world: any, rand
if (random() < 0.5) { if (random() < 0.5) {
// Horizontal then vertical // Horizontal then vertical
for (let x = Math.min(x1, x2); x <= Math.max(x1, x2); x++) { for (let x = Math.min(x1, x2); x <= Math.max(x1, x2); x++) {
tiles[idx(world, x, y1)] = 0; tiles[idx(world, x, y1)] = GAME_CONFIG.terrain.empty;
} }
for (let y = Math.min(y1, y2); y <= Math.max(y1, y2); y++) { for (let y = Math.min(y1, y2); y <= Math.max(y1, y2); y++) {
tiles[idx(world, x2, y)] = 0; tiles[idx(world, x2, y)] = GAME_CONFIG.terrain.empty;
} }
} else { } else {
// Vertical then horizontal // Vertical then horizontal
for (let y = Math.min(y1, y2); y <= Math.max(y1, y2); y++) { for (let y = Math.min(y1, y2); y <= Math.max(y1, y2); y++) {
tiles[idx(world, x1, y)] = 0; tiles[idx(world, x1, y)] = GAME_CONFIG.terrain.empty;
} }
for (let x = Math.min(x1, x2); x <= Math.max(x1, x2); x++) { for (let x = Math.min(x1, x2); x <= Math.max(x1, x2); x++) {
tiles[idx(world, x, y2)] = 0; tiles[idx(world, x, y2)] = GAME_CONFIG.terrain.empty;
} }
} }
} }
function decorate(width: number, height: number, tiles: Tile[], random: () => number, exit: Vec2): void {
const world = { width, height };
// Set exit tile
tiles[idx(world as any, exit.x, exit.y)] = GAME_CONFIG.terrain.exit;
// Add water patches (similar to PD Sewers)
const waterMask = generatePatch(width, height, 0.45, 5, random);
for (let i = 0; i < tiles.length; i++) {
if (tiles[i] === GAME_CONFIG.terrain.empty && waterMask[i]) {
tiles[i] = GAME_CONFIG.terrain.water;
}
}
// Wall decorations
for (let y = 0; y < height - 1; y++) {
for (let x = 0; x < width; x++) {
const i = idx(world as any, x, y);
const nextY = idx(world as any, x, y + 1);
if (tiles[i] === GAME_CONFIG.terrain.wall &&
tiles[nextY] === GAME_CONFIG.terrain.water &&
random() < 0.25) {
tiles[i] = GAME_CONFIG.terrain.wallDeco;
}
}
}
// Floor decorations (moss)
for (let y = 1; y < height - 1; y++) {
for (let x = 1; x < width - 1; x++) {
const i = idx(world as any, x, y);
if (tiles[i] === GAME_CONFIG.terrain.empty) {
let wallCount = 0;
if (tiles[idx(world as any, x + 1, y)] === GAME_CONFIG.terrain.wall) wallCount++;
if (tiles[idx(world as any, x - 1, y)] === GAME_CONFIG.terrain.wall) wallCount++;
if (tiles[idx(world as any, x, y + 1)] === GAME_CONFIG.terrain.wall) wallCount++;
if (tiles[idx(world as any, x, y - 1)] === GAME_CONFIG.terrain.wall) wallCount++;
if (random() * 16 < wallCount * wallCount) {
tiles[i] = GAME_CONFIG.terrain.emptyDeco;
}
}
}
}
}
/**
* Simple cellular automata for generating patches of terrain
*/
function generatePatch(width: number, height: number, fillChance: number, iterations: number, random: () => number): boolean[] {
let map = new Array(width * height).fill(false).map(() => random() < fillChance);
for (let step = 0; step < iterations; step++) {
const nextMap = new Array(width * height).fill(false);
for (let y = 1; y < height - 1; y++) {
for (let x = 1; x < width - 1; x++) {
let neighbors = 0;
for (let dy = -1; dy <= 1; dy++) {
for (let dx = -1; dx <= 1; dx++) {
if (map[(y + dy) * width + (x + dx)]) neighbors++;
}
}
if (neighbors > 4) nextMap[y * width + x] = true;
else if (neighbors < 4) nextMap[y * width + x] = false;
else nextMap[y * width + x] = map[y * width + x];
}
}
map = nextMap;
}
return map;
}
function placeEnemies(level: number, rooms: Room[], actors: Map<EntityId, Actor>, random: () => number): void { function placeEnemies(level: number, rooms: Room[], actors: Map<EntityId, Actor>, random: () => number): void {
let enemyId = 2; let enemyId = 2;
const numEnemies = GAME_CONFIG.enemy.baseCount + level * GAME_CONFIG.enemy.baseCountPerLevel + Math.floor(random() * GAME_CONFIG.enemy.randomBonus); const numEnemies = GAME_CONFIG.enemy.baseCount + level * GAME_CONFIG.enemy.baseCountPerLevel + Math.floor(random() * GAME_CONFIG.enemy.randomBonus);

View File

@@ -1,4 +1,5 @@
import type { World, EntityId } from "../../core/types"; import type { World, EntityId } from "../../core/types";
import { GAME_CONFIG } from "../../core/config/GameConfig";
export function inBounds(w: World, x: number, y: number): boolean { export function inBounds(w: World, x: number, y: number): boolean {
return x >= 0 && y >= 0 && x < w.width && y < w.height; return x >= 0 && y >= 0 && x < w.width && y < w.height;
@@ -9,7 +10,8 @@ export function idx(w: World, x: number, y: number): number {
} }
export function isWall(w: World, x: number, y: number): boolean { export function isWall(w: World, x: number, y: number): boolean {
return w.tiles[idx(w, x, y)] === 1; const tile = w.tiles[idx(w, x, y)];
return tile === GAME_CONFIG.terrain.wall || tile === GAME_CONFIG.terrain.wallDeco;
} }
export function isBlocked(w: World, x: number, y: number): boolean { export function isBlocked(w: World, x: number, y: number): boolean {

View File

@@ -7,7 +7,9 @@ import { GAME_CONFIG } from "../core/config/GameConfig";
export class DungeonRenderer { export class DungeonRenderer {
private scene: Phaser.Scene; private scene: Phaser.Scene;
private gfx: Phaser.GameObjects.Graphics; private map?: Phaser.Tilemaps.Tilemap;
private layer?: Phaser.Tilemaps.TilemapLayer;
private playerSprite?: Phaser.GameObjects.Sprite; private playerSprite?: Phaser.GameObjects.Sprite;
private enemySprites: Map<EntityId, Phaser.GameObjects.Sprite> = new Map(); private enemySprites: Map<EntityId, Phaser.GameObjects.Sprite> = new Map();
private corpseSprites: Phaser.GameObjects.Sprite[] = []; private corpseSprites: Phaser.GameObjects.Sprite[] = [];
@@ -25,36 +27,28 @@ export class DungeonRenderer {
private minimapGfx!: Phaser.GameObjects.Graphics; private minimapGfx!: Phaser.GameObjects.Graphics;
private minimapContainer!: Phaser.GameObjects.Container; private minimapContainer!: Phaser.GameObjects.Container;
private minimapBg!: Phaser.GameObjects.Rectangle; private minimapBg!: Phaser.GameObjects.Rectangle;
private minimapVisible = false; // Off by default private minimapVisible = false;
constructor(scene: Phaser.Scene) { constructor(scene: Phaser.Scene) {
this.scene = scene; this.scene = scene;
this.gfx = this.scene.add.graphics();
// Initialize minimap
this.initMinimap(); this.initMinimap();
} }
private initMinimap() { private initMinimap() {
this.minimapContainer = this.scene.add.container(0, 0); this.minimapContainer = this.scene.add.container(0, 0);
this.minimapContainer.setScrollFactor(0); // Fixed to camera this.minimapContainer.setScrollFactor(0);
this.minimapContainer.setDepth(1001); // Same as menu this.minimapContainer.setDepth(1001);
// Background panel (like menu)
this.minimapBg = this.scene.add this.minimapBg = this.scene.add
.rectangle(0, 0, GAME_CONFIG.ui.minimapPanelWidth, GAME_CONFIG.ui.minimapPanelHeight, 0x000000, 0.8) .rectangle(0, 0, GAME_CONFIG.ui.minimapPanelWidth, GAME_CONFIG.ui.minimapPanelHeight, 0x000000, 0.8)
.setStrokeStyle(1, 0xffffff, 0.9) .setStrokeStyle(1, 0xffffff, 0.9)
.setInteractive(); // Capture clicks .setInteractive();
this.minimapGfx = this.scene.add.graphics(); this.minimapGfx = this.scene.add.graphics();
this.minimapContainer.add(this.minimapBg); this.minimapContainer.add(this.minimapBg);
this.minimapContainer.add(this.minimapGfx); this.minimapContainer.add(this.minimapGfx);
// Position in center
this.positionMinimap(); this.positionMinimap();
// Start hidden
this.minimapContainer.setVisible(false); this.minimapContainer.setVisible(false);
} }
@@ -64,6 +58,25 @@ export class DungeonRenderer {
this.visible = new Uint8Array(this.world.width * this.world.height); this.visible = new Uint8Array(this.world.width * this.world.height);
this.visibleStrength = new Float32Array(this.world.width * this.world.height); this.visibleStrength = new Float32Array(this.world.width * this.world.height);
// Setup Tilemap
if (this.map) this.map.destroy();
this.map = this.scene.make.tilemap({
data: Array.from({ length: world.height }, (_, y) =>
Array.from({ length: world.width }, (_, x) => this.world.tiles[idx(this.world, x, y)])
),
tileWidth: 16,
tileHeight: 16
});
const tileset = this.map.addTilesetImage("tiles0", "tiles0", 16, 16, 0, 0)!;
this.layer = this.map.createLayer(0, tileset, 0, 0)!;
this.layer.setDepth(0);
// Initial tile states (hidden)
this.layer.forEachTile(tile => {
tile.setVisible(false);
});
// Clear old corpses // Clear old corpses
for (const sprite of this.corpseSprites) { for (const sprite of this.corpseSprites) {
sprite.destroy(); sprite.destroy();
@@ -75,11 +88,10 @@ export class DungeonRenderer {
this.playerSprite = this.scene.add.sprite(0, 0, "warrior", 0); this.playerSprite = this.scene.add.sprite(0, 0, "warrior", 0);
this.playerSprite.setDepth(100); this.playerSprite.setDepth(100);
// Calculate display size to fit within tile while maintaining 12:15 aspect ratio // Calculate scale to fit 15px high sprite into 16px tile
const scale = TILE_SIZE / 15; // Fit height to tile size const scale = 1.0;
this.playerSprite.setScale(scale); this.playerSprite.setScale(scale);
// Simple animations from PD source
this.scene.anims.create({ this.scene.anims.create({
key: 'warrior-idle', key: 'warrior-idle',
frames: this.scene.anims.generateFrameNumbers('warrior', { frames: [0, 0, 0, 1, 0, 0, 1, 1] }), frames: this.scene.anims.generateFrameNumbers('warrior', { frames: [0, 0, 0, 1, 0, 0, 1, 1] }),
@@ -104,7 +116,7 @@ export class DungeonRenderer {
this.playerSprite.play('warrior-idle'); this.playerSprite.play('warrior-idle');
} }
// Rat animations // Enemy animations
if (!this.scene.anims.exists('rat-idle')) { if (!this.scene.anims.exists('rat-idle')) {
this.scene.anims.create({ this.scene.anims.create({
key: 'rat-idle', key: 'rat-idle',
@@ -126,7 +138,6 @@ export class DungeonRenderer {
}); });
} }
// Bat animations
if (!this.scene.anims.exists('bat-idle')) { if (!this.scene.anims.exists('bat-idle')) {
this.scene.anims.create({ this.scene.anims.create({
key: 'bat-idle', key: 'bat-idle',
@@ -153,13 +164,11 @@ export class DungeonRenderer {
return !isWall(this.world, x, y); return !isWall(this.world, x, y);
}); });
// Position minimap
this.positionMinimap(); this.positionMinimap();
} }
private positionMinimap() { private positionMinimap() {
const cam = this.scene.cameras.main; const cam = this.scene.cameras.main;
// Center on screen like menu
this.minimapContainer.setPosition(cam.width / 2, cam.height / 2); this.minimapContainer.setPosition(cam.width / 2, cam.height / 2);
} }
@@ -187,7 +196,6 @@ export class DungeonRenderer {
this.visible[i] = 1; this.visible[i] = 1;
this.seen[i] = 1; this.seen[i] = 1;
// falloff: 1 at center, ~0.4 at radius edge
const radiusT = Phaser.Math.Clamp(r / GAME_CONFIG.player.viewRadius, 0, 1); const radiusT = Phaser.Math.Clamp(r / GAME_CONFIG.player.viewRadius, 0, 1);
const falloff = 1 - radiusT * 0.6; const falloff = 1 - radiusT * 0.6;
const strength = Phaser.Math.Clamp(v * falloff, 0, 1); const strength = Phaser.Math.Clamp(v * falloff, 0, 1);
@@ -205,67 +213,31 @@ export class DungeonRenderer {
return this.seen; return this.seen;
} }
render(playerPath: Vec2[]) { render(_playerPath: Vec2[]) {
this.gfx.clear(); if (!this.world || !this.layer) return;
if (!this.world) return;
// Tiles w/ fog + falloff + silhouettes
for (let y = 0; y < this.world.height; y++) {
for (let x = 0; x < this.world.width; x++) {
const i = idx(this.world, x, y);
// Update Tiles
this.layer.forEachTile(tile => {
const i = idx(this.world, tile.x, tile.y);
const isSeen = this.seen[i] === 1; const isSeen = this.seen[i] === 1;
const isVis = this.visible[i] === 1; const isVis = this.visible[i] === 1;
if (!isSeen) { if (!isSeen) {
this.gfx.fillStyle(0x000000, 1); tile.setVisible(false);
this.gfx.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);
continue;
}
const wall = isWall(this.world, x, y);
const base = wall ? GAME_CONFIG.rendering.wallColor : GAME_CONFIG.rendering.floorColor;
let alpha: number;
if (isVis) {
const s = this.visibleStrength[i];
alpha = Phaser.Math.Clamp(GAME_CONFIG.rendering.visibleMinAlpha + s * GAME_CONFIG.rendering.visibleStrengthFactor, GAME_CONFIG.rendering.visibleMinAlpha, GAME_CONFIG.rendering.visibleMaxAlpha);
} else { } else {
alpha = wall ? GAME_CONFIG.rendering.fogAlphaWall : GAME_CONFIG.rendering.fogAlphaFloor; tile.setVisible(true);
if (isVis) {
tile.alpha = 1.0;
tile.tint = 0xffffff;
} else {
tile.alpha = isWall(this.world, tile.x, tile.y) ? 0.4 : 0.2;
tile.tint = 0x888888;
} }
}
});
this.gfx.fillStyle(base, alpha); // Actors
this.gfx.fillRect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);
}
}
// Exit (stairs) if seen
{
const ex = this.world.exit.x;
const ey = this.world.exit.y;
const i = idx(this.world, ex, ey);
if (this.seen[i] === 1) {
const alpha = this.visible[i] === 1 ? 1.0 : GAME_CONFIG.rendering.visibleMinAlpha;
this.gfx.fillStyle(GAME_CONFIG.rendering.exitColor, alpha);
this.gfx.fillRect(ex * TILE_SIZE + 7, ey * TILE_SIZE + 7, TILE_SIZE - 14, TILE_SIZE - 14);
}
}
// Path preview (seen only)
if (playerPath.length >= 2) {
this.gfx.fillStyle(GAME_CONFIG.rendering.pathPreviewColor, GAME_CONFIG.rendering.visibleMinAlpha);
for (const p of playerPath) {
// We can check isSeen via internal helper or just local array since we're inside
const i = idx(this.world, p.x, p.y);
if (this.seen[i] !== 1) continue;
this.gfx.fillRect(p.x * TILE_SIZE + 6, p.y * TILE_SIZE + 6, TILE_SIZE - 12, TILE_SIZE - 12);
}
}
// Actors (enemies only if visible)
const activeEnemyIds = new Set<EntityId>(); const activeEnemyIds = new Set<EntityId>();
for (const a of this.world.actors.values()) { for (const a of this.world.actors.values()) {
const i = idx(this.world, a.pos.x, a.pos.y); const i = idx(this.world, a.pos.x, a.pos.y);
const isVis = this.visible[i] === 1; const isVis = this.visible[i] === 1;
@@ -282,14 +254,11 @@ export class DungeonRenderer {
activeEnemyIds.add(a.id); activeEnemyIds.add(a.id);
let sprite = this.enemySprites.get(a.id); let sprite = this.enemySprites.get(a.id);
const textureKey = a.type === "bat" ? "bat" : "rat"; const textureKey = a.type === "bat" ? "bat" : "rat";
if (!sprite) { if (!sprite) {
sprite = this.scene.add.sprite(0, 0, textureKey, 0); sprite = this.scene.add.sprite(0, 0, textureKey, 0);
sprite.setDepth(99); sprite.setDepth(99);
const scale = TILE_SIZE / 15;
sprite.setScale(scale);
sprite.play(`${textureKey}-idle`); sprite.play(`${textureKey}-idle`);
this.enemySprites.set(a.id, sprite); this.enemySprites.set(a.id, sprite);
} }
@@ -298,11 +267,9 @@ export class DungeonRenderer {
sprite.setVisible(true); sprite.setVisible(true);
} }
// Hide/Cleanup inactive/non-visible enemy sprites
for (const [id, sprite] of this.enemySprites.entries()) { for (const [id, sprite] of this.enemySprites.entries()) {
if (!activeEnemyIds.has(id)) { if (!activeEnemyIds.has(id)) {
sprite.setVisible(false); sprite.setVisible(false);
// We could also destroy if they are dead, but hide is safer for now
if (!this.world.actors.has(id)) { if (!this.world.actors.has(id)) {
sprite.destroy(); sprite.destroy();
this.enemySprites.delete(id); this.enemySprites.delete(id);
@@ -310,16 +277,13 @@ export class DungeonRenderer {
} }
} }
// Render minimap
this.renderMinimap(); this.renderMinimap();
} }
private renderMinimap() { private renderMinimap() {
this.minimapGfx.clear(); this.minimapGfx.clear();
if (!this.world) return; if (!this.world) return;
// Calculate scale to fit map within panel
const padding = GAME_CONFIG.ui.minimapPadding; const padding = GAME_CONFIG.ui.minimapPadding;
const availableWidth = GAME_CONFIG.ui.minimapPanelWidth - padding * 2; const availableWidth = GAME_CONFIG.ui.minimapPanelWidth - padding * 2;
const availableHeight = GAME_CONFIG.ui.minimapPanelHeight - padding * 2; const availableHeight = GAME_CONFIG.ui.minimapPanelHeight - padding * 2;
@@ -328,73 +292,44 @@ export class DungeonRenderer {
const scaleY = availableHeight / this.world.height; const scaleY = availableHeight / this.world.height;
const tileSize = Math.floor(Math.min(scaleX, scaleY)); const tileSize = Math.floor(Math.min(scaleX, scaleY));
// Center the map within the panel
const mapPixelWidth = this.world.width * tileSize; const mapPixelWidth = this.world.width * tileSize;
const mapPixelHeight = this.world.height * tileSize; const mapPixelHeight = this.world.height * tileSize;
const offsetX = -mapPixelWidth / 2; const offsetX = -mapPixelWidth / 2;
const offsetY = -mapPixelHeight / 2; const offsetY = -mapPixelHeight / 2;
// Draw only seen tiles
for (let y = 0; y < this.world.height; y++) { for (let y = 0; y < this.world.height; y++) {
for (let x = 0; x < this.world.width; x++) { for (let x = 0; x < this.world.width; x++) {
const i = idx(this.world, x, y); const i = idx(this.world, x, y);
const isSeen = this.seen[i] === 1; if (this.seen[i] !== 1) continue;
if (!isSeen) continue;
const wall = isWall(this.world, x, y); const wall = isWall(this.world, x, y);
const color = wall ? 0x666666 : 0x333333; const color = wall ? 0x666666 : 0x333333;
this.minimapGfx.fillStyle(color, 1); this.minimapGfx.fillStyle(color, 1);
this.minimapGfx.fillRect( this.minimapGfx.fillRect(offsetX + x * tileSize, offsetY + y * tileSize, tileSize, tileSize);
offsetX + x * tileSize,
offsetY + y * tileSize,
tileSize,
tileSize
);
} }
} }
// Draw exit if seen
const ex = this.world.exit.x; const ex = this.world.exit.x;
const ey = this.world.exit.y; const ey = this.world.exit.y;
const exitIdx = idx(this.world, ex, ey); if (this.seen[idx(this.world, ex, ey)] === 1) {
if (this.seen[exitIdx] === 1) {
this.minimapGfx.fillStyle(0xffd166, 1); this.minimapGfx.fillStyle(0xffd166, 1);
this.minimapGfx.fillRect( this.minimapGfx.fillRect(offsetX + ex * tileSize, offsetY + ey * tileSize, tileSize, tileSize);
offsetX + ex * tileSize,
offsetY + ey * tileSize,
tileSize,
tileSize
);
} }
// Draw player
const player = [...this.world.actors.values()].find(a => a.isPlayer); const player = [...this.world.actors.values()].find(a => a.isPlayer);
if (player) { if (player) {
this.minimapGfx.fillStyle(0x66ff66, 1); this.minimapGfx.fillStyle(0x66ff66, 1);
this.minimapGfx.fillRect( this.minimapGfx.fillRect(offsetX + player.pos.x * tileSize, offsetY + player.pos.y * tileSize, tileSize, tileSize);
offsetX + player.pos.x * tileSize,
offsetY + player.pos.y * tileSize,
tileSize,
tileSize
);
} }
// Draw visible enemies
for (const a of this.world.actors.values()) { for (const a of this.world.actors.values()) {
if (a.isPlayer) continue; if (a.isPlayer) continue;
const i = idx(this.world, a.pos.x, a.pos.y); const i = idx(this.world, a.pos.x, a.pos.y);
const isVis = this.visible[i] === 1; if (this.visible[i] === 1) {
if (!isVis) continue;
this.minimapGfx.fillStyle(0xff6666, 1); this.minimapGfx.fillStyle(0xff6666, 1);
this.minimapGfx.fillRect( this.minimapGfx.fillRect(offsetX + a.pos.x * tileSize, offsetY + a.pos.y * tileSize, tileSize, tileSize);
offsetX + a.pos.x * tileSize, }
offsetY + a.pos.y * tileSize,
tileSize,
tileSize
);
} }
} }
@@ -429,7 +364,6 @@ export class DungeonRenderer {
0 0
); );
corpse.setDepth(50); corpse.setDepth(50);
corpse.setScale(TILE_SIZE / 15);
corpse.play(`${textureKey}-die`); corpse.play(`${textureKey}-die`);
this.corpseSprites.push(corpse); this.corpseSprites.push(corpse);
} }

View File

@@ -42,6 +42,7 @@ export class GameScene extends Phaser.Scene {
this.load.spritesheet("warrior", "warrior.png", { frameWidth: 12, frameHeight: 15 }); this.load.spritesheet("warrior", "warrior.png", { frameWidth: 12, frameHeight: 15 });
this.load.spritesheet("rat", "rat.png", { frameWidth: 16, frameHeight: 15 }); this.load.spritesheet("rat", "rat.png", { frameWidth: 16, frameHeight: 15 });
this.load.spritesheet("bat", "bat.png", { frameWidth: 15, frameHeight: 15 }); this.load.spritesheet("bat", "bat.png", { frameWidth: 15, frameHeight: 15 });
this.load.spritesheet("tiles0", "assets/tiles0.png", { frameWidth: 16, frameHeight: 16 });
} }
create() { create() {