Exemplo n.º 1
0
    public void CheckAndAddEdgeToVertex(Collider other, bool editMode = false)
    {
        if (!other)         // shorthand for (other == null)
        {
            return;
        }

        EdgeScript edge = other.GetComponent <EdgeScript> ();

        if (edge)
        {
            if (editMode)
            {
                // update the edge to link to this vertex, but only in edit mode
                edge.CheckAndAddVertexToEdge(GetComponent <Collider> ());
            }
            for (int i = 0; i < Edges.Length; i++)
            {
                if (Edges [i] == edge)
                {
                    // if this edge is already in the list there is no need to add it a second time
                    break;
                }
                if (Edges [i] == null)
                {
                    // add edge to first empty slot in the list
                    Edges [i] = edge;
                    break;
                }
            }
        }
    }
Exemplo n.º 2
0
    public void CheckAndRemoveEdgeFromVertex(Collider other, bool editMode = false)
    {
        if (!other)         // shorthand for (other == null)
        {
            return;
        }

        EdgeScript edge = other.GetComponent <EdgeScript> ();

        if (edge)
        {
            if (editMode)
            {
                // update the edge that links to this vertex, but only in edit mode
                edge.CheckAndRemoveVertexFromEdge(GetComponent <Collider> ());
            }
            for (int i = 0; i < Edges.Length; i++)
            {
                if (Edges [i] == edge)
                {
                    // remove the edge from the list and move all following edges in the list up one spot
                    for (int j = i + 1; j < Edges.Length; j++)
                    {
                        Edges [j - 1] = Edges [j];
                    }
                    Edges [Edges.Length - 1] = null;
                    break;
                }
            }
        }
    }
Exemplo n.º 3
0
    private void loadPlan(string path)
    {
        print("importing plan");
        string line;

        using (StreamReader sr = new StreamReader(path)) {
            line = sr.ReadToEnd();
        }

        JsonReader reader = new JsonReader();

        var output = reader.Read <Dictionary <string, object>[]>(line);

        foreach (Dictionary <string, object> step in output)
        {
            int t = (int)step["t"];
            try {
                foreach (Dictionary <string, object> signal in (Dictionary <string, object>[])step["signals"])
                {
                    //Find edge

                    //modify occupants/signal
                    //Set up cache for quickly finding edges
                    GameObject edge = GameObject.Find(signal["start"].ToString() + "->" + signal["end"].ToString());
                    EdgeScript scpt = edge.GetComponent <EdgeScript>();

                    scpt.occupantsSchedule[t] = (int)signal["predictedOccupancy"];
                    scpt.flowSchedule[t]      = (int)signal["inFlow"];
                    scpt.signalSchedule[t]    = (bool)signal["signal"];
                }
            } catch (Exception e) {
            }
            maxT = t;
        }
    }
Exemplo n.º 4
0
    private EdgeWrapper GetOrMakeEdgeWrapper(EdgeScript edge, Dictionary <EdgeScript, EdgeWrapper> edgeDict)
    {
        EdgeWrapper wrapper;

        if (!edgeDict.TryGetValue(edge, out wrapper))
        {
            wrapper         = new EdgeWrapper(edge);
            edgeDict [edge] = wrapper;
        }
        return(wrapper);
    }
Exemplo n.º 5
0
    // Uses the neighbours given to the node to generate edges
    public void ManualEdgeCreation()
    {
        foreach (GameObject node in neighbours)
        {
            NodeScript neighbourNode = node.GetComponent <NodeScript>();

            //don't add edge if already exists
            if (node != null && node != this && this.FindEdgeTo(neighbourNode) == null)
            {
                EdgeScript edge = new EdgeScript(this, neighbourNode);
                edge.SetCost((node.transform.position - this.transform.position).magnitude);

                edges.Add(edge);
            }
        }
    }
Exemplo n.º 6
0
    // Generate edges for auto grid generation
    public void GenerateEdges()
    {
        Collider[] neighbourNodes = Physics.OverlapBox(transform.position, transform.localScale);

        foreach (Collider nodeCollider in neighbourNodes)
        {
            NodeScript node = nodeCollider.gameObject.GetComponent <NodeScript>();

            if (node != null && node != this)
            {
                EdgeScript edge = new EdgeScript(this, node);
                edge.SetCost((node.transform.position - this.transform.position).magnitude);

                edges.Add(edge);
            }
        }
    }
Exemplo n.º 7
0
    // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
    // TODO: Take this specific function, Modify it to only calculate BPM cost
    // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
    public float GetCost(VertexWrapper fromNodeWrapper, VertexWrapper toNodeWrapper, EdgeScript edge, CostMethodType method, TravelerProfile Traveler = null, VertexScript startNode = null, VertexScript goalNode = null)
    {
        VertexScript fromNode = fromNodeWrapper.Vertex;
        VertexScript toNode   = toNodeWrapper.Vertex;

        // the baseCost is our interpretation of the physical cost of travel, ignoring any personality traits
        float baseCost = 0f;

        switch (method)
        {
        case CostMethodType.ClosestToCompass:
            // pick the path with the smallest angle compared to the vector between you and the destination
            Vector3 differenceForEdge = toNode.transform.position - fromNode.transform.position;
            Vector3 differenceForGoal = goalNode.transform.position - fromNode.transform.position;
            baseCost = Mathf.Abs(Vector3.Angle(differenceForEdge, differenceForGoal));
            break;

        case CostMethodType.DistanceHorizontal:
            // use only the pure horizontal distance, ignoring any vertical distance
            Vector3 difference = toNode.transform.position - fromNode.transform.position;
            difference.y = 0;
            baseCost     = difference.magnitude;
            break;

        case CostMethodType.DistanceTrue:
            // use the typical 3D distance between the two points
            baseCost = (toNode.transform.position - fromNode.transform.position).magnitude;
            break;

        case CostMethodType.DistanceVertical:
            // use only the pure vertical distance, ignoring any horizontal distance
            // this is equivalent to saying "walking on flat ground is easy, but any change in elevation is hard"
            baseCost = Mathf.Abs(toNode.transform.position.y - fromNode.transform.position.y);
            break;

        case CostMethodType.NumberOfStops:
            // counts the number the vertices between the start and the goal nodes
            baseCost = 1f;
            break;

        case CostMethodType.PeakLover:
            // for people who enjoy walking along the tops of hills and mountains so they can enjoy the view
            // there is a cost for going down, but not for going up
            baseCost = Mathf.Max(0f, fromNode.transform.position.y - toNode.transform.position.y);
            break;

        case CostMethodType.SmoothTurns:
            // when you're driving very fast or driving a very large vehicle it's important that your turns are smooth
            // the cost is smaller if the edge is a straight-forward continuation of the last edge and larger if you have to make a sharp turn
            if (fromNodeWrapper.LowestCostEdgeSoFar != null)
            {
                // all nodes except the start node will have a "lowest cost edge so far", so we can use it
                Vector3 differenceNext     = toNode.transform.position - fromNode.transform.position;
                Vector3 differencePrevious = fromNode.transform.position - fromNodeWrapper.LowestCostEdgeSoFar.Edge.GetOtherVertex(fromNode).transform.position;
                // ignore changes in elevation so that only horizontal turning is taken into account
                differenceNext.y     = 0;
                differencePrevious.y = 0;
                // the cost should be higher if the angle is larger or if the distance traveled is shorter (i.e. it's a sharper turn)
                // the cost should be lower if the angle is smaller or if the distance traveled is larger (i.e. it's a long smooth turn)
                baseCost = Mathf.Abs(Vector3.Angle(differencePrevious, differenceNext)) / (differencePrevious.magnitude + differenceNext.magnitude);
            }
            else
            {
                // the start node has no "lowest cost edge so far" so just use 0 (no need to turn when leaving the start node)
                baseCost = 0f;
            }
            break;


        ///////////////////
        case CostMethodType.Steepness:          // <- Use this for calculating edge BPM Cost
            // the cost is the angle that the edge makes with the horizon
            // so flat paths are good but the steeper the edge (going up or going down) the more it costs
            Vector3 differenceFull = toNode.transform.position - fromNode.transform.position;
            Vector3 differenceFlat = new Vector3(differenceFull.x, differenceFull.z, 0f);
            baseCost = Mathf.Abs(Vector3.Angle(differenceFlat, differenceFull));
            break;

        case CostMethodType.UpSucksDownOkay:            // <- work with both
            // for people who hate walking uphill but don't mind going downhill
            // there is a cost for going up but no cost for going down
            baseCost = Mathf.Max(0f, toNode.transform.position.y - fromNode.transform.position.y);
            break;
        ////////////////////


        default:
            // if nothing else, just use the physical length of the edge
            baseCost = (edge.transform.localScale.y * 2f);
            break;
        }
        // end of baseCost calculation

        // retrieve the traveler profile, then check if the profile is null to prevent errors
        if (Traveler == null)
        {
            Traveler = TravelerProfileCatalog.GetProfile(TravelerProfileCatalog.TravelerType.Neutral);
        }

        // if profile is not null use the average of the trait indexes (which will be -1 to 1)
        // but if profile is null then just use zero
        float compatibility = (Traveler != null
                        ?  (Traveler.LikesToWalk * edge.PedestrianFriendly +
                            Traveler.LikesToBicycle * edge.BicyclistFriendly +
                            Traveler.LikesToDrive * edge.CarFriendly +
                            Traveler.LikesVistas * edge.Beautiful +
                            Traveler.LikesFood * edge.FoodAvailable +
                            Traveler.LikesHeart * edge.Heart) / 5f

                        : 0f);

        // (1 - compatibility) gives a value that is 0 (good) to 2 (bad)
        // this translates to:
        //   -- cost is reduced when the traveler likes the edge
        //   -- cost is not affected when the traveler has no opinion of the edge
        //   -- cost is increased when the traveler dislikes the edge
        float personalityCost = (1f - compatibility);

        // using personalityCost * baseCost means "the traveler's emotions can make anything easy or anything hard"
        return(personalityCost * baseCost);
    }
    // Update is called once per frame

    public void Update()
    {
        if (group && group.goals == null)
        {
            group = null;
            goal  = null;
        }



        if (!paused)
        {
            if (GridManagerScript.enableCollisions && avatar.GetComponent <Trigger>().stop)
            {
                return;
            }
            //sanity check
            if (nextNode == null || currentNode == null || currentNode.FindEdgeTo(nextNode) == null)
            {
                return;
            }

            //update a the path when end is closed
            if (GridManagerScript.usingAStarOnly &&
                (AStarPath.Count == 0 || (entering && !AStarPath.Last().goal)))
            {
                Debug.Log("NewPath " + AStarPath.Last());
                indexAtAstarPath = 0;
                AStarPath        = GridManagerScript.AStar.
                                   GenerateEntryPath(currentNode, group != null? group.goals.ToArray() : null);
                nextNode = GetBestDiffusionNode(currentNode);
            }

            if (!GridManagerScript.isTest)
            {
                float speedLimit = GridManagerScript.citySpeed;
                //get the edge speed and calculate speed limit if it exist, else assume no difference
                //calc traffic
                EdgeScript edge = currentNode.FindEdgeTo(nextNode);
                if (currentNode != null && edge != null)
                {
                    //speed in miles per hour
                    //0.0003miles/s = 0.066p/second per second (fs - fake seconds)
                    speedLimit = edge.GetSpeed();
                    //GET THIS CHECKED OUT
                    // speedLimit = speedLimit - speedLimit * (edge.nodesTraffic / EdgeScript.maxTraffic) * EdgeScript.maxTrafficP;
                }
                if (GridManagerScript.accelerationCalculations)
                {
                    //if the next node is the parking node and avatar has some speed0 slow down
                    if (nextNode.openParking && (nextNode.NodeStatus == NodeScript.NODE_STATUS.END && atmSpeed >= (speedLimit * parkingSpeed)))
                    {
                        atmSpeed -= atmSpeed * (decceleration * 2);
                    }

                    //else accelerate// decelerate
                    else
                    {
                        //calc deceleration
                        //if above speed limit or
                        if (atmSpeed > speedLimit)
                        {
                            atmSpeed -= atmSpeed * decceleration;
                        }
                        //calc acceleration
                        else if (atmSpeed < speedLimit)
                        {
                            acceleration = acceleration * accelerationSteepness;
                            atmSpeed    += atmSpeed * acceleration;
                            if (atmSpeed > speedLimit)
                            {
                                atmSpeed = speedLimit;                        //skip coming into calculations for dec or acc next time
                            }
                        }
                    }
                    speedLimit = atmSpeed;
                }
                //foreach frame translate
                //checkout 123 for explanation
                //1 mile irl = 240p in game
                //add about 20p to make up for inconsistency of time.deltatime
                //every update calc how much of a second has passed in game and add it on the speed

                float speedinpixels     = (speedLimit * 260) / 3600; //mile/h
                float translatePerFrame = speedinpixels * GridManagerScript.secondsPerSecond * Time.deltaTime;

                Vector3 translateAvatar = avatar.transform.position + (nextNode.transform.position - avatar.transform.position).normalized * translatePerFrame; //vector to translate by

                //get the distance between avatar and goal and see if you're overshooting
                //if you're not overshooting just continue
                //if you are overshooting just arrive
                //Db (distance before) is hypothenos from origin to goal (basic distance)
                //Da (distance after) is the hypothenos from origin to the potential new destination (towards goal)
                float Db = Vector3.Distance(avatar.transform.position, nextNode.transform.position);
                float Da = Vector3.Distance(avatar.transform.position, translateAvatar);

                if (Da > Db)
                {
                    avatar.transform.position = nextNode.transform.position;
                }
                else
                {
                    avatar.transform.position = translateAvatar;
                }
            }
            else
            {
                avatar.transform.position = avatar.transform.position + (nextNode.transform.position - avatar.transform.position).normalized;
            }

            // Check if the avatar is within the bounds of the next node's centre
            if (avatar.transform.position.x >= nextNode.transform.position.x - 1.0f &&
                avatar.transform.position.y >= nextNode.transform.position.y - 1.0f &&
                avatar.transform.position.z >= nextNode.transform.position.z - 1.0f &&
                avatar.transform.position.x <= nextNode.transform.position.x + 1.0f &&
                avatar.transform.position.y <= nextNode.transform.position.y + 1.0f &&
                avatar.transform.position.z <= nextNode.transform.position.z + 1.0f)
            {
                double timeOfDay = getTimeOfDay();

                currentNode.FindEdgeTo(nextNode).removeOccupancy(timeOfDay);
                // If not at the destination
                //TODO REWRITE THIS CHECK AND THE ONES BELOW
                //if no specific goal any goals count
                //if specific goal, all goals count
                if ((goal == null && ((nextNode.NodeStatus != NodeScript.NODE_STATUS.END && !isCityAvatar) ||
                                      (!nextNode.goal && isCityAvatar && entering) || (!nextNode.exit && isCityAvatar && !entering))) ||
                    (goal != null && goal != nextNode))
                {
                    //set the previous node to the current node
                    previousNode = currentNode;
                    // Set the current node as the next node
                    currentNode = nextNode;
                    // Calculate the next node
                    if (entering)
                    {
                        nextNode = GetBestDiffusionNode(nextNode);
                    }
                    else
                    {
                        nextNode = GetBestExitDiffusionNode(nextNode);
                    }
                    currentNode.FindEdgeTo(nextNode).addOccupancy(timeOfDay);
                    totalPathLength += currentNode.FindEdgeTo(nextNode).roadLen;
                }
                else
                {
                    // check if destination reached is in goals
                    //if goal is not specified arrive at any of the goals
                    //if goal is specified only  arrive at the given goal
                    //only arrive at redir goal
                    if ((goal == null && (group == null || group.goals == null || (group.goals.Contains(nextNode) || (redirected && group.redirectToGoals.Contains(nextNode))) || !entering)) ||
                        (goal == nextNode))
                    {
                        //reset the overlapping avatars on the node behind you
                        //if(GridManagerScript.isTest) currentNode.avatarsOverlapping = -1;
                        // If your destination was a parking lot add a car to the lot
                        if ((entering && nextNode.goal && nextNode.GetComponentInParent <ParkingLot>() || goal == nextNode))
                        {
                            timeArrived = (float)timeOfDay; //get the current time
                            timeLeftArrivedVTCAll.Add(new Tuple <float, float, float>(timeLeft, timeArrived, totalPathLength));
                            nextNode.GetComponentInParent <ParkingLot>().AddCar(this);
                            endReached = true;
                        }
                        else if (!entering)
                        {
                            endReached = true;
                        }
                    }

                    //go to the actual goal
                    else
                    {
                        //set the previous node to the current node
                        previousNode = currentNode;
                        // Set the current node as the next node
                        currentNode = nextNode;

                        // Calculate the next node
                        //passes current end that is not it's own goal
                        nextNode = GetBestDiffusionNode(nextNode);
                        currentNode.FindEdgeTo(nextNode).addOccupancy(timeOfDay);
                        totalPathLength += currentNode.FindEdgeTo(nextNode).roadLen;
                    }
                }
            }
        }
    }
Exemplo n.º 9
0
    public void loadGraph()
    {
        //Destroy all nodes


        //read file
        string line;

        using (StreamReader sr = new StreamReader(path)) {
            line = sr.ReadToEnd();
        }

        JsonReader reader = new JsonReader();

        var output = reader.Read <Dictionary <string, object> >(line);

        Dictionary <string, object>[] jnode = (Dictionary <string, object>[])output ["nodes"];
        //create nodes
        print("CREATE NODES");
        foreach (Dictionary <string, object> jNode in jnode)
        {
            GameObject node = (GameObject)Instantiate(nodeTemp);


            node.name = jNode["id"].ToString();
            NodeScript scpt = node.GetComponent <NodeScript>();

            scpt.Id        = jNode["id"].ToString();
            scpt.occupants = (int)jNode["arrivals"];
            scpt.goalState = (bool)jNode["isGoal"];

            Dictionary <string, object> pos = (Dictionary <string, object>)jNode["position"];
            node.transform.position = new Vector3(float.Parse(pos["x"].ToString()),
                                                  float.Parse(pos["y"].ToString()),
                                                  float.Parse(pos["z"].ToString()));
        }
        print("CREATE EDGES");
        //Create edges
        foreach (Dictionary <string, object> jNode in jnode)
        {
            try {
                foreach (Dictionary <string, object> jEdge in (Dictionary <string, object>[])jNode["edges"])
                {
                    GameObject start = GameObject.Find(jEdge["start"].ToString());
                    GameObject end   = GameObject.Find(jEdge["end"].ToString());

                    GameObject edge = (GameObject)Instantiate(edgeTemp,
                                                              start.transform.position,
                                                              start.transform.rotation);
                    edge.name = jEdge ["start"].ToString() + "->" + jEdge ["end"].ToString();
                    EdgeScript edgeScpt = edge.GetComponent <EdgeScript> ();


                    edgeScpt.flowRate     = (int)jEdge ["flowRate"];
                    edgeScpt.cost         = (int)jEdge ["cost"];
                    edgeScpt.start        = start;
                    edgeScpt.end          = end;
                    edge.transform.parent = start.transform;
                }
            } catch (InvalidCastException e) {
            }
        }

        //Create elevators
        try {
            foreach (Dictionary <string, object> jElevator in (Dictionary <string, object>[])output ["elevators"])
            {
                //instantiate new elevator
                GameObject elevator = (GameObject)Instantiate(elevatorTemp);
                elevator.name = jElevator["id"].ToString() + "elevator";
                ElevatorScript scpt = elevator.GetComponent <ElevatorScript>();

                Dictionary <string, object>[] jNodes = (Dictionary <string, object>[])jElevator["nodes"];

                GameObject[] nodes = new GameObject[jNodes.Length];
                //Create new Edge array
                int index = 0;

                foreach (Dictionary <string, object> node in jNodes)
                {
                    nodes[index] = GameObject.Find(node["id"].ToString());
                    index++;
                }

                scpt.Id              = jElevator["id"].ToString();
                scpt.nodes           = nodes;
                scpt.initialLocation = jElevator["initialLocation"].ToString();
                //Find edges by name
            }
        } catch (InvalidCastException e) {
        }
    }
Exemplo n.º 10
0
 public EdgeWrapper(EdgeScript Edge, float Cost = float.PositiveInfinity)
 {
     this.Edge = Edge;
     this.Cost = Cost;
 }
    public void StretchEdgeBetweenTwoVertices(VertexScript vertexA, VertexScript vertexB, EdgeScript edge)
    {
        Vector3 leftVertexPosition  = vertexA.transform.position;
        Vector3 rightVertexPosition = vertexB.transform.position;

        edge.transform.position = Vector3.Lerp(leftVertexPosition, rightVertexPosition, 0.5f);
        Vector3 positionDifferences = rightVertexPosition - leftVertexPosition;

        edge.transform.localScale = new Vector3(EdgeThickness, positionDifferences.magnitude * 0.5f, EdgeThickness);
        edge.transform.rotation   = Quaternion.LookRotation(positionDifferences);
        edge.transform.Rotate(new Vector3(90, 0, 0));
    }