145 lines
4.7 KiB
JavaScript
145 lines
4.7 KiB
JavaScript
export class Map {
|
|
constructor(width, height) {
|
|
this.width = width;
|
|
this.height = height;
|
|
this.tiles = [];
|
|
this.rooms = [];
|
|
}
|
|
|
|
generate() {
|
|
this.rooms = [];
|
|
// Initialize with walls
|
|
for (let y = 0; y < this.height; y++) {
|
|
this.tiles[y] = [];
|
|
for (let x = 0; x < this.width; x++) {
|
|
this.tiles[y][x] = '#';
|
|
}
|
|
}
|
|
|
|
const MAX_ROOMS = 10;
|
|
const MIN_SIZE = 6;
|
|
const MAX_SIZE = 12;
|
|
|
|
for (let i = 0; i < MAX_ROOMS; i++) {
|
|
const w = Math.floor(Math.random() * (MAX_SIZE - MIN_SIZE + 1)) + MIN_SIZE;
|
|
const h = Math.floor(Math.random() * (MAX_SIZE - MIN_SIZE + 1)) + MIN_SIZE;
|
|
const x = Math.floor(Math.random() * (this.width - w - 1)) + 1;
|
|
const y = Math.floor(Math.random() * (this.height - h - 1)) + 1;
|
|
|
|
const newRoom = { x, y, w, h };
|
|
|
|
// Check overlap
|
|
let failed = false;
|
|
for (const other of this.rooms) {
|
|
if (newRoom.x <= other.x + other.w && newRoom.x + newRoom.w >= other.x &&
|
|
newRoom.y <= other.y + other.h && newRoom.y + newRoom.h >= other.y) {
|
|
failed = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!failed) {
|
|
this.createRoom(newRoom);
|
|
|
|
if (this.rooms.length > 0) {
|
|
const prev = this.rooms[this.rooms.length - 1];
|
|
const newCenter = { x: Math.floor(newRoom.x + newRoom.w / 2), y: Math.floor(newRoom.y + newRoom.h / 2) };
|
|
const prevCenter = { x: Math.floor(prev.x + prev.w / 2), y: Math.floor(prev.y + prev.h / 2) };
|
|
|
|
if (Math.random() < 0.5) {
|
|
this.createHKorridor(prevCenter.x, newCenter.x, prevCenter.y);
|
|
this.createVKorridor(prevCenter.y, newCenter.y, newCenter.x);
|
|
} else {
|
|
this.createVKorridor(prevCenter.y, newCenter.y, prevCenter.x);
|
|
this.createHKorridor(prevCenter.x, newCenter.x, newCenter.y);
|
|
}
|
|
}
|
|
|
|
this.rooms.push(newRoom);
|
|
}
|
|
}
|
|
}
|
|
|
|
generateTown() {
|
|
this.rooms = [];
|
|
// Fill with grass/floor
|
|
for (let y = 0; y < this.height; y++) {
|
|
this.tiles[y] = [];
|
|
for (let x = 0; x < this.width; x++) {
|
|
this.tiles[y][x] = '.';
|
|
}
|
|
}
|
|
|
|
// Helper to draw a building
|
|
const drawBuilding = (x, y, w, h, doorSide) => {
|
|
// Walls
|
|
for (let by = y; by < y + h; by++) {
|
|
for (let bx = x; bx < x + w; bx++) {
|
|
if (by === y || by === y + h - 1 || bx === x || bx === x + w - 1) {
|
|
this.tiles[by][bx] = '#';
|
|
} else {
|
|
this.tiles[by][bx] = '.';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Door
|
|
if (doorSide === 'bottom') {
|
|
this.tiles[y + h - 1][Math.floor(x + w / 2)] = '.';
|
|
} else if (doorSide === 'top') {
|
|
this.tiles[y][Math.floor(x + w / 2)] = '.';
|
|
} else if (doorSide === 'left') {
|
|
this.tiles[Math.floor(y + h / 2)][x] = '.';
|
|
} else if (doorSide === 'right') {
|
|
this.tiles[Math.floor(y + h / 2)][x + w - 1] = '.';
|
|
}
|
|
|
|
// Add to rooms for reference
|
|
this.rooms.push({ x, y, w, h });
|
|
};
|
|
|
|
// 1. Temple (North Center)
|
|
drawBuilding(20, 5, 10, 8, 'bottom');
|
|
|
|
// 2. General Store (West)
|
|
drawBuilding(5, 15, 8, 6, 'right');
|
|
|
|
// 3. Weapon Shop (East)
|
|
drawBuilding(37, 15, 8, 6, 'left');
|
|
|
|
// 4. Dungeon Entrance (North East)
|
|
drawBuilding(40, 5, 6, 6, 'bottom');
|
|
|
|
// 5. Houses (South)
|
|
drawBuilding(10, 30, 6, 5, 'top');
|
|
drawBuilding(22, 30, 6, 5, 'top');
|
|
drawBuilding(34, 30, 6, 5, 'top');
|
|
}
|
|
|
|
|
|
createRoom(room) {
|
|
for (let y = room.y; y < room.y + room.h; y++) {
|
|
for (let x = room.x; x < room.x + room.w; x++) {
|
|
this.tiles[y][x] = '.';
|
|
}
|
|
}
|
|
}
|
|
|
|
createHKorridor(x1, x2, y) {
|
|
for (let x = Math.min(x1, x2); x <= Math.max(x1, x2); x++) {
|
|
this.tiles[y][x] = '.';
|
|
}
|
|
}
|
|
|
|
createVKorridor(y1, y2, x) {
|
|
for (let y = Math.min(y1, y2); y <= Math.max(y1, y2); y++) {
|
|
this.tiles[y][x] = '.';
|
|
}
|
|
}
|
|
|
|
isWalkable(x, y) {
|
|
if (x < 0 || x >= this.width || y < 0 || y >= this.height) return false;
|
|
return this.tiles[y][x] === '.' || this.tiles[y][x] === '>' || this.tiles[y][x] === '<';
|
|
}
|
|
}
|