private PuzzleData GeneratePuzzle(int i_puzzleIndex, IPuzzleGenerator i_puzzleGeneratorIF, Vector3 i_startingPosition) { PuzzleData puzzleData = i_puzzleGeneratorIF.GeneratePuzzle(m_width, m_emulatedState.m_difficulty, m_forwardCellsPerSideways); Vector2Int gridSize = new Vector2Int(puzzleData.Width, puzzleData.Height); GameObject[,] spawnedObjects = new GameObject[gridSize.x, gridSize.y]; m_spawnedObjects.Add(i_puzzleIndex, spawnedObjects); for (int x = 0; x < puzzleData.Width; ++x) { for (int y = 0; y < puzzleData.Height; ++y) { PuzzleCell cell = puzzleData.GetCell(x, y); if (cell.m_prefabToSpawn != null) { spawnedObjects[x, y] = Instantiate(cell.m_prefabToSpawn, i_startingPosition + new Vector3(x * m_cellSize, 0, y * m_cellSize), Quaternion.identity, transform); } } } // Link for (int x = 0; x < puzzleData.Width; ++x) { for (int y = 0; y < puzzleData.Height; ++y) { PuzzleCell cell = puzzleData.GetCell(x, y); if (cell.m_cellsToLinkTo != null) { foreach (Vector2Int cellCoords in cell.m_cellsToLinkTo) { GameObject objectToLinkFrom = spawnedObjects[x, y]; GameObject objectToLinkTo = spawnedObjects[cellCoords.x, cellCoords.y]; foreach (IActivator activator in objectToLinkFrom.GetComponents <IActivator>()) { foreach (IActivatee activatee in objectToLinkTo.GetComponents <IActivatee>()) { activator.AssignActivee(activatee); } } } } } } return(puzzleData); }
public PuzzleData GeneratePuzzle ( int i_width, float i_difficulty, float i_forwardCellsPerSideways ) { PuzzleData puzzleData = new PuzzleData(i_width, m_data.m_jamLength); HashSet<int> fullLanes = new HashSet<int>(); // Figure out how many lanes to fill up int minLanes = m_data.m_lanesOfTrafficAtMinDif; int maxLanes = i_width - m_data.m_lanesWithoutTrafficAtMaxDif; int numLanes = Mathf.FloorToInt(Mathf.Lerp(minLanes, maxLanes, i_difficulty)); // Num lanes of traffic // Pick our lanes while(fullLanes.Count < numLanes) { fullLanes.Add(Random.Range(0, i_width)); } // Spawn our cars foreach(int laneIndex in fullLanes) { for(int y = 0; y < m_data.m_jamLength; y += 2) { PuzzleCell carCell = puzzleData.GetCell(laneIndex, y); carCell.m_prefabToSpawn = m_data.m_carPrefabs[Random.Range(0, m_data.m_carPrefabs.Count)]; } } int extraCellsPostJam = Mathf.CeilToInt(2 * i_forwardCellsPerSideways); // Bit of padding on the exit puzzleData.AddRows(extraCellsPostJam); return puzzleData; }
public PuzzleData GeneratePuzzle ( int i_width, float i_difficulty, float i_forwardCellsPerSideways ) { // Slalomy thing // Pick how wide it's going to be // Calculate how many rows we need between each barrier // Calculate how many rows of extra diagonal barriers are needed /* * | /| | /| * |\ /| | / | |\ / | * | \ / | |\ / | | |^--| | * | |^-| | | |^-| | | |^^^| | * | |^^| | | |^^| | | |^^^| | * | |-^| | | |-^| | | |--^| | * | |^^| | | |^^| | | |^^^| | * | |^-| | | |^-| | | |^^^| | * | |^^| | | |^^| | | |^--| | * | |-^| | | |-^| | | |^^^| | * | / \ | |/ \ | | |^^^| | * |/ \| | \ | | |--^| | * | \| |/ \ | * | \| */ // Calculate how long we need it to be // First we have to pick where we're going to place this int slalomWidth = 2 + Mathf.Max(Mathf.CeilToInt(Mathf.Lerp(m_data.m_extraRoadWidthPropMinDif, m_data.m_extraRoadWidthPropMaxDif, i_difficulty) * (i_width - 2)), 0); int slalomLeftLaneX = Random.Range(0, i_width - slalomWidth); // Figure out how much extra height we need for the hard shoulders int slalomLeftShoulderWidth = slalomLeftLaneX; int slalomRightShoulderWidth = i_width - (slalomLeftLaneX + slalomWidth); int maxShoulderWidth = Mathf.Max(slalomLeftShoulderWidth, slalomRightShoulderWidth); int shoulderDiagonalMaxHeight = maxShoulderWidth; int shoulderAdditionalHeight = shoulderDiagonalMaxHeight * 2; // Top and bottom // Now figure out how much height we need for the slalom int slalomVerticalSpacePerBarrier = Mathf.CeilToInt((slalomWidth - 1) * i_forwardCellsPerSideways) + Mathf.CeilToInt(Mathf.Lerp(m_data.m_extraSlalomHeightPerBarrierMinDif, m_data.m_extraSlalomHeightPerBarrierMaxDif, i_difficulty)); int slalomHeight = m_data.m_slalomBarriers + (m_data.m_slalomBarriers - 1) * slalomVerticalSpacePerBarrier; // Total height int puzzleCellHeight = slalomHeight + shoulderAdditionalHeight; // Super simple to start PuzzleData puzzleData = new PuzzleData(i_width, puzzleCellHeight); // Start placing Vector2Int slalomBottomLeft = new Vector2Int(slalomLeftShoulderWidth, shoulderDiagonalMaxHeight); Vector2Int slalomBottomRight = slalomBottomLeft + new Vector2Int(slalomWidth - 1, 0); Vector2Int slalomTopLeft = slalomBottomLeft + new Vector2Int(0, slalomHeight - 1); Vector2Int slalomTopRight = slalomBottomRight + new Vector2Int(0, slalomHeight - 1); void PlaceWall(Vector2Int i_pos, GameObject i_prefab) { if (i_pos.x >= 0 && i_pos.x < puzzleData.Width && i_pos.y >= 0 && i_pos.y < puzzleData.Height) { PuzzleCell wallCell = puzzleData.GetCell(i_pos.x, i_pos.y); wallCell.m_prefabToSpawn = i_prefab; } } // Slalom bool isLeft = (Mathf.RoundToInt(Random.Range(0f, 1f)) == 1); for (int y = 0; y < slalomHeight; ++y) { PlaceWall(slalomBottomLeft + new Vector2Int(-1, y), m_data.m_leftWallPrefab); PlaceWall(slalomBottomRight + new Vector2Int(1, y), m_data.m_rightWallPrefab); if (y == 0 || (y % (slalomVerticalSpacePerBarrier + 1) == 0)) { // Place a wall for (int x = 0; x < slalomWidth - 1; ++x) { if (isLeft) { PlaceWall(slalomBottomLeft + new Vector2Int(x, y), m_data.m_slalomWallPrefab); } else { PlaceWall(slalomBottomRight + new Vector2Int(-x, y), m_data.m_slalomWallPrefab); } } isLeft = !isLeft; } } // Hard shoulder for (int y = 0; y < shoulderDiagonalMaxHeight; ++y) { // Bottom ones PlaceWall(slalomBottomLeft + new Vector2Int(-1, -1) + new Vector2Int(-y, -y), m_data.m_leftDiagonalWallPrefab); PlaceWall(slalomBottomRight + new Vector2Int(1, -1) + new Vector2Int(y, -y), m_data.m_rightDiagonalWallPrefab); // Top ones PlaceWall(slalomTopLeft + new Vector2Int(-1, 1) + new Vector2Int(-y, y), m_data.m_rightDiagonalWallPrefab); PlaceWall(slalomTopRight + new Vector2Int(1, 1) + new Vector2Int(y, y), m_data.m_leftDiagonalWallPrefab); } puzzleData.AddRows(2); return(puzzleData); }
private IEnumerator GeneratePuzzle(IPuzzleGenerator i_puzzleGeneratorIF, float i_difficulty, float i_startingSplineT, float i_startingSplineTClamped) { PuzzleData puzzleData = i_puzzleGeneratorIF.GeneratePuzzle(m_trackWidthInCells, i_difficulty, m_forwardCellsPerSideways); AddRandomStuff(puzzleData, i_difficulty); SplineTransformData puzzleStartTransformData = m_spline.CalculateAproxSplineTransformData(i_startingSplineTClamped); Vector2Int gridSize = new Vector2Int(puzzleData.Width, puzzleData.Height); SpawnedPuzzle spawnedPuzzleData = new SpawnedPuzzle(); spawnedPuzzleData.m_spawnedObjects = new GameObject[gridSize.x, gridSize.y]; spawnedPuzzleData.m_startPuzzleHeight = m_runningDistancePS; spawnedPuzzleData.m_endPuzzleHeight = m_runningDistancePS + puzzleData.Height; spawnedPuzzleData.m_puzzleData = puzzleData; spawnedPuzzleData.m_startTransformData = puzzleStartTransformData; m_spawnedPuzzles.Enqueue(spawnedPuzzleData); float GetT(int i_y) { return((i_startingSplineTClamped + i_y * m_trackTPerCell) % 1f); } // Work out if we need to offset the starting spline T float trackLength = m_spline.Length; float puzzleTLength = (puzzleData.Height * m_cellSize) / trackLength; float totalAddedT = 0f; while (!m_spline.DoesTRangeSupportPuzzles(i_startingSplineT, i_startingSplineT + puzzleTLength, out float nextValidT)) { totalAddedT += (nextValidT - i_startingSplineT); i_startingSplineT = nextValidT; i_startingSplineTClamped = i_startingSplineT % 1f; yield return(0); } m_runningDistancePS += Mathf.CeilToInt(totalAddedT * trackLength / m_cellSize); // Lets figure out wtf we need to spawn this crap for (int y = 0; y < puzzleData.Height; ++y) { // Every time we go up one we need to find our new transform info float splineT = GetT(y); SplineTransformData splineTransformData = m_spline.CalculateAproxSplineTransformData(splineT); int timesAroundTrack = Mathf.FloorToInt(i_startingSplineT); if (timesAroundTrack % 2 == 1) // If odd, flip { splineTransformData.m_worldUp = -splineTransformData.m_worldUp; } m_splineTransformsCalulated.Add(splineTransformData); Vector3 puzzleLeftPos = splineTransformData.m_worldPos - (Vector3.Cross(splineTransformData.m_worldUp.normalized, splineTransformData.m_worldFwd.normalized) * m_cellSize * (m_trackWidthInCells - 1) / 2f); Quaternion objectRotation = Quaternion.LookRotation(splineTransformData.m_worldFwd.normalized, splineTransformData.m_worldUp.normalized); for (int x = 0; x < puzzleData.Width; ++x) { PuzzleCell cell = puzzleData.GetCell(x, y); if (cell.m_prefabToSpawn != null) { Vector3 positionToSpawn = puzzleLeftPos + (objectRotation * new Vector3(x * m_cellSize, 0, 0)); Quaternion rotationToSpawn = objectRotation; // Adjust because the track isn't actually flat all the way along // Lift above the track Vector3 raycastFrom = positionToSpawn + splineTransformData.m_worldUp * m_upwardProjectionLengthBeforeDownwardRaycast; if (Physics.Raycast(new Ray(raycastFrom, -splineTransformData.m_worldUp), out RaycastHit hit, m_downwardRaycastLength, m_trackLayer)) { // Adjust positionToSpawn = hit.point; rotationToSpawn = Quaternion.LookRotation(splineTransformData.m_worldFwd.normalized, hit.normal.normalized); } spawnedPuzzleData.m_spawnedObjects[x, y] = Instantiate(cell.m_prefabToSpawn, positionToSpawn, cell.m_prefabRotation * rotationToSpawn, transform); spawnedPuzzleData.m_spawnedObjects[x, y].transform.localScale *= m_modelScaler; } } yield return(0); } // Link for (int x = 0; x < puzzleData.Width; ++x) { for (int y = 0; y < puzzleData.Height; ++y) { PuzzleCell cell = puzzleData.GetCell(x, y); if (cell.m_cellsToLinkTo != null) { foreach (Vector2Int cellCoords in cell.m_cellsToLinkTo) { GameObject objectToLinkFrom = spawnedPuzzleData.m_spawnedObjects[x, y]; GameObject objectToLinkTo = spawnedPuzzleData.m_spawnedObjects[cellCoords.x, cellCoords.y]; foreach (IActivator activator in objectToLinkFrom.GetComponents <IActivator>()) { foreach (IActivatee activatee in objectToLinkTo.GetComponents <IActivatee>()) { activator.AssignActivee(activatee); } } } } } } }
public PuzzleData GeneratePuzzle ( int i_width, float i_difficulty, float i_forwardCellsPerSideways ) { PuzzleData puzzleData = new PuzzleData(i_width, m_data.m_puzzleLength); // Place some walls (W) and removed the ability to place walls in places nearby that would block the player from getting through (x) // May need to go up with (x) as many cells as necessary to go sideways one block /* * x x * x W x * */ bool[,] takenCells = new bool[i_width, m_data.m_puzzleLength]; // Figure out how many blocks we're going to spawn int totalCells = i_width * m_data.m_puzzleLength; int blocksToSpawn = Mathf.FloorToInt(totalCells * Mathf.Lerp(m_data.m_wallCellPercentageAtMinDif, m_data.m_wallCellPercentageAtMaxDif, i_difficulty)); int verticalCellsToBlock = Mathf.CeilToInt(i_forwardCellsPerSideways); // Super bad and simple stuff int attempts = 0; while (blocksToSpawn > 0 && attempts < blocksToSpawn * 10) { Vector2Int spawnCoords = new Vector2Int(Random.Range(0, i_width), Random.Range(0, m_data.m_puzzleLength)); if (takenCells[spawnCoords.x, spawnCoords.y] == false) { // Spawn our wall PuzzleCell wallCell = puzzleData.GetCell(spawnCoords.x, spawnCoords.y); wallCell.m_prefabToSpawn = m_data.m_wallPrefab; // Block the cells around it void BlockCell(Vector2Int i_coords) { if (i_coords.x >= 0 && i_coords.x < i_width) { if (i_coords.y >= 0 && i_coords.y < m_data.m_puzzleLength) { takenCells[i_coords.x, i_coords.y] = true; } } } BlockCell(spawnCoords + new Vector2Int(0, 0)); BlockCell(spawnCoords + new Vector2Int(-1, 0)); BlockCell(spawnCoords + new Vector2Int(1, 0)); for (int i = 1; i <= verticalCellsToBlock; ++i) { BlockCell(spawnCoords + new Vector2Int(0, -i)); BlockCell(spawnCoords + new Vector2Int(0, i)); BlockCell(spawnCoords + new Vector2Int(-1, -i)); BlockCell(spawnCoords + new Vector2Int(-1, i)); BlockCell(spawnCoords + new Vector2Int(1, -i)); BlockCell(spawnCoords + new Vector2Int(1, i)); } --blocksToSpawn; } ++attempts; } puzzleData.AddRows(1); return(puzzleData); }
public PuzzleData GeneratePuzzle ( int i_width, float i_difficulty, float i_forwardCellsPerSideways ) { // SimpleSlalomy thing // Pick how wide it's going to be // Calculate how many rows we need between each barrier // Calculate how many rows of extra diagonal barriers are needed /* * | |^-| | * | |^^| | * | |-^| | * | |^^| | * | |^-| | * | |^^| | * |---- ---| */ int openingGapWidth = 1 + Mathf.CeilToInt(Mathf.Lerp(m_data.m_extraEntryWidthMinDif, m_data.m_extraEntryWidthMaxDif, i_difficulty)); // Now figure out how much height we need for the SimpleSlalom int slalomVerticalSpacePerBarrier = Mathf.CeilToInt((i_width - openingGapWidth) * i_forwardCellsPerSideways) + Mathf.CeilToInt(Mathf.Lerp(m_data.m_extraHeightPerBarrierMinDif, m_data.m_extraHeightPerBarrierMaxDif, i_difficulty)); int slalomHeight = m_data.m_slalomBarriers + (m_data.m_slalomBarriers - 1) * slalomVerticalSpacePerBarrier; // Super simple to start PuzzleData puzzleData = new PuzzleData(i_width, slalomHeight); // Start placing void PlaceWall(Vector2Int i_pos) { PuzzleCell wallCell = puzzleData.GetCell(i_pos.x, i_pos.y); wallCell.m_prefabToSpawn = m_data.m_wallPrefab; } // SimpleSlalom bool isLeft = (Random.Range(0f, 1f) > 0.5f) ? true : false; for (int barrierIndex = 0; barrierIndex < m_data.m_slalomBarriers; ++barrierIndex) { int gapStartIndex = (isLeft ? 0 : i_width - openingGapWidth); for (int x = 0; x < i_width; ++x) { if (x >= gapStartIndex && x < gapStartIndex + openingGapWidth) { // Gap } else { PlaceWall(new Vector2Int(x, barrierIndex * (slalomVerticalSpacePerBarrier + 1))); // Add on 1 for the barrier row itself } } isLeft = !isLeft; } puzzleData.AddRows(slalomVerticalSpacePerBarrier); return(puzzleData); }
public PuzzleData GeneratePuzzle ( int i_width, float i_difficulty, float i_forwardCellsPerSideways ) { // Calculate how long we need it to be int maxGateOffset = i_width - 1; int cellsOfSpaceNeeded = Mathf.CeilToInt(maxGateOffset * i_forwardCellsPerSideways) /*+ 1*/; // You need one extra cell to get out of the switch IF it has walls of some sort you need to go through cellsOfSpaceNeeded += Mathf.FloorToInt((1f - i_difficulty) * m_data.m_puzzleCellLengthHandicapMinDifficulty) + Mathf.FloorToInt(i_difficulty * m_data.m_puzzleCellLengthHandicapMaxDifficulty); // Switch + space + gate int puzzleCellLength = 1 + cellsOfSpaceNeeded + 1; // Super simple to start PuzzleData puzzleData = new PuzzleData(i_width, puzzleCellLength); // Place the switchs List <PuzzleCell> switches = new List <PuzzleCell>(); int switchCount = Mathf.CeilToInt(Mathf.Lerp(m_data.m_switchesPresentMinDif, m_data.m_switchesPresentMaxDif, i_difficulty)); while (switches.Count < Mathf.Min(switchCount, i_width)) { int switchX = Random.Range(0, i_width); PuzzleCell switchCell = puzzleData.GetCell(switchX, 0); if (switchCell.m_prefabToSpawn == null) { switchCell.m_prefabToSpawn = m_data.m_switchPrefab; switches.Add(switchCell); } } // Place the gates List <PuzzleCell> gates = new List <PuzzleCell>(); List <int> gateXs = new List <int>(); int gateCount = Mathf.CeilToInt(Mathf.Lerp(m_data.m_gatesPresentMinDif, m_data.m_gatesPresentMaxDif, i_difficulty)); int gateY = puzzleCellLength - 1; while (gates.Count < Mathf.Min(gateCount, i_width)) { int gateX = Random.Range(0, i_width); PuzzleCell gateCell = puzzleData.GetCell(gateX, gateY); if (gateCell.m_prefabToSpawn == null) { gateCell.m_prefabToSpawn = m_data.m_gatePrefab; gates.Add(gateCell); gateXs.Add(gateX); } } // Fill with walls for (int x = 0; x < i_width; ++x) { PuzzleCell cell = puzzleData.GetCell(x, gateY); if (cell.m_prefabToSpawn == null) { cell.m_prefabToSpawn = m_data.m_wallPrefab; } } // Link foreach (PuzzleCell switchCell in switches) { foreach (int gateX in gateXs) { switchCell.m_cellsToLinkTo.Add(new Vector2Int(gateX, gateY)); } } // Add empty cells at the end so the player has time to get back to their next thingy float halfWidth = (i_width - 1) / 2f; int gateOffsetFromCenter = Mathf.CeilToInt(halfWidth); int extraCellsNeeded = Mathf.CeilToInt(halfWidth) + gateOffsetFromCenter + 1; puzzleData.AddRows(extraCellsNeeded); return(puzzleData); }