Use wall + floor assets from Pixel dungeon
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user