feat: finished RandomMapGenerator, not fully tested
This commit is contained in:
parent
63f5a2a3a0
commit
86fabc2336
|
@ -54,12 +54,6 @@
|
||||||
33, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35,
|
33, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35,
|
||||||
41, 42, 42, 42, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43],
|
41, 42, 42, 42, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43],
|
||||||
"entrances": [
|
"entrances": [
|
||||||
{
|
|
||||||
"x": 0,
|
|
||||||
"y": 12,
|
|
||||||
"width": 3,
|
|
||||||
"alt_tile": [52, 54]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"x": 29,
|
"x": 29,
|
||||||
"y": 12,
|
"y": 12,
|
||||||
|
@ -117,12 +111,6 @@
|
||||||
"y": 11,
|
"y": 11,
|
||||||
"width": 3,
|
"width": 3,
|
||||||
"alt_tile": [52, 54]
|
"alt_tile": [52, 54]
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": 29,
|
|
||||||
"y": 9,
|
|
||||||
"width": 3,
|
|
||||||
"alt_tile": [52, 54]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { TiledTilemapData } from "../../Wolfie2D/DataTypes/Tilesets/TiledData";
|
||||||
import Vec2 from "../../Wolfie2D/DataTypes/Vec2";
|
import Vec2 from "../../Wolfie2D/DataTypes/Vec2";
|
||||||
import Debug from "../../Wolfie2D/Debug/Debug";
|
import Debug from "../../Wolfie2D/Debug/Debug";
|
||||||
import { GameEventType } from "../../Wolfie2D/Events/GameEventType";
|
import { GameEventType } from "../../Wolfie2D/Events/GameEventType";
|
||||||
|
@ -7,14 +8,14 @@ import GameLevel from "./GameLevel";
|
||||||
|
|
||||||
|
|
||||||
export default class Tutorial extends GameLevel{
|
export default class Tutorial extends GameLevel{
|
||||||
|
private map: TiledTilemapData;
|
||||||
loadScene(): void {
|
loadScene(): void {
|
||||||
// Load resources
|
// Load resources
|
||||||
// this.load.tilemap("forest1", "shattered_sword_assets/tilemaps/Tutorial.json");
|
// this.load.tilemap("forest1", "shattered_sword_assets/tilemaps/Tutorial.json");
|
||||||
// let map = localStorage.getItem("map");
|
// let map = localStorage.getItem("map");
|
||||||
let rmg = new RandomMapGenerator("shattered_sword_assets/jsons/forest_template.json", 114514);
|
let rmg = new RandomMapGenerator("shattered_sword_assets/jsons/forest_template.json", 114514);
|
||||||
let map = rmg.getMap();
|
this.map = rmg.getMap();
|
||||||
this.load.tilemapFromObject("forest1", map);
|
this.load.tilemapFromObject("forest1", this.map);
|
||||||
|
|
||||||
this.load.spritesheet("player", "shattered_sword_assets/spritesheets/Hiro.json")
|
this.load.spritesheet("player", "shattered_sword_assets/spritesheets/Hiro.json")
|
||||||
//load music here
|
//load music here
|
||||||
|
@ -23,7 +24,7 @@ export default class Tutorial extends GameLevel{
|
||||||
startScene(): void {
|
startScene(): void {
|
||||||
// Add the level 1 tilemap
|
// Add the level 1 tilemap
|
||||||
this.add.tilemap("forest1", new Vec2(2, 2));
|
this.add.tilemap("forest1", new Vec2(2, 2));
|
||||||
this.viewport.setBounds(0, 0, 64*32, 20*32);
|
this.viewport.setBounds(0, 0, this.map.width*32, this.map.height*32);
|
||||||
|
|
||||||
this.playerSpawn = new Vec2(5*32, 9*32);
|
this.playerSpawn = new Vec2(5*32, 9*32);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ export default class RandomMapGenerator {
|
||||||
private gen: any;
|
private gen: any;
|
||||||
private hasExit: boolean;
|
private hasExit: boolean;
|
||||||
private minRoom: number;
|
private minRoom: number;
|
||||||
|
private roomPlaced: number;
|
||||||
|
private exitFacing: Facing;
|
||||||
|
|
||||||
constructor(JSONFilePath: string, seed: any) {
|
constructor(JSONFilePath: string, seed: any) {
|
||||||
let xhr = new XMLHttpRequest();
|
let xhr = new XMLHttpRequest();
|
||||||
|
@ -42,6 +44,8 @@ export default class RandomMapGenerator {
|
||||||
this.gen = new gen(seed);
|
this.gen = new gen(seed);
|
||||||
this.hasExit = false;
|
this.hasExit = false;
|
||||||
this.minRoom = this.template.minroom;
|
this.minRoom = this.template.minroom;
|
||||||
|
this.roomPlaced = 0;
|
||||||
|
this.exitFacing = this.getEntranceFacing(this.template.exit.entrances[0], this.template.exit.width);
|
||||||
|
|
||||||
|
|
||||||
this.template.rooms.forEach((room) => {
|
this.template.rooms.forEach((room) => {
|
||||||
|
@ -88,18 +92,106 @@ export default class RandomMapGenerator {
|
||||||
let room = this.copyRoom(this.template.entrance, 0, 0);
|
let room = this.copyRoom(this.template.entrance, 0, 0);
|
||||||
this.rooms.push(room);
|
this.rooms.push(room);
|
||||||
|
|
||||||
|
let facing = this.getEntranceFacing(this.template.entrance.entrances[0], this.template.entrance.width);
|
||||||
|
let position = new Vec2(this.template.entrance.entrances[0].x, this.template.entrance.entrances[0].y);
|
||||||
|
|
||||||
|
this.putNextRoom(position, this.getOppositeFacing(facing));
|
||||||
|
|
||||||
|
if (!this.hasExit)
|
||||||
|
throw new Error("Fail to generate a map with exit!");
|
||||||
|
|
||||||
// if (!this.hasExit)
|
|
||||||
// throw new Error("Fail to generate a map with exit!");
|
|
||||||
this.fillData();
|
this.fillData();
|
||||||
return this.map;
|
return this.map;
|
||||||
}
|
}
|
||||||
|
|
||||||
private putNextRoom(): boolean {
|
private putNextRoom(position: Vec2, facing: Facing): boolean {
|
||||||
|
switch (facing) {
|
||||||
|
case Facing.LEFT:
|
||||||
|
position.x += 1;
|
||||||
|
break;
|
||||||
|
case Facing.RIGHT:
|
||||||
|
position.x -= 1;
|
||||||
|
break;
|
||||||
|
case Facing.UP:
|
||||||
|
position.y += 1;
|
||||||
|
break;
|
||||||
|
case Facing.DOWN:
|
||||||
|
position.y -= 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (this.roomPlaced >= this.minRoom && facing == this.exitFacing) {
|
||||||
|
this.putExitRoom(position);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let nextRoom = this.getRandomRoom(facing);
|
||||||
|
let nextPosition: Vec2 = undefined;
|
||||||
|
let thisEntrance: Entrance = undefined;
|
||||||
|
for (let index = 0; index < nextRoom.entrances.length; index++) {
|
||||||
|
const entrance = nextRoom.entrances[index];
|
||||||
|
if (this.getEntranceFacing(entrance, nextRoom.weight) == facing) {
|
||||||
|
let tmpPosition = new Vec2(position.x - entrance.x, position.y - entrance.y);
|
||||||
|
if (this.isValidRoom(tmpPosition, new Vec2(tmpPosition.x + nextRoom.width - 1, tmpPosition.y + nextRoom.height - 1))) {
|
||||||
|
thisEntrance = entrance;
|
||||||
|
nextPosition = tmpPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!thisEntrance) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let room = this.copyRoom(nextRoom, nextPosition.x, nextPosition.y);
|
||||||
|
this.rooms.push(room);
|
||||||
|
this.roomPlaced += 1;
|
||||||
|
if (this.hasExit && this.gen.range() <= 0.1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (let index = 0; index < nextRoom.entrances.length; index++) {
|
||||||
|
const entrance = nextRoom.entrances[index];
|
||||||
|
if (entrance != thisEntrance) {
|
||||||
|
let facing = this.getEntranceFacing(entrance, nextRoom.width);
|
||||||
|
let position = new Vec2(nextPosition.x + entrance.x, nextPosition.y + entrance.y);
|
||||||
|
|
||||||
|
if (this.putNextRoom(position, this.getOppositeFacing(facing))) {
|
||||||
|
this.removeEntrance(room, entrance, facing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private putExitRoom(position: Vec2): void {
|
||||||
|
position = new Vec2(position.x - this.template.exit.entrances[0].x, position.y - this.template.exit.entrances[0].y);
|
||||||
|
if (!this.isValidRoom(position, new Vec2(position.x + this.template.exit.width - 1, position.y + this.template.exit.height - 1))) {
|
||||||
|
throw new Error("Cannot put exit room!!! Position is invalid!!! Please check order of entrances in map template.");
|
||||||
|
}
|
||||||
|
let room = this.copyRoom(this.template.exit, position.x, position.y);
|
||||||
|
this.rooms.push(room);
|
||||||
|
this.hasExit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeEntrance(room: Room, entrance: Entrance, facing: Facing): void {
|
||||||
|
let width = room.bottomRight.x - room.topLeft.x + 1;
|
||||||
|
if (facing == Facing.LEFT || facing == Facing.RIGHT) {
|
||||||
|
for (let index = 0; index < entrance.width; index++)
|
||||||
|
room.topLayer[(entrance.y + index) * width + entrance.x] = 0;
|
||||||
|
if (entrance.y > 0)
|
||||||
|
room.topLayer[(entrance.y - 1) * width + entrance.x] = entrance.alt_tile[0];
|
||||||
|
if (entrance.y + entrance.width <= (room.bottomRight.y - room.topLeft.y))
|
||||||
|
room.topLayer[(entrance.y + entrance.width) * width + entrance.x] = entrance.alt_tile[1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (let index = 0; index < entrance.width; index++)
|
||||||
|
room.topLayer[(entrance.y) * width + entrance.x + index] = 0;
|
||||||
|
if (entrance.x > 0)
|
||||||
|
room.topLayer[(entrance.y) * width + entrance.x - 1] = entrance.alt_tile[0];
|
||||||
|
if (entrance.x + entrance.width <= (room.bottomRight.x - room.topLeft.x))
|
||||||
|
room.topLayer[(entrance.y) * width + entrance.x + entrance.width] = entrance.alt_tile[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fillData() {
|
private fillData() {
|
||||||
let width = this.maxX - this.minX + 1;
|
let width = this.maxX - this.minX + 1;
|
||||||
let height = this.maxY - this.minY + 1;
|
let height = this.maxY - this.minY + 1;
|
||||||
|
@ -144,7 +236,8 @@ export default class RandomMapGenerator {
|
||||||
this.map.layers[0].data = new Array(width * height).fill(this.template.background);
|
this.map.layers[0].data = new Array(width * height).fill(this.template.background);
|
||||||
this.map.layers[1].data = new Array(width * height);
|
this.map.layers[1].data = new Array(width * height);
|
||||||
|
|
||||||
this.rooms.forEach((room) => {
|
for (let index = 0; index < this.rooms.length; index++) {
|
||||||
|
const room = this.rooms[index];
|
||||||
let roomWidth = room.bottomRight.x - room.topLeft.x + 1;
|
let roomWidth = room.bottomRight.x - room.topLeft.x + 1;
|
||||||
let roomHeight = room.bottomRight.y - room.topLeft.y + 1;
|
let roomHeight = room.bottomRight.y - room.topLeft.y + 1;
|
||||||
for (let i = 0; i < roomHeight; i++)
|
for (let i = 0; i < roomHeight; i++)
|
||||||
|
@ -152,19 +245,21 @@ export default class RandomMapGenerator {
|
||||||
this.map.layers[0].data[(room.topLeft.y + i) * width + room.topLeft.x + j] = room.bottomLayer[i * roomWidth + j];
|
this.map.layers[0].data[(room.topLeft.y + i) * width + room.topLeft.x + j] = room.bottomLayer[i * roomWidth + j];
|
||||||
this.map.layers[1].data[(room.topLeft.y + i) * width + room.topLeft.x + j] = room.topLayer[i * roomWidth + j];
|
this.map.layers[1].data[(room.topLeft.y + i) * width + room.topLeft.x + j] = room.topLayer[i * roomWidth + j];
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private isValidRoom(topLeft: Vec2, bottomRight: Vec2): boolean {
|
private isValidRoom(topLeft: Vec2, bottomRight: Vec2): boolean {
|
||||||
this.rooms.forEach((room) => {
|
for (let index = 0; index < this.rooms.length; index++) {
|
||||||
if (room.topLeft.x < bottomRight.x &&
|
const room = this.rooms[index];
|
||||||
room.bottomRight.x > topLeft.x &&
|
if (room.topLeft.x <= bottomRight.x &&
|
||||||
room.topLeft.y < bottomRight.y &&
|
room.bottomRight.x >= topLeft.x &&
|
||||||
room.bottomRight.y > topLeft.y)
|
room.topLeft.y <= bottomRight.y &&
|
||||||
return true;
|
room.bottomRight.y >= topLeft.y)
|
||||||
})
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
console.warn("Found an invalid room! TopLeft:", topLeft.toString, "BottomRight:", bottomRight.toString);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private getEntranceFacing(entrance: Entrance, width: number): Facing {
|
private getEntranceFacing(entrance: Entrance, width: number): Facing {
|
||||||
if (entrance.x === 0)
|
if (entrance.x === 0)
|
||||||
|
@ -189,18 +284,20 @@ export default class RandomMapGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getRandomRoom(value: number, facing: Facing): RoomTemplate {
|
private getRandomRoom(facing: Facing): RoomTemplate {
|
||||||
let array = this.getRoomArray(facing), weight = this.getRoomWeight(facing);
|
let array = this.getRoomArray(facing), weight = this.getRoomWeight(facing);
|
||||||
|
let value = this.gen(weight);
|
||||||
|
|
||||||
if (value >= weight)
|
if (value >= weight)
|
||||||
throw new Error("Random number " + value + " is larger than total weight " + weight);
|
throw new Error("Random number " + value + " is larger than total weight " + weight);
|
||||||
|
|
||||||
array.forEach((room) => {
|
for (let index = 0; index < array.length; index++) {
|
||||||
|
let room = array[index];
|
||||||
if (value < room.weight)
|
if (value < room.weight)
|
||||||
return room;
|
return room;
|
||||||
value -= room.weight;
|
value -= room.weight;
|
||||||
})
|
}
|
||||||
throw new Error("Cannot find Room! \nRooms: " + JSON.stringify(array) + "\nValue: " + value);
|
throw new Error("Cannot find Room! \nValue: " + value + "\nRooms: " + JSON.stringify(array));
|
||||||
}
|
}
|
||||||
|
|
||||||
private getRoomArray(facing: Facing): Array<RoomTemplate> {
|
private getRoomArray(facing: Facing): Array<RoomTemplate> {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user