private static void OutputParent(TextWriter writer, ParentNode node, GravityNode rootNode, string prefix1, string prefix2) { writer.Write(prefix1); writer.Write("Total Mass: "); writer.Write(node.Mass); writer.Write("\tCentre of mass: "); writer.Write(node.CentreOfMass); writer.Write("\tCell Size: "); writer.WriteLine(node.Size); int range = 7; while (range > 0 && node.SubNodes[range] == null) { range--; } for (int index = 0; index <= range; index++) { if (node.SubNodes[index] != null) { if (index == range) { Output(writer, node.SubNodes[index], rootNode, prefix2 + LAST_PREFIX, prefix2 + SPACING); } else { Output(writer, node.SubNodes[index], rootNode, prefix2 + NEXT_PREFIX, prefix2 + CONT_PREFIX); } } } }
public GravityNode(GameObject item) { this.item = item; this.SetScript(); next = null; previous = null; }
/// <summary> /// Initialize base variables of gravity frame, to be used with player position /// when player has entered the level. /// </summary> /// <param name="playerPosition">Position of player.</param> public void Initialize(Vector3 playerPosition) { // initialize firstClosestNode = FindFirstClosestNode(playerPosition); secondClosestNode = FindSecondClosestNode(playerPosition); closestPointOnFrameLine = FindClosestPointOnFrame(playerPosition); closestPointOnFramePlane = FindClosestPointOnFramePlane(playerPosition); }
public static void Output(TextWriter writer, GravityNode node, string prefix1, string prefix2) { if (node == null) { return; } Output(writer, node, node, prefix1, prefix2); }
private static void OutputLeaf(TextWriter writer, LeafNode node, GravityNode rootNode, string prefix1, string prefix2) { writer.Write(prefix1); writer.Write("Mass: "); writer.Write(node.Mass); writer.Write("\tCentre of mass: "); writer.Write(node.CentreOfMass); writer.Write("\tForce: "); writer.WriteLine(GravityManager.CalculateTreeForce(node, rootNode)); }
public void Enqueue(GameObject item) { GravityNode temp = new GravityNode(item); if (!this.IsEmpty()) { temp.SetNext(first); first.SetPrevious(temp); } first = temp; }
public static Vector3 CalculateForce(GravityNode target, GravityNode tree) { if (target == tree) { return(Vector3.zero); } var difference = tree.CentreOfMass - target.CentreOfMass; var distance = difference.magnitude; return((difference * target.Mass * tree.Mass * G) / Mathf.Pow(distance, 3)); }
//Removes item from the list, along with its script. Returns false if list doesn't contain item, true otherwise. public bool Dequeue(GameObject item) { if (this.Contains(item)) { if (current.HasNext()) { if (current.HasPrevious()) { //Set the previous node's next node to be the current node's next node. current.GetPrevious().SetNext(current.GetNext()); //Set the next node's previous node to be the current node's previous node. current.GetNext().SetPrevious(current.GetPrevious()); //Set the current node to be the previous node. current = current.GetPrevious(); return(true); } else //it must be the first node if there isn't a previous node { //Set the second node's previous node to null. current.GetNext().SetPrevious(null); //Set the second node to now be the first node. first = current.GetNext(); //Set current to the new first node. current = first; return(true); } } else //it must be the last node if there is no next node { if (current.HasPrevious()) { //Sets the previous node's next node to null. current.GetPrevious().SetNext(null); //Sets current to the previous node. current = current.GetPrevious(); return(true); } else //it must be the only node { current = null; first = null; return(true); } } } return(false); }
/// <summary> /// Finds node closest to <paramref name="position"/> to <paramref name="position"/> in full /// frame, or among nodes in the closeby field of <paramref name="node"/>. /// </summary> /// <returns>Closest node on frame.</returns> /// <param name="position">Position for which to find the closest node.</param> /// <param name="node">Optional node with closeby field, use to reduce search space.</param> private GravityNode FindFirstClosestNode(Vector3 position, GravityNode node = null) { // Find closest gravNode to position, either in full frame or among node.closeby List <GravityNode> currFrame = node == null ? gravityFrame : node.closeby; List <float> dist = new List <float>(currFrame.Count); int count = 0; foreach (GravityNode gn in currFrame) { dist.Insert(count++, Vector3.Distance(position, gn.position)); } int closestNodeInd = dist.IndexOf(Mathf.Min(dist.ToArray())); // return(currFrame[closestNodeInd]); }
private static void Output(TextWriter writer, GravityNode node, GravityNode rootNode, string prefix1, string prefix2) { if (node == null) { return; } if (node.IsLeaf) { OutputLeaf(writer, (LeafNode)node, rootNode, prefix1, prefix2); } else { OutputParent(writer, (ParentNode)node, rootNode, prefix1, prefix2); } }
/// <summary> /// Updates the variables holding first/second closest nodes and /// position on frame of the player. /// </summary> /// <param name="playerPosition">Position of player.</param> public void UpdatePlayerBasedElements(Vector3 playerPosition) { firstClosestNode = FindFirstClosestNode(playerPosition, firstClosestNode); secondClosestNode = FindSecondClosestNode(playerPosition); closestPointOnFrameLine = FindClosestPointOnFrame(playerPosition); closestPointOnFramePlane = FindClosestPointOnFramePlane(playerPosition); ////DEBUG //Debug.DrawLine(playerPosition, firstClosestNode.position, Color.gray); //Debug.DrawLine(playerPosition, secondClosestNode.position, Color.gray); //Debug.DrawLine(playerPosition, closestPointOnFrameLine, Color.yellow); //Debug.DrawLine(firstClosestNode.planePoints[0], secondClosestNode.planePoints[0], Color.magenta); //Debug.DrawLine(secondClosestNode.planePoints[0], secondClosestNode.planePoints[1], Color.magenta); //Debug.DrawLine(secondClosestNode.planePoints[1], firstClosestNode.planePoints[1], Color.magenta); //Debug.DrawLine(firstClosestNode.planePoints[1], firstClosestNode.planePoints[0], Color.magenta); //Debug.DrawLine(playerPosition, closestPointOnFramePlane, Color.green); ////DEBUG }
public void CalculateForces(GravityNode node, GravityNode root) { if (node.IsLeaf) { var leaf = (LeafNode)node; leaf.Body.Force = CalculateTreeForce(node, root); } else { foreach (var subNode in ((ParentNode)node).SubNodes) { if (subNode != null) { CalculateForces(subNode, root); } } } }
public static Vector3 CalculateTreeForce(GravityNode target, GravityNode tree) { if (tree.IsLeaf || ((ParentNode)tree).Size / Vector3.Distance(target.CentreOfMass, tree.CentreOfMass) < gravityRatio) { return(CalculateForce(target, tree)); } else { var force = Vector3.zero; foreach (var subNode in ((ParentNode)tree).SubNodes) { if (subNode != null) { force += CalculateTreeForce(target, subNode); } } return(force); } }
private GravityNode BuildTree(GravityBody[] bodies, Vector3 origin, int power) { if (bodies.Length == 1) { return(new LeafNode(bodies[0])); } var seperatedBodies = new List <GravityBody> [8]; foreach (var body in bodies) { foreach (Region region in Enum.GetValues(typeof(Region))) { if (IsWithinRegion(origin, body.Position, region, power - 1)) { if (seperatedBodies[(int)region] == null) { seperatedBodies[(int)region] = new List <GravityBody>(); } seperatedBodies[(int)region].Add(body); break; } } } var nodes = new GravityNode[8]; foreach (Region region in Enum.GetValues(typeof(Region))) { var newOrigin = origin + ((Vector3)region.GetDirection()) * Mathf.Pow(2, power - 2); if (seperatedBodies[(int)region] != null) { nodes[(int)region] = BuildTree(seperatedBodies[(int)region].ToArray(), newOrigin, power - 1); } } return(new ParentNode(nodes, Mathf.Pow(2, power))); }
/// <summary> /// Generate gravity frame from maze frame object, should only be used when paths between nodes are perfectly straight. /// </summary> /// <param name="mazeFrame">MazeFrame object.</param> private void GenerateGravityFrameFromMazeObj(MazeFrame mazeFrame, float closebyDist) { // Generate gravity frame based on maze nodes gravityFrame = new List <GravityNode>(mazeFrame.Nodes.Count); // First create base list, then add neighbors foreach (MazeNode mazeNode in mazeFrame.Nodes) { // Create gravity node from maze node GravityNode gravNode = new GravityNode(mazeNode.Position, mazeNode.Identifier); gravityFrame.Add(gravNode); } for (int i = 0; i < gravityFrame.Count; i++) { foreach (MazeNode neighbor in mazeFrame.Nodes[i].ConnectedNeighbors) { gravityFrame[i].neighbors.Add(gravityFrame.Find(x => x.identifier == neighbor.Identifier)); } } // Add closeby list to each node AddClosebyNodes(closebyDist); }
/// <summary> /// Generate gravity frame from splines fitted to maze frame. /// </summary> /// <param name="mazeFrameSplines">Splines fitted to maze frames.</param> ///// <param name="closebyDist"> Distance at which nodes are considered close by.</param> /// <param name="junctionDist"> Distance at which nodes are considered close to junction.</param> private void GenerateGravityFrameFromSplines(MazeFrame mazeFrame, MazeFrameSplines mazeFrameSplines, float junctionDist, float planeWidth) { // Generate gravity frame based on maze frame fitted splines int nodeCount = 0; foreach (MazeFrameSplines.SplineSegment splineSeg in mazeFrameSplines.SplineSegments) { nodeCount += splineSeg.spline.NSamplesToUse; } gravityFrame = new List <GravityNode>(nodeCount); // Generate sub frame to use later List <List <GravityNode> > segmentSubFrame = new List <List <GravityNode> >(mazeFrameSplines.SplineSegments.Count); // Create nodes for each splines for (int iSpline = 0; iSpline < mazeFrameSplines.SplineSegments.Count; iSpline++) { segmentSubFrame.Add(new List <GravityNode>(mazeFrameSplines.SplineSegments[iSpline].spline.NSamplesToUse)); GravityNode prevNode = null; for (int i = 0; i < mazeFrameSplines.SplineSegments[iSpline].spline.NSamplesToUse; i++) { Vector3 currPos = mazeFrameSplines.SplineSegments[iSpline].spline.GetPointOnSpline(mazeFrameSplines.SplineSegments[iSpline].spline.SampleIndToT(i)); Vector3 currTang = mazeFrameSplines.SplineSegments[iSpline].spline.GetTangentToPointOnSpline(mazeFrameSplines.SplineSegments[iSpline].spline.SampleIndToT(i)).normalized; Vector3 currNorm = mazeFrameSplines.SplineSegments[iSpline].spline.DefaultGetNormalAtT(mazeFrameSplines.SplineSegments[iSpline].spline.SampleIndToT(i)).normalized; Vector3 cross = Vector3.Cross(currTang, currNorm); Vector3[] planePoints = new Vector3[2] { currPos + (cross * (planeWidth / 2f)), currPos - (cross * (planeWidth / 2f)) }; GravityNode node = new GravityNode(currPos, iSpline + "-" + currPos.ToString(), planePoints); if (prevNode != null) { node.neighbors.Add(prevNode); prevNode.neighbors.Add(node); } // Determine if near junction if (mazeFrameSplines.SplineSegments[iSpline].startNeighbors.Count > 0) { if (Vector3.Distance(currPos, mazeFrameSplines.SplineSegments[iSpline].spline.GetPointOnSpline(0)) < junctionDist) { node.nearJunction = true; } } if (mazeFrameSplines.SplineSegments[iSpline].endNeighbors.Count > 0) { if (Vector3.Distance(currPos, mazeFrameSplines.SplineSegments[iSpline].spline.GetPointOnSpline(1)) < junctionDist) { node.nearJunction = true; } } // Add to frame gravityFrame.Add(node); prevNode = node; // Add spline segment sub-frame as well segmentSubFrame[iSpline].Add(node); } } // Create closeby list from, and connect, neighboring splines for (int iSeg = 0; iSeg < mazeFrameSplines.SplineSegments.Count; iSeg++) { // Add frame to its own closeby List <GravityNode> currSubFrame = segmentSubFrame[iSeg]; foreach (GravityNode node in currSubFrame) { node.closeby.AddRange(currSubFrame); } // Start/end of spline List <List <MazeFrameSplines.SplineSegment> > segList = new List <List <MazeFrameSplines.SplineSegment> >(2) { mazeFrameSplines.SplineSegments[iSeg].startNeighbors, mazeFrameSplines.SplineSegments[iSeg].endNeighbors }; for (int iStartEnd = 0; iStartEnd <= 1; iStartEnd++) { foreach (MazeFrameSplines.SplineSegment neighSeg in segList[iStartEnd]) { // Get sub frame index List <GravityNode> neighSegSF = segmentSubFrame[mazeFrameSplines.SplineSegments.IndexOf(neighSeg)]; // Add to closeby list foreach (GravityNode node in currSubFrame) { node.closeby.AddRange(neighSegSF); } // Connect start/end switch (iStartEnd) { case 0: { if (Vector3.Distance(currSubFrame[0].position, neighSegSF[0].position) < Vector3.Distance(currSubFrame[0].position, neighSegSF[neighSegSF.Count - 1].position)) { currSubFrame[0].neighbors.Add(neighSegSF[0]); } else { currSubFrame[0].neighbors.Add(neighSegSF[neighSegSF.Count - 1]); } break; } case 1: { if (Vector3.Distance(currSubFrame[currSubFrame.Count - 1].position, neighSegSF[0].position) < Vector3.Distance(currSubFrame[currSubFrame.Count - 1].position, neighSegSF[neighSegSF.Count - 1].position)) { currSubFrame[currSubFrame.Count - 1].neighbors.Add(neighSegSF[0]); } else { currSubFrame[currSubFrame.Count - 1].neighbors.Add(neighSegSF[neighSegSF.Count - 1]); } break; } } } } } }
public void SetPrevious(GravityNode previous) { this.previous = previous; }
public void SetNext(GravityNode next) { this.next = next; }
/// <summary> /// Generate gravity frame from object center line nodes (the output given by <see cref="MazePopulator.PopulateWithCylinders(MazeFrame, float, int)"/>. /// </summary> /// <param name="objCenterLineNodes">Object center line nodes, given as output from <see cref="MazePopulator.PopulateWithCylinders(MazeFrame, float, int)"/>.</param> private void GenerateGravityFrameFromObjCenterLineNodes(Dictionary <string, Vector3> objCenterLineNodes, float closebyDist) // FIXME name parsing below is too complicated, should be easier way { // Generate gravity frame based on maze nodes gravityFrame = new List <GravityNode>(objCenterLineNodes.Count); // First create base list with shortened names and separate neighbor dictionary Dictionary <string, List <string> > neighbors = new Dictionary <string, List <string> >(objCenterLineNodes.Count); foreach (KeyValuePair <string, Vector3> node in objCenterLineNodes) { // Create gravity node GravityNode gravNode = new GravityNode(node.Value, node.Key); gravityFrame.Add(gravNode); //Parse identifier string[] identifier = node.Key.Split(new char[] { '-' }, System.StringSplitOptions.RemoveEmptyEntries); if ((identifier[0][0] == 'c') && identifier.Length > 6) { throw new System.Exception("Node naming in PopulateMaze is incorrect."); } if ((identifier[0][0] == 'b') && identifier.Length > 3) { throw new System.Exception("Node naming in PopulateMaze is incorrect."); } // Generate neighbor identifiers and add to dictionary // The naming schemes exist, with specified neighbors: // conn-<center_nodeid>-<start_neighid>-<end_neighid>-<num>-<index==0> // --> base-<center_nodeid>-<start_neighid> // conn-<center_nodeid>-<start_neighid>-<end_neighid>-<num>-<index==num> // --> base-<center_nodeid>-<end_neighid> // conn-<center_nodeid>-<start_neighid>-<end_neighid>-<num>-<index!=0/num> // --> conn-<center_nodeid>-<start_neighid>-<end_neighid>-<num>-<index-1> // --> conn-<center_nodeid>-<start_neighid>-<end_neighid>-<num>-<index+1> // base-<nodeid>-<neighid> // --> base-<neighid>-<nodeid> // (if exists)--> conn-<nodeid>-<neighid>-<ANY> // List <string> currNeighbors = new List <string>(); if (identifier[0][0] == 'b') // isBase { currNeighbors.Add("base" + "-" + identifier[2] + "-" + identifier[1]); // NEEDS TO ADDED INDIVIDUALLY } else if (identifier[0][0] == 'c') // isConn { int curveNum = System.Int32.Parse(identifier[4]); int curveInd = System.Int32.Parse(identifier[5]); if ((curveInd > (curveNum - 1)) || curveNum < 2) { throw new System.Exception("Node naming in PopulateMaze is incorrect."); } if (curveInd == 0) { currNeighbors.Add("base" + "-" + identifier[1] + "-" + identifier[2]); // NEEDS TO ADDED RECIPROCALLY (as the base doesn't if it has a conn) // FIXME reciprocal, or..., using maze for neighbor def currNeighbors.Add("conn" + "-" + identifier[1] + "-" + identifier[2] + "-" + identifier[3] + "-" + identifier[4] + "-" + (1)); } else if (curveInd == (curveNum - 1)) { currNeighbors.Add("base" + "-" + identifier[1] + "-" + identifier[3]); // NEEDS TO ADDED RECIPROCALLY (as the base doesn't if it has a conn) currNeighbors.Add("conn" + "-" + identifier[1] + "-" + identifier[2] + "-" + identifier[3] + "-" + identifier[4] + "-" + (curveNum - 2)); } else { currNeighbors.Add("conn" + "-" + identifier[1] + "-" + identifier[2] + "-" + identifier[3] + "-" + identifier[4] + "-" + (curveInd - 1)); currNeighbors.Add("conn" + "-" + identifier[1] + "-" + identifier[2] + "-" + identifier[3] + "-" + identifier[4] + "-" + (curveInd + 1)); } } else { throw new System.Exception("Node naming in PopulateMaze is incorrect."); } neighbors.Add(node.Key, currNeighbors); } // Add neighbors to gravity frame nodes foreach (GravityNode node in gravityFrame) { if (node.identifier[0] == 'b') // isBase { foreach (string currneighbor in neighbors[node.identifier]) { node.neighbors.Add(gravityFrame.Find(x => x.identifier == currneighbor)); } } if (node.identifier[0] == 'c') // isConn { foreach (string currneighbor in neighbors[node.identifier]) { node.neighbors.Add(gravityFrame.Find(x => x.identifier == currneighbor)); } foreach (GravityNode nb in node.neighbors) { if (nb.identifier[0] == 'b') { nb.neighbors.Add(node); } // RECIPROCAL ADDING FOR BASE TO CONN // FIXME could also do with an 'if exists' type of check } } } // FIXME not all close nodes are merged //// Combine nodes at (nearly) identical positions //Stack<GravityNode> toRemove = new Stack<GravityNode>((int)Mathf.Round(gravityFrame.Count / 10f)); // guess... //for (int inode1 = 0; inode1 < gravityFrame.Count - 1; inode1++) //{ // for (int inode2 = inode1 + 1; inode2 < gravityFrame.Count; inode2++) // { // if ((Vector3.Distance(gravityFrame[inode1].position, gravityFrame[inode2].position) < 0.1f) && !toRemove.Contains(gravityFrame[inode2])) // { // // For each neighbor of node2: // // - remove node2 from neighbor.neighbors // // - add neighbor to node1.neighbors (if not already neighbors) // // - add node1 to neigbor.neighbors (if not already neighbors) // foreach (GravityNode neighborlvl2 in gravityFrame[inode2].neighbors) // { // neighborlvl2.neighbors.Remove(gravityFrame[inode2]); // if (!gravityFrame[inode1].neighbors.Contains(neighborlvl2)) // { // gravityFrame[inode1].neighbors.Add(neighborlvl2); // neighborlvl2.neighbors.Add(gravityFrame[inode1]); // } // } // // Then, remove node2 from node1 and from frame // toRemove.Push(gravityFrame[inode2]); // if (gravityFrame[inode1].neighbors.Contains(gravityFrame[inode2])) { gravityFrame[inode1].neighbors.Remove(gravityFrame[inode2]); } // } // } //} //while (toRemove.Count > 0) //{ // GravityNode currNode = toRemove.Pop(); // gravityFrame.Remove(currNode); //} // Add closeby list to each node AddClosebyNodes(closebyDist); }
public void Clear() { current = null; first = null; }
public GravityList() { first = null; current = null; }