예제 #1
0
 /// <summary>
 /// Recursively adds <see cref="ColoredLine"/> objects to the <see cref="Lines"/> list for all of a given nodes children
 /// </summary>
 /// <param name="node">A node which will recursively have its children added to the Lines list</param>
 public static void AddChildrenToList(NodeObject node)
 {
     for (int i = 0; i < node.Children.Count; i++)
     {
         Lines.Add(new ColoredLine(node.Position, ((NodeObject)node.Children[i]).Position, LineDraw.lineColors[node.Depth % LineDraw.lineColors.Length]));
         AddChildrenToList((NodeObject)node.Children[i]);
     }
 }
 /// <summary>
 /// Changes the current node to be the parent of the current node, if it has a parent
 /// </summary>
 public void SelectParentNode()
 {
     if (CurrentNode.Parent != null)
     {
         CurrentNode = (NodeObject)CurrentNode.Parent;
         LineDraw.SelectNode(CurrentNode);
         TreeUIController.DisplayNodeInfo(CurrentNode);
     }
 }
 /// <summary>
 /// Changes the currently selected node to be a child of the currently selected node
 /// </summary>
 /// <param name="childIndex">The child index of the new selected node</param>
 public void SelectChildNode(int childIndex)
 {
     if (CurrentNode.Children.Count > childIndex)
     {
         CurrentNode = (NodeObject)CurrentNode.Children[childIndex];
         LineDraw.SelectNode(CurrentNode);
         TreeUIController.DisplayNodeInfo(CurrentNode);
     }
 }
예제 #4
0
        /// <summary>
        /// Sets the position of a <see cref="NodeObject"/> in the world, and all its children, recursively <para/>
        /// This method is an <see cref="IEnumerator"/> so the tree is given time to be created, instead of the program freezing whilst it creates the tree in one frame
        /// </summary>
        /// <param name="node">The starting node to set the position of</param>
        IEnumerator SetNodePosition(NodeObject node)
        {
            node.SetPosition(visualisationType);
            nodesGenerated++;

            foreach (Node child in node.Children)
            {
                yield return(new WaitForSeconds(.1f));

                StartCoroutine(SetNodePosition((NodeObject)child));
            }
        }
예제 #5
0
        /// <summary>
        /// If the user has started running MCTS, then display information about it to the UI whilst it generates <para/>
        /// When the MCTS has finished generating, set the position of each <see cref="NodeObject"/> so that they can be rendered on-screen <para/>
        /// When each nodes position has been set, switch to the tree navigation UI
        /// </summary>
        void Update()
        {
            //Don't do anything until the user has started running the MCTS
            if (mcts == null)
            {
                return;
            }

            //While the MCTS is still running, display progress information about the time remaining and the amounts of nodes created to the user
            if (!mcts.Finished)
            {
                timeLeft -= Time.deltaTime;
                if (timeLeft <= 0)
                {
                    mcts.Finish();
                }
                TreeUIController.UpdateProgressBar((1 - (timeLeft / timeToRunFor)) / 2, "Running MCTS   " + mcts.UniqueNodes + " nodes     " + timeLeft.ToString("0.0") + "s/" + timeToRunFor.ToString("0.0") + "s");
            }

            //Return if the MCTS has not finished being created
            if (!mcts.Finished)
            {
                return;
            }

            //If the MCTS has finished being computed, start to create gameobjects for each node in the tree
            if (!startedVisualisation)
            {
                rootNodeObject = (NodeObject)mcts.Root;
                rootNodeObject.SetPosition(visualisationType);
                StartCoroutine(SetNodePosition(rootNodeObject));
                startedVisualisation = true;
            }

            //Display information on the progress bar about how many node objects have been created, until every node in the tree has its own gameobject
            if (!allNodesGenerated)
            {
                if (nodesGenerated < mcts.UniqueNodes)
                {
                    TreeUIController.UpdateProgressBar(0.5f + ((float)nodesGenerated / mcts.UniqueNodes / 2), "Creating node objects: " + nodesGenerated + "/" + mcts.UniqueNodes);
                }
                else if (nodesGenerated == mcts.UniqueNodes)
                {
                    //If every node has had a gameobject created for it, then switch to the navigation UI and start to render the game tree
                    TreeUIController.SwitchToNavigationUI();
                    Camera.main.GetComponent <LineDraw>().linesVisible         = true;
                    Camera.main.GetComponent <TreeCameraControl>().CurrentNode = rootNodeObject;
                    TreeUIController.DisplayNodeInfo(mcts.Root);
                    allNodesGenerated = true;
                    LineDraw.SelectNode(rootNodeObject);
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Selects the provided node, replacing the contents of the <see cref="Lines"/> list with only lines relevant to the select nodes related nodes
        /// </summary>
        /// <param name="node">The node to select</param>
        public static void SelectNode(NodeObject node)
        {
            //Clear the list
            Lines = new List <ColoredLine>();
            NodeObject currentNode = node;

            //Back-track up the tree, drawing lines from the root node to the selected node
            while (currentNode.Parent != null)
            {
                Lines.Add(new ColoredLine(((NodeObject)currentNode.Parent).Position, currentNode.Position, LineDraw.lineColors[currentNode.Parent.Depth % LineDraw.lineColors.Length]));
                currentNode = (NodeObject)currentNode.Parent;
            }

            //Recursively add all the children of the selected node to the Lines list
            AddChildrenToList(node);
        }
예제 #7
0
        /// <summary>
        /// Gives this <see cref=" NodeObject"/> a position in world space depending on its position in the game tree
        /// </summary>
        public void SetPosition(VisualisationType visualisationType)
        {
            NodeObject parentObject = (NodeObject)Parent;

            //Play around with this value to change the structure of the tree depending on depth
            float depthMul = 60;

            if (visualisationType == VisualisationType.Standard3D)
            {
                #region Standard 3D node placement
                //Root node, automatically starts at origin, does not require additional initialisation
                if (Depth == 0)
                {
                    return;
                }

                if (Depth == 1)             //If at depth 1, use the Fibonacci sphere algorithm to evenly distribute all depth 1 nodes in a sphere around the root node
                {
                    #region Fibbonacci Sphere algorithm
                    int   samples   = Parent.Children.Capacity + 1;
                    float offset    = 2f / samples;
                    float increment = Mathf.PI * (3 - Mathf.Sqrt(5));

                    float y   = ((parentObject.ChildPositionsSet * offset) - 1) + (offset / 2);
                    float r   = Mathf.Sqrt(1 - Mathf.Pow(y, 2));
                    float phi = ((parentObject.ChildPositionsSet + 1) % samples) * increment;
                    float x   = Mathf.Cos(phi) * r;
                    float z   = Mathf.Sin(phi) * r;
                    #endregion
                    Position = new Vector3(x, y, z) * depthMul;
                }
                else                        //If at any other depth, position the new node a set distance away from its parent node
                {
                    Position  = parentObject.Position;
                    Position += parentObject.LocalPosition.normalized * depthMul * 2;
                    Vector3 rotationPoint = Position;

                    Vector3 normal = parentObject.LocalPosition;
                    Vector3 tangent;
                    Vector3 t1 = Vector3.Cross(normal, Vector3.forward);
                    Vector3 t2 = Vector3.Cross(normal, Vector3.up);

                    if (t1.magnitude > t2.magnitude)
                    {
                        tangent = t1;
                    }
                    else
                    {
                        tangent = t2;
                    }

                    if (Parent.Children.Count != 1)
                    {
                        Position += tangent.normalized * depthMul * 0.25f;
                        Position  = Position.RotateAround(rotationPoint, rotationPoint - parentObject.Position, (360 / Parent.Children.Capacity) * parentObject.ChildPositionsSet);
                    }
                }
                #endregion
            }
            else if (visualisationType == VisualisationType.Disk2D)
            {
                #region Disk 2D node placement
                //Root node, automatically starts at origin, does not require additional initialisation
                if (Depth == 0)
                {
                    ArcAngle = 360;
                    return;
                }

                if (Depth == 1)             //If at depth 1, place the new node on the edge of a circle around the origin
                {
                    Position = new Vector3(60, 0, 0);
                    Position = Position.RotateAround(Vector3.zero, Vector3.up, parentObject.ChildPositionsSet * (parentObject.ArcAngle / parentObject.Children.Count));
                }
                else                        //If at any other depth, position the new node a set distance away from its parent node
                {
                    Position  = parentObject.Position;
                    Position += (parentObject.LocalPosition.normalized * depthMul);
                    Position  = Position.RotateAround(parentObject.Position, Vector3.up, -(parentObject.ArcAngle / 2) + (parentObject.ChildPositionsSet * (parentObject.ArcAngle / parentObject.Children.Count)));
                }
                ArcAngle = parentObject.ArcAngle / parentObject.Children.Count;
                #endregion
            }
            else if (visualisationType == VisualisationType.Cone)
            {
                #region Cone node placement
                //Root node, automatically starts at origin, does not require additional initialisation
                if (Depth == 0)
                {
                    Radius = 1000;
                    return;
                }

                Position = parentObject.Position;

                if (parentObject.Children.Count > 1)
                {
                    Position += new Vector3(parentObject.Radius, 0, 0);
                    Position  = Position.RotateAround(parentObject.Position, Vector3.up, parentObject.ChildPositionsSet * (360 / parentObject.Children.Count));

                    Vector3 a = parentObject.Position + new Vector3(parentObject.Radius, 0, 0);
                    Vector3 b = a.RotateAround(parentObject.Position, Vector3.up, 360 / parentObject.Children.Count);
                    Radius = (a - b).magnitude / 2;
                }
                else
                {
                    Radius = parentObject.Radius;
                }

                Position += new Vector3(0, -150, 0);
                #endregion
            }
            else
            {
                throw new System.Exception("Unknown visualisation type: " + visualisationType.ToString() + " encountered");
            }

            parentObject.ChildPositionsSet++;
        }