Example #1
0
        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;
        }
Example #3
0
        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);
        }
Example #4
0
        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);
        }
Example #7
0
        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);
        }