public void SpawnSpawnables(TrainingRoom room, System.Random rand) { var roomType = roomTypes.GetRandom(rand); HashSet <Vector2Int> floorTiles = new HashSet <Vector2Int>(room.unitSpaceFloors); HashSet <Vector2Int> wallTiles = new HashSet <Vector2Int>(room.unitSpaceWalls); Debug.Log("LEVEL SPAWNED AT: " + transform.position); Vector2Int pos = new Vector2Int(Mathf.RoundToInt(transform.position.x), Mathf.RoundToInt(transform.position.z)) + room.Position; Debug.Log($"LEVEL SPAWN: {pos}"); RoomType.RoomSet roomSet = roomType.roomSets.GetRandom(rand); var spawned = SpawnGenerator.SpawnItemsInRoom(rand, roomType, roomType.roomSets.GetRandom(rand), floorTiles, wallTiles, pos); foreach (var item in spawned) { item.transform.SetParent(room.transform); } }
const int MAX_ITEM_STACK = 3; // TODO: evaluate where to put this variable // place all the required items within a room public static HashSet <GameObject> SpawnItemsInRoom(Random rand, RoomType roomType, RoomType.RoomSet roomSet, HashSet <Vector2Int> floorPos, HashSet <Vector2Int> wallPos, Vector2Int finalizeOffset = default(Vector2Int)) //Defaults to zero { HashSet <GameObject> spawnedObjects = new HashSet <GameObject>(); // we copying the list as we are changing the data of roomtype otherwise List <RoomType.SpawnListItem> workingList = new List <RoomType.SpawnListItem>(roomType.spawnList); if (roomSet.extraSpawnList != null) { workingList.AddRange(roomSet.extraSpawnList); } HashSet <Vector2Int> onTopPos = new HashSet <Vector2Int>(); HashSet <Vector2Int> workingFloor = new HashSet <Vector2Int>(floorPos); HashSet <Vector2Int> workingWall = new HashSet <Vector2Int>(wallPos); for (int i = 0; i < workingList.Count; i++) { float relativeSpawnAmount = (500 / (workingFloor.Count + workingWall.Count)); int min = Mathf.RoundToInt(workingList[i].Min / relativeSpawnAmount); int max = Mathf.RoundToInt(workingList[i].Max / relativeSpawnAmount); Debug.Log("onTop:" + workingList[i].Spawnable.spawnOnTop); HashSet <Vector2Int> allowedSpawnPos = new HashSet <Vector2Int>(); // HashSet has optimal lookuptimes O(1) // TODO: validate that probability sum is one int totalPos = workingFloor.Count + wallPos.Count + onTopPos.Count; allowedSpawnPos.UnionWith(FindNewPos((int)Math.Round((totalPos * workingList[i].Spawnable.notWallProbability)), workingFloor, finalizeOffset, rand, 2)); allowedSpawnPos.UnionWith(FindNewPos((int)Math.Round((totalPos * workingList[i].Spawnable.byWallProbability)), workingWall, finalizeOffset, rand, 2)); allowedSpawnPos.UnionWith(FindNewPos((int)Math.Round((totalPos * workingList[i].Spawnable.spawnOnTop)), onTopPos, Vector2Int.zero, rand)); //NOTE CHANGE OFFSET TO 0 // chose an amount to spawn a Spawnable type int spawnCount = rand.NextInclusive(min, max); for (int j = 0; j < spawnCount && allowedSpawnPos.Count > 0; j++) { // TODO: roll pos in tile Vector2Int tile = allowedSpawnPos.GetRandom(rand); Vector3 spawnPosition = new Vector3(tile.x, 0, tile.y); Quaternion objectQuaternion = Quaternion.Euler(0, rand.NextInclusive(0, workingList[i].Spawnable.angleMaxOffset), 0); Vector3? forward = null; // if we are about to spawn on the side of a object, we need a forward vector bool isOnTopPos = onTopPos.Contains(tile); if (!isOnTopPos) { forward = objectQuaternion * new Vector3(0, 0, 1); } if (TryResolvePositionPhysically(workingList[i].Spawnable, ref spawnPosition, forward, objectQuaternion)) { spawnedObjects.Add(GameObject.Instantiate(workingList[i].Spawnable.gameObject, spawnPosition, objectQuaternion)); // TODO: rounding bugs!!! Vector2Int tileToRemove = new Vector2Int((int)(tile.x * 0.5f), (int)(tile.y * 0.5f)); workingFloor.RemoveWhere(pos => pos == tileToRemove); workingWall.RemoveWhere(pos => pos == tileToRemove); allowedSpawnPos.RemoveWhere(pos => pos == tile); if (!workingList[i].Spawnable.allowOtherOnTop && isOnTopPos) { onTopPos.Remove(tile); } else if (workingList[i].Spawnable.allowOtherOnTop) { onTopPos.Add(tile); if (workingList[i].Spawnable.spawnOnTop > rand.NextFloat()) { allowedSpawnPos.Add(tile); } } spawnCount -= SpawnRelatives(workingList[i].Spawnable, new Vector2(spawnPosition.x, spawnPosition.z), objectQuaternion, rand, ref spawnedObjects, ref workingList, min, max); } } } // if we are not debugging, we delete scripts used for placement if (Application.isPlaying) { foreach (var spawnedObject in spawnedObjects) { UnityEngine.Object.Destroy(spawnedObject.GetComponent <Spawnable>()); } } return(spawnedObjects); }