Use wall + floor assets from Pixel dungeon
This commit is contained in:
BIN
public/assets/tiles0.png
Normal file
BIN
public/assets/tiles0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -30,7 +30,7 @@ export const GAME_CONFIG = {
|
||||
},
|
||||
|
||||
rendering: {
|
||||
tileSize: 24,
|
||||
tileSize: 16,
|
||||
cameraZoom: 2,
|
||||
wallColor: 0x2b2b2b,
|
||||
floorColor: 0x161616,
|
||||
@@ -45,6 +45,15 @@ export const GAME_CONFIG = {
|
||||
visibleStrengthFactor: 0.65
|
||||
},
|
||||
|
||||
terrain: {
|
||||
empty: 1,
|
||||
wall: 4,
|
||||
water: 63,
|
||||
emptyDeco: 24,
|
||||
wallDeco: 12,
|
||||
exit: 8
|
||||
},
|
||||
|
||||
ui: {
|
||||
minimapPanelWidth: 340,
|
||||
minimapPanelHeight: 220,
|
||||
|
||||
@@ -2,7 +2,7 @@ export type EntityId = number;
|
||||
|
||||
export type Vec2 = { x: number; y: number };
|
||||
|
||||
export type Tile = 0 | 1; // 0 = floor, 1 = wall
|
||||
export type Tile = number;
|
||||
|
||||
export type Action =
|
||||
| { type: "move"; dx: number; dy: number }
|
||||
|
||||
@@ -19,7 +19,7 @@ interface Room {
|
||||
export function generateWorld(level: number, runState: RunState): { world: World; playerId: EntityId } {
|
||||
const width = GAME_CONFIG.map.width;
|
||||
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);
|
||||
|
||||
@@ -52,6 +52,8 @@ export function generateWorld(level: number, runState: RunState): { world: World
|
||||
|
||||
placeEnemies(level, rooms, actors, random);
|
||||
|
||||
decorate(width, height, tiles, random, exit);
|
||||
|
||||
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 {
|
||||
for (let x = room.x; x < room.x + room.width; x++) {
|
||||
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) {
|
||||
// Horizontal then vertical
|
||||
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++) {
|
||||
tiles[idx(world, x2, y)] = 0;
|
||||
tiles[idx(world, x2, y)] = GAME_CONFIG.terrain.empty;
|
||||
}
|
||||
} else {
|
||||
// Vertical then horizontal
|
||||
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++) {
|
||||
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 {
|
||||
let enemyId = 2;
|
||||
const numEnemies = GAME_CONFIG.enemy.baseCount + level * GAME_CONFIG.enemy.baseCountPerLevel + Math.floor(random() * GAME_CONFIG.enemy.randomBonus);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { World, EntityId } from "../../core/types";
|
||||
import { GAME_CONFIG } from "../../core/config/GameConfig";
|
||||
|
||||
export function inBounds(w: World, x: number, y: number): boolean {
|
||||
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 {
|
||||
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 {
|
||||
|
||||
@@ -7,7 +7,9 @@ import { GAME_CONFIG } from "../core/config/GameConfig";
|
||||
|
||||
export class DungeonRenderer {
|
||||
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 enemySprites: Map<EntityId, Phaser.GameObjects.Sprite> = new Map();
|
||||
private corpseSprites: Phaser.GameObjects.Sprite[] = [];
|
||||
@@ -25,36 +27,28 @@ export class DungeonRenderer {
|
||||
private minimapGfx!: Phaser.GameObjects.Graphics;
|
||||
private minimapContainer!: Phaser.GameObjects.Container;
|
||||
private minimapBg!: Phaser.GameObjects.Rectangle;
|
||||
private minimapVisible = false; // Off by default
|
||||
private minimapVisible = false;
|
||||
|
||||
constructor(scene: Phaser.Scene) {
|
||||
this.scene = scene;
|
||||
this.gfx = this.scene.add.graphics();
|
||||
|
||||
// Initialize minimap
|
||||
this.initMinimap();
|
||||
}
|
||||
|
||||
private initMinimap() {
|
||||
this.minimapContainer = this.scene.add.container(0, 0);
|
||||
this.minimapContainer.setScrollFactor(0); // Fixed to camera
|
||||
this.minimapContainer.setDepth(1001); // Same as menu
|
||||
this.minimapContainer.setScrollFactor(0);
|
||||
this.minimapContainer.setDepth(1001);
|
||||
|
||||
// Background panel (like menu)
|
||||
this.minimapBg = this.scene.add
|
||||
.rectangle(0, 0, GAME_CONFIG.ui.minimapPanelWidth, GAME_CONFIG.ui.minimapPanelHeight, 0x000000, 0.8)
|
||||
.setStrokeStyle(1, 0xffffff, 0.9)
|
||||
.setInteractive(); // Capture clicks
|
||||
.setInteractive();
|
||||
|
||||
this.minimapGfx = this.scene.add.graphics();
|
||||
|
||||
this.minimapContainer.add(this.minimapBg);
|
||||
this.minimapContainer.add(this.minimapGfx);
|
||||
|
||||
// Position in center
|
||||
this.positionMinimap();
|
||||
|
||||
// Start hidden
|
||||
this.minimapContainer.setVisible(false);
|
||||
}
|
||||
|
||||
@@ -64,22 +58,40 @@ export class DungeonRenderer {
|
||||
this.visible = new Uint8Array(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
|
||||
for (const sprite of this.corpseSprites) {
|
||||
sprite.destroy();
|
||||
}
|
||||
this.corpseSprites = [];
|
||||
|
||||
// Setup player sprite
|
||||
// Setup player sprite
|
||||
if (!this.playerSprite) {
|
||||
this.playerSprite = this.scene.add.sprite(0, 0, "warrior", 0);
|
||||
this.playerSprite.setDepth(100);
|
||||
|
||||
// Calculate display size to fit within tile while maintaining 12:15 aspect ratio
|
||||
const scale = TILE_SIZE / 15; // Fit height to tile size
|
||||
// Calculate scale to fit 15px high sprite into 16px tile
|
||||
const scale = 1.0;
|
||||
this.playerSprite.setScale(scale);
|
||||
|
||||
// Simple animations from PD source
|
||||
this.scene.anims.create({
|
||||
key: 'warrior-idle',
|
||||
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');
|
||||
}
|
||||
|
||||
// Rat animations
|
||||
// Enemy animations
|
||||
if (!this.scene.anims.exists('rat-idle')) {
|
||||
this.scene.anims.create({
|
||||
key: 'rat-idle',
|
||||
@@ -126,7 +138,6 @@ export class DungeonRenderer {
|
||||
});
|
||||
}
|
||||
|
||||
// Bat animations
|
||||
if (!this.scene.anims.exists('bat-idle')) {
|
||||
this.scene.anims.create({
|
||||
key: 'bat-idle',
|
||||
@@ -153,13 +164,11 @@ export class DungeonRenderer {
|
||||
return !isWall(this.world, x, y);
|
||||
});
|
||||
|
||||
// Position minimap
|
||||
this.positionMinimap();
|
||||
}
|
||||
|
||||
private positionMinimap() {
|
||||
const cam = this.scene.cameras.main;
|
||||
// Center on screen like menu
|
||||
this.minimapContainer.setPosition(cam.width / 2, cam.height / 2);
|
||||
}
|
||||
|
||||
@@ -187,7 +196,6 @@ export class DungeonRenderer {
|
||||
this.visible[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 falloff = 1 - radiusT * 0.6;
|
||||
const strength = Phaser.Math.Clamp(v * falloff, 0, 1);
|
||||
@@ -205,67 +213,31 @@ export class DungeonRenderer {
|
||||
return this.seen;
|
||||
}
|
||||
|
||||
render(playerPath: Vec2[]) {
|
||||
this.gfx.clear();
|
||||
render(_playerPath: Vec2[]) {
|
||||
if (!this.world || !this.layer) return;
|
||||
|
||||
if (!this.world) return;
|
||||
// Update Tiles
|
||||
this.layer.forEachTile(tile => {
|
||||
const i = idx(this.world, tile.x, tile.y);
|
||||
const isSeen = this.seen[i] === 1;
|
||||
const isVis = this.visible[i] === 1;
|
||||
|
||||
// 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);
|
||||
|
||||
const isSeen = this.seen[i] === 1;
|
||||
const isVis = this.visible[i] === 1;
|
||||
|
||||
if (!isSeen) {
|
||||
this.gfx.fillStyle(0x000000, 1);
|
||||
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 (!isSeen) {
|
||||
tile.setVisible(false);
|
||||
} else {
|
||||
tile.setVisible(true);
|
||||
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);
|
||||
tile.alpha = 1.0;
|
||||
tile.tint = 0xffffff;
|
||||
} else {
|
||||
alpha = wall ? GAME_CONFIG.rendering.fogAlphaWall : GAME_CONFIG.rendering.fogAlphaFloor;
|
||||
tile.alpha = isWall(this.world, tile.x, tile.y) ? 0.4 : 0.2;
|
||||
tile.tint = 0x888888;
|
||||
}
|
||||
|
||||
this.gfx.fillStyle(base, alpha);
|
||||
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)
|
||||
// Actors
|
||||
const activeEnemyIds = new Set<EntityId>();
|
||||
|
||||
for (const a of this.world.actors.values()) {
|
||||
const i = idx(this.world, a.pos.x, a.pos.y);
|
||||
const isVis = this.visible[i] === 1;
|
||||
@@ -282,14 +254,11 @@ export class DungeonRenderer {
|
||||
|
||||
activeEnemyIds.add(a.id);
|
||||
let sprite = this.enemySprites.get(a.id);
|
||||
|
||||
const textureKey = a.type === "bat" ? "bat" : "rat";
|
||||
|
||||
if (!sprite) {
|
||||
sprite = this.scene.add.sprite(0, 0, textureKey, 0);
|
||||
sprite.setDepth(99);
|
||||
const scale = TILE_SIZE / 15;
|
||||
sprite.setScale(scale);
|
||||
sprite.play(`${textureKey}-idle`);
|
||||
this.enemySprites.set(a.id, sprite);
|
||||
}
|
||||
@@ -298,11 +267,9 @@ export class DungeonRenderer {
|
||||
sprite.setVisible(true);
|
||||
}
|
||||
|
||||
// Hide/Cleanup inactive/non-visible enemy sprites
|
||||
for (const [id, sprite] of this.enemySprites.entries()) {
|
||||
if (!activeEnemyIds.has(id)) {
|
||||
sprite.setVisible(false);
|
||||
// We could also destroy if they are dead, but hide is safer for now
|
||||
if (!this.world.actors.has(id)) {
|
||||
sprite.destroy();
|
||||
this.enemySprites.delete(id);
|
||||
@@ -310,16 +277,13 @@ export class DungeonRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
// Render minimap
|
||||
this.renderMinimap();
|
||||
}
|
||||
|
||||
private renderMinimap() {
|
||||
this.minimapGfx.clear();
|
||||
|
||||
if (!this.world) return;
|
||||
|
||||
// Calculate scale to fit map within panel
|
||||
const padding = GAME_CONFIG.ui.minimapPadding;
|
||||
const availableWidth = GAME_CONFIG.ui.minimapPanelWidth - padding * 2;
|
||||
const availableHeight = GAME_CONFIG.ui.minimapPanelHeight - padding * 2;
|
||||
@@ -328,73 +292,44 @@ export class DungeonRenderer {
|
||||
const scaleY = availableHeight / this.world.height;
|
||||
const tileSize = Math.floor(Math.min(scaleX, scaleY));
|
||||
|
||||
// Center the map within the panel
|
||||
const mapPixelWidth = this.world.width * tileSize;
|
||||
const mapPixelHeight = this.world.height * tileSize;
|
||||
const offsetX = -mapPixelWidth / 2;
|
||||
const offsetY = -mapPixelHeight / 2;
|
||||
|
||||
// Draw only seen tiles
|
||||
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);
|
||||
const isSeen = this.seen[i] === 1;
|
||||
|
||||
if (!isSeen) continue;
|
||||
if (this.seen[i] !== 1) continue;
|
||||
|
||||
const wall = isWall(this.world, x, y);
|
||||
const color = wall ? 0x666666 : 0x333333;
|
||||
|
||||
this.minimapGfx.fillStyle(color, 1);
|
||||
this.minimapGfx.fillRect(
|
||||
offsetX + x * tileSize,
|
||||
offsetY + y * tileSize,
|
||||
tileSize,
|
||||
tileSize
|
||||
);
|
||||
this.minimapGfx.fillRect(offsetX + x * tileSize, offsetY + y * tileSize, tileSize, tileSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw exit if seen
|
||||
const ex = this.world.exit.x;
|
||||
const ey = this.world.exit.y;
|
||||
const exitIdx = idx(this.world, ex, ey);
|
||||
if (this.seen[exitIdx] === 1) {
|
||||
if (this.seen[idx(this.world, ex, ey)] === 1) {
|
||||
this.minimapGfx.fillStyle(0xffd166, 1);
|
||||
this.minimapGfx.fillRect(
|
||||
offsetX + ex * tileSize,
|
||||
offsetY + ey * tileSize,
|
||||
tileSize,
|
||||
tileSize
|
||||
);
|
||||
this.minimapGfx.fillRect(offsetX + ex * tileSize, offsetY + ey * tileSize, tileSize, tileSize);
|
||||
}
|
||||
|
||||
// Draw player
|
||||
const player = [...this.world.actors.values()].find(a => a.isPlayer);
|
||||
if (player) {
|
||||
this.minimapGfx.fillStyle(0x66ff66, 1);
|
||||
this.minimapGfx.fillRect(
|
||||
offsetX + player.pos.x * tileSize,
|
||||
offsetY + player.pos.y * tileSize,
|
||||
tileSize,
|
||||
tileSize
|
||||
);
|
||||
this.minimapGfx.fillRect(offsetX + player.pos.x * tileSize, offsetY + player.pos.y * tileSize, tileSize, tileSize);
|
||||
}
|
||||
|
||||
// Draw visible enemies
|
||||
for (const a of this.world.actors.values()) {
|
||||
if (a.isPlayer) continue;
|
||||
const i = idx(this.world, a.pos.x, a.pos.y);
|
||||
const isVis = this.visible[i] === 1;
|
||||
if (!isVis) continue;
|
||||
|
||||
this.minimapGfx.fillStyle(0xff6666, 1);
|
||||
this.minimapGfx.fillRect(
|
||||
offsetX + a.pos.x * tileSize,
|
||||
offsetY + a.pos.y * tileSize,
|
||||
tileSize,
|
||||
tileSize
|
||||
);
|
||||
if (this.visible[i] === 1) {
|
||||
this.minimapGfx.fillStyle(0xff6666, 1);
|
||||
this.minimapGfx.fillRect(offsetX + a.pos.x * tileSize, offsetY + a.pos.y * tileSize, tileSize, tileSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,7 +364,6 @@ export class DungeonRenderer {
|
||||
0
|
||||
);
|
||||
corpse.setDepth(50);
|
||||
corpse.setScale(TILE_SIZE / 15);
|
||||
corpse.play(`${textureKey}-die`);
|
||||
this.corpseSprites.push(corpse);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ export class GameScene extends Phaser.Scene {
|
||||
this.load.spritesheet("warrior", "warrior.png", { frameWidth: 12, 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("tiles0", "assets/tiles0.png", { frameWidth: 16, frameHeight: 16 });
|
||||
}
|
||||
|
||||
create() {
|
||||
|
||||
Reference in New Issue
Block a user