public NodeWalkable GetNextWalkableNodeInDirection(NodeWalkable currentNode, Vector3Int direction, Vector3Int currentUpVector)
        {
            Debug.AssertFormat(direction.magnitude == 1, this, "Direction is invalid: {0}", direction);

            NodeWalkable nextWalkableNode = default;

            if (m_GridModel != null && currentNode != null)
            {
                nextWalkableNode = m_GridModel.TryGetWalkableNode(currentNode.Coordinates + direction);

                if (nextWalkableNode == null && currentNode.UpVectors.Length > 1)
                {
                    for (int i = 0; i < currentNode.UpVectors.Length; ++i)
                    {
                        Vector3Int targetUpVector = currentNode.UpVectors[i];
                        if (currentUpVector != targetUpVector)
                        {
                            Quaternion rotation         = Quaternion.FromToRotation(currentUpVector, targetUpVector);
                            Vector3Int rotatedDirection = Vector3IntUtil.Rotate(direction, rotation);

                            nextWalkableNode = m_GridModel.TryGetWalkableNode(currentNode.Coordinates + rotatedDirection);

                            if (nextWalkableNode != null)
                            {
                                break;
                            }
                        }
                    }
                }
            }

            Debug.Assert(nextWalkableNode != null, "Failed to get next walkable node.", this);

            return(nextWalkableNode);
        }
示例#2
0
        private Node CreateGridNode(Vector3Int nodeCoordinates, int gridSize, Transform gridRoot, float nodeSpacing = 1f)
        {
            Node node = default;

            Vector3Int walkableBoundsMin = Vector3Int.zero;
            Vector3Int walkableBoundsMax = new Vector3Int(gridSize - 1, gridSize - 1, gridSize - 1);

            Vector3Int surfaceBoundsMin = walkableBoundsMin + Vector3Int.one;
            Vector3Int surfaceBoundsMax = walkableBoundsMax - Vector3Int.one;

            if (CheckIfCoordinatesAreOnCubeBoundsSurface(nodeCoordinates, walkableBoundsMin, walkableBoundsMax) == true)
            {
                Vector3Int[] upVectors = CalculateNodeUpVectors(nodeCoordinates, walkableBoundsMin, walkableBoundsMax);
                GameObject   nodeView  = CreateNodeView(m_WalkableNodePrefab, gridRoot, nodeCoordinates, gridSize, nodeSpacing);

                node = new NodeWalkable(nodeCoordinates, upVectors, nodeView);
            }
            else if (CheckIfCoordinatesAreOnCubeBoundsSurface(nodeCoordinates, surfaceBoundsMin, surfaceBoundsMax) == true)
            {
                Vector3Int[] upVectors = CalculateNodeUpVectors(nodeCoordinates, surfaceBoundsMin, surfaceBoundsMax);
                GameObject   nodeView  = CreateNodeView(m_SurfaceNodePrefab, gridRoot, nodeCoordinates, gridSize, nodeSpacing);

                node = new NodeSurface(nodeCoordinates, upVectors, nodeView);
            }
            else
            {
                node = new NodeEmpty(nodeCoordinates);
            }

            return(node);
        }
示例#3
0
        public NodeWalkable GetRandomWalkableNode()
        {
            int          randomIndex        = Random.Range(0, m_UnobstructedWalkableGridNodes.Count);
            NodeWalkable randomWalkableNode = m_UnobstructedWalkableGridNodes[randomIndex];

            return(randomWalkableNode);
        }
示例#4
0
 private static void AddObstacles(Node[] gridNodes, NodeWalkable playerStartNode, float density, ObstaclePattern pattern, int minPlayerStartClearance)
 {
     for (int i = 0; i < gridNodes.Length; ++i)
     {
         NodeWalkable walkableNode = gridNodes[i] as NodeWalkable;
         if (walkableNode != null && walkableNode != playerStartNode)
         {
             // Don't add obstacles on edges of the cube.
             if (walkableNode.UpVectors != null && walkableNode.UpVectors.Length == 1)
             {
                 if (Random.value <= density)
                 {
                     float nodeDistanceToPlayer = Vector3Int.Distance(playerStartNode.Coordinates, walkableNode.Coordinates);
                     if (nodeDistanceToPlayer > minPlayerStartClearance)
                     {
                         if (CheckIfNodeMatchesObstaclePattern(walkableNode, pattern) == true)
                         {
                             walkableNode.SetAsObstacle();
                         }
                     }
                 }
             }
         }
     }
 }
示例#5
0
        public WorldGridModel(Node[] gridNodes, int gridSize, NodeWalkable playerStartNode)
        {
            m_GridNodes = gridNodes;
            GridSize    = gridSize;

            PlayerStartNode = playerStartNode;

            CreateGridNodeSubSets();
        }
        public void UpdatePlayerTarget(IReadOnlyCollection <NodeWalkable> excludedNodes)
        {
            if (AreReferencesAssigned == true)
            {
                NodeWalkable newPlayerTargetNode = GetNewPlayerTargetNode(excludedNodes);

                m_GridView.SetNewTargetNode(newPlayerTargetNode, PlayerTargetNode);

                PlayerTargetNode = newPlayerTargetNode;
            }
        }
示例#7
0
        private static NodeWalkable GetPlayerStartNode(Node[] gridNodes, int gridSize)
        {
            Vector3Int playerStartNodeCoordinates = new Vector3Int(gridSize / 2, gridSize / 2, 0);
            int        playerStartNodeIndex       = WorldGridUtil.ConvertNodeCoordinatesToIndex(playerStartNodeCoordinates, gridSize);

            NodeWalkable playerStartNode = gridNodes[playerStartNodeIndex] as NodeWalkable;

            Debug.Assert(playerStartNode != null, "Invalid player start node!");

            return(playerStartNode);
        }
示例#8
0
        public NodeWalkable TryGetWalkableNode(Vector3Int nodeCoordinates)
        {
            NodeWalkable walkableNode = null;

            Node node = TryGetNodeAtCoordinates(nodeCoordinates);

            if (node != null)
            {
                walkableNode = node as NodeWalkable;
            }

            return(walkableNode);
        }
示例#9
0
        private void CreateGridNodeSubSets()
        {
            m_UnobstructedWalkableGridNodes = new List <NodeWalkable>();

            for (int i = 0; i < m_GridNodes.Length; ++i)
            {
                NodeWalkable walkableNode = m_GridNodes[i] as NodeWalkable;

                if (walkableNode != null && walkableNode.IsObstacle == false)
                {
                    m_UnobstructedWalkableGridNodes.Add(walkableNode);
                }
            }
        }
示例#10
0
        private NodeWalkable GetNewPlayerTargetNode(IReadOnlyCollection <NodeWalkable> excludedNodes)
        {
            NodeWalkable newPlayerTargetNode = default;

            if (m_GridModel != null && excludedNodes.Count < m_GridModel.UnobsctructedWalkableNodeCount)
            {
                do
                {
                    newPlayerTargetNode = m_GridModel.GetRandomWalkableNode();
                }while (CheckIfWalkableNodeIsExcluded(newPlayerTargetNode, excludedNodes) == true);
            }

            Debug.Assert(newPlayerTargetNode != null, "Failed to get new player target node.", this);

            return(newPlayerTargetNode);
        }
示例#11
0
        private bool CheckIfWalkableNodeIsExcluded(NodeWalkable walkableNode, IReadOnlyCollection <NodeWalkable> exludedNodes)
        {
            bool isExcluded = false;

            if (walkableNode != null && exludedNodes != null && exludedNodes.Count > 0)
            {
                foreach (NodeWalkable excludedNode in exludedNodes)
                {
                    if (walkableNode == excludedNode)
                    {
                        isExcluded = true;
                        break;
                    }
                }
            }

            return(isExcluded);
        }
示例#12
0
        public void SetNewTargetNode(NodeWalkable targetNode, NodeWalkable previousTargetNode)
        {
            if (AreReferencesAssigned == true)
            {
                if (previousTargetNode != null)
                {
                    m_TargetParticles.transform.position = previousTargetNode.ViewPosition;
                    m_TargetParticles.Play();
                }

                if (targetNode != null && targetNode.View != null)
                {
                    targetNode.View.Show(m_TargetColor, m_TargetEmissionIntensity, true);

                    m_TargetLight.enabled            = true;
                    m_TargetLight.color              = m_TargetColor;
                    m_TargetLight.transform.position = targetNode.ViewPosition;
                }
            }
        }
示例#13
0
        public override WorldGridModel GenerateWorldGridModel(Transform gridRoot)
        {
            int nodeCount = m_GridSize * m_GridSize * m_GridSize;

            Node[] gridNodes = new Node[nodeCount];

            for (int i = 0; i < nodeCount; ++i)
            {
                Vector3Int nodeCoordinates = WorldGridUtil.ConvertNodeIndexToCoordinates(i, m_GridSize);
                gridNodes[i] = CreateGridNode(nodeCoordinates, m_GridSize, gridRoot);
            }

            NodeWalkable playerStartNode = GetPlayerStartNode(gridNodes, m_GridSize);

            if (m_ObstacleDensity > 0)
            {
                AddObstacles(gridNodes, playerStartNode, m_ObstacleDensity, m_ObstaclePattern, m_MinimumPlayerStartClearance);
            }

            WorldGridModel gridModel = new WorldGridModel(gridNodes, m_GridSize, playerStartNode);

            return(gridModel);
        }
示例#14
0
        private static bool CheckIfNodeMatchesObstaclePattern(NodeWalkable walkableNode, ObstaclePattern pattern)
        {
            bool nodeMatchesObstaclePattern = false;

            if (walkableNode != null)
            {
                Vector3Int nodeCoordinates = walkableNode.Coordinates;
                Vector3Int nodeUpVector    = walkableNode.UpVectors[0];
                int        remainder       = pattern == ObstaclePattern.Even ? 0 : 1;

                // Add obstacles in a pattern so that the player can always pass through and the player target is always reachable.
                // Pattern:
                // #-#
                // ---
                // #-#
                nodeMatchesObstaclePattern  = true;
                nodeMatchesObstaclePattern &= nodeCoordinates.y % 2 == remainder || Mathf.Abs(nodeUpVector.y) > 0;
                nodeMatchesObstaclePattern &= nodeCoordinates.x % 2 == remainder || Mathf.Abs(nodeUpVector.x) > 0;
                nodeMatchesObstaclePattern &= nodeCoordinates.z % 2 == remainder || Mathf.Abs(nodeUpVector.z) > 0;
            }

            return(nodeMatchesObstaclePattern);
        }