extends Node3D class_name LevelGenerator var levelGrid: Array[Array] @export var gridSize: int = 250 @export var doorBlock: PackedScene var spawnableRooms: Array[RoomData] var doorSpawnPoints: Array[DoorPosition] var doorBlockSpawnPoints: Array[DoorPosition] var biomes: Array[Biome] var rng := RandomNumberGenerator.new() func _ready() -> void: initGrid() var spaceshipRoomList := RoomListSpaceship.new() # Have something choose the map in this part later spawnableRooms = spaceshipRoomList.rooms var temp: Array[DoorPosition] var temp2: Array[DoorPosition] = [] # Generate the level temp = spawnRoom(spawnableRooms[0],Vector2i(30,30),3,true) for x in temp: temp2 += spawnRoomAtDoor(spawnableRooms,x) for x in temp2: print(x.pos) spawnRoomAtDoor(spawnableRooms,x) spawnDoors() #printLevelGrid() #Utility func initGrid() -> void: for x in gridSize: var newRow: Array levelGrid.push_back(newRow) for y in gridSize: var newCell := GridCell.new() levelGrid[x].push_back(newCell) func addGridCells(cell1: GridCell,cell2: GridCell) -> GridCell: var returnCell: GridCell = GridCell.new() returnCell.spaceTaken = cell1.spaceTaken or cell2.spaceTaken returnCell.door = cell2.door returnCell.doorOrientation = cell2.doorOrientation returnCell.biome = cell1.biome return returnCell func addArrays2D(array1: Array[Array], array2: Array[Array], arr2pos: Vector2i = Vector2i(0,0)) -> void: if array1.size() <= (arr2pos.x) + array2.size(): return if array1[arr2pos.y].size() <= (arr2pos.y) + array2[0].size(): return for x in array2.size(): for y in array2[x].size(): array1[x+arr2pos.x][y+arr2pos.y] = addGridCells(array1[x+arr2pos.x][y+arr2pos.y],array2[x][y]) func checkOverlapArrays2D(array1: Array[Array], array2: Array[Array], arr2pos: Vector2i = Vector2i(0,0)) -> bool: if array1.size() <= (arr2pos.x) + array2.size(): return true if array1[arr2pos.y].size() <= (arr2pos.y) + array2[0].size(): return true for x in array2.size(): for y in array2[x].size(): if array1[x+arr2pos.x][y+arr2pos.y].spaceTaken and array2[x][y].spaceTaken: return true return false func rotateArray2D(array: Array[Array], numberOfRotationsBy90Degrees: int) -> void: var size: int = array.size() var layerCount: int = size/2 for x in numberOfRotationsBy90Degrees%4: for layer in layerCount: var first: int = layer var last: int = size - first - 1 for element in range(first, last): var offset = element - first var top = array[first][element] var right = array[element][last] var bot = array[last][last-offset] var left = array[last-offset][first] array[element][last] = top array[last][last-offset] = right array[last-offset][first] = bot array[first][element] = left func getDoorPosition(cell: GridCell, GridCellPosition: Vector2i) -> DoorPosition: if !cell.door: print("Tried to get door at cell that isnt a door") return null var returnDoorPosition := DoorPosition.new() returnDoorPosition.pos = GridCellPosition returnDoorPosition.orientation = cell.doorOrientation return returnDoorPosition func addObject(AddedObject:PackedScene, Parent: Node3D, Position: Vector3, Rotation: Vector3= Vector3(0,0,0)): if !AddedObject: print("tried to add object but packed scene is null") return var obj = AddedObject.instantiate() Parent.add_child(obj) obj.position = Position obj.rotation = Rotation return obj #Spawning Rooms func rotateRoomData(roomData: RoomData, numberOfRotationsBy90Degrees: int) -> void: rotateArray2D(roomData.roomGrid,numberOfRotationsBy90Degrees) roomData.rotations = wrapi(roomData.rotations + numberOfRotationsBy90Degrees,0,4) for door in roomData.doorPositions: door.rotatePosRight(roomData.roomGrid.size(),numberOfRotationsBy90Degrees) func spawnRoom(roomDataInput: RoomData,pos: Vector2i,numberOfRotationsBy90Degrees: int = 0, centered: bool = false) -> Array[DoorPosition]: #Pos corresponds to the upper left corner of the room immage var roomData: RoomData = roomDataInput.duplicateRoom() var roomScene: PackedScene = load(roomData.roomSceneRef) rotateRoomData(roomData,numberOfRotationsBy90Degrees) var roomGrid := roomData.roomGrid var doorPositions: Array[DoorPosition] = roomData.doorPositions if centered: pos = Vector2i(pos.x-(roomGrid.size()/2),pos.y-(roomGrid[0].size()/2)) addArrays2D(levelGrid,roomGrid,pos) addObject(roomScene,self,Vector3(pos.x+(roomGrid.size()/2),0,pos.y+(roomGrid[0].size()/2)),Vector3(0,(roomData.rotations%4)*PI/2,0)) for door in doorPositions: door.pos = pos + door.pos return doorPositions func getDoorFromRoom(roomData: RoomData,index: int) -> DoorPosition: return roomData.doorPositions[index % roomData.doorPositions.size()] func putRoomAtDoor(roomData: RoomData, door: DoorPosition,spawnDoorIndex: int) -> Array: ##Return array contains roomData, spawn Pos in that order #Init Values: var spawnDoor: DoorPosition = getDoorFromRoom(roomData,spawnDoorIndex) #Which door from the spawned room connects to the exiting room var doorOrientationDifference : int = wrapi(spawnDoor.orientation - door.orientation,0,4) #Difference in orinet. between spawned and existing room var numberOfRoomRotations: int = 0 #How many rotations are needed to make spawned rooms spawn door face the existing door var spawnPos: Vector2i var doorOffset: Vector2i #Offset by 1 space so the doors are next to eachother and not inside eachoter #Find number of rotations and then rotate the room if !doorOrientationDifference == 2: if doorOrientationDifference == 1: numberOfRoomRotations = 3 if doorOrientationDifference == 0: numberOfRoomRotations = 2 if doorOrientationDifference == 3: numberOfRoomRotations = 1 rotateRoomData(roomData,numberOfRoomRotations) #Get new values for spawnDoor and set door offset spawnDoor = getDoorFromRoom(roomData,spawnDoorIndex) match spawnDoor.orientation: 0: doorOffset = Vector2i(0,-1) 1: doorOffset = Vector2i(1,0) 2: doorOffset = Vector2i(0,1) 3: doorOffset = Vector2i(-1,0) #Set spawn pos and return values spawnPos = door.pos - spawnDoor.pos + doorOffset var returnArray: Array = [roomData,spawnPos] return returnArray func spawnRoomAtDoor(roomDataInput: Array[RoomData], door: DoorPosition) -> Array[DoorPosition]: var returnArray: Array[DoorPosition] var roomData: RoomData = null var spawnDoorIndex: int = -1 #Choose the room to use var rooms: Array[RoomData] = roomDataInput.duplicate() rooms.shuffle() for room in rooms: #Check if room has allready been found if roomData and spawnDoorIndex != -1: break #Randomise door checking order var doorIndices: Array[int] for x in room.doorPositions.size(): doorIndices.push_back(x) doorIndices.shuffle() #Check if doorIndex fits and assign roomData and spawnDoorIndex if it does for doorIndex in doorIndices: if checkIfRoomFits(room,door,doorIndex): roomData = room.duplicateRoom() spawnDoorIndex = doorIndex break #Check if a room has been found if !roomData or spawnDoorIndex == -1: doorBlockSpawnPoints.push_back(door) return returnArray #Get Spawn Info and spawn room var spawnInfo: Array = putRoomAtDoor(roomData,door,spawnDoorIndex) spawnRoom(spawnInfo[0],spawnInfo[1]) returnArray = spawnInfo[0].doorPositions for x in returnArray.size(): if returnArray[x].pos == door.pos: returnArray.remove_at(x) returnArray[x].pos = spawnInfo[1] + returnArray[x].pos return returnArray func checkIfRoomFits(roomDataInput: RoomData,door: DoorPosition,spawnDoorIndex: int) -> bool: var roomData: RoomData = roomDataInput.duplicateRoom() var spawnInfo: Array = putRoomAtDoor(roomData,door,spawnDoorIndex) if checkOverlapArrays2D(levelGrid,spawnInfo[0].roomGrid,spawnInfo[1]): return false else: return true func spawnDoors() -> void: for doorSpawn in doorSpawnPoints: pass for doorBlockSpawn in doorBlockSpawnPoints: addObject(doorBlock,self,Vector3(doorBlockSpawn.pos.x+0.5,0,doorBlockSpawn.pos.y+0.5),Vector3(0,doorBlockSpawn.orientation*-PI/2,0)) #Debug Functions func printLevelGrid() -> void: for x in levelGrid.size(): for y in levelGrid[x].size(): if levelGrid[x][y].spaceTaken: debugCubeAtPos(Vector2(x,y)) func debugCubeAtPos(pos: Vector2): var debugCube: PackedScene = preload("res://test/debugCube.tscn") addObject(debugCube,self,Vector3(pos.x+0.5,0,pos.y+0.5))