public SplineTransformData CalculateAproxSplineTransformData(float i_splineVal) { SplineTransformData data = new SplineTransformData(); //Convert sline val to worldspace distance float distTravelled = i_splineVal * Length; //Walk the spline this distance int lastIndex = 0; float distTotal = 0; float distSeg = 0; Vector3 prevPos = m_splinePoints[0].transform.position; Vector3 fwd = Vector3.forward; bool walkDone = false; for (int j = 0; j < m_splinePoints.Length && !walkDone; ++j) { distSeg = 0; Vector3 p0 = m_splinePoints[ClampIndex(j - 1)].transform.position; Vector3 p1 = m_splinePoints[j].transform.position; Vector3 p2 = m_splinePoints[ClampIndex(j + 1)].transform.position; Vector3 p3 = m_splinePoints[ClampIndex(j + 2)].transform.position; prevPos = p1; //Walk along the spline from p1 to p2, incrementing the time value for (int i = 0; i < (int)(1f / m_segmentLengthDelta) && !walkDone; ++i) { float t = (i + 1) * m_segmentLengthDelta; Vector3 curPos = GetIntraSegmentPos(m_segments[j], t); float dist = Vector3.Magnitude(curPos - prevPos); fwd = Vector3.Normalize(curPos - prevPos); distTotal += dist; distSeg += dist; if (distTotal >= distTravelled) { walkDone = true; } prevPos = curPos; } if (!walkDone) { lastIndex = j; } } //We know the last index, and how far ahead we are to the next, interpolate that shid baby float segVal = Mathf.Min(distSeg / m_segments[lastIndex].m_length, 1); data.m_worldPos = prevPos; data.m_worldFwd = fwd; data.m_worldUp = Vector3.Lerp(m_segments[lastIndex].m_startUp, m_segments[lastIndex].m_endUp, segVal); return(data); }
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); } } } } } } }