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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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;
 | 
					        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,18 +245,20 @@ 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 {
 | 
				
			||||||
| 
						 | 
					@ -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