public DiffusionAvatarScript(PeakingGroup group, bool prebooked) : base()
    {
        timeLeft = (float)getTimeOfDay(); //get the current time
        if (group.goals == null)
        {
            return;
        }

        this.group = group;
        //check space in main parking destination, check if prebooking
        //prebooked ones head towards the goal and the goal is always open for them
        if (prebooked)
        {
            id = Guid.NewGuid();
            if (group.goals.First().GetComponent <ParkingLot>().reserveSpace(id))
            {
                //have only one goal
                goal = group.goals.First();
                //change booked status
                this.prebooked = prebooked;
            }
        }
    }
    // 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;
                    }
                }
            }
        }
    }
コード例 #3
0
 public void removeSpawnBucket(PeakingGroup g)
 {
     this.groupsSpawnBuckets.Remove(g);
     this.spawnGroupSums.Remove(g);
 }
コード例 #4
0
 public void addSpawnBucket(PeakingGroup g, Dictionary <double, int> carSpawnerBuckets)
 {
     this.groupsSpawnBuckets[g] = carSpawnerBuckets;
     spawnGroupSums[g]          = 0;
 }
コード例 #5
0
    //Calculates the diffusion value for the node
    private void CalculateDiffusion()
    {
        for (int i = 0; i < groups.Length; i++)
        {
            //check for desync
            if (i >= staticDiffusionBases.Length)
            {
                return;
            }

            PeakingGroup group = groups[i].GetComponent <PeakingGroup>();

            //if non-goal oriented group skip
            if (groups[i].goals == null)
            {
                continue;
            }

            // If there is an end and this node isn't the goal and not blocked

            if (myManager.GetEndAllocated() && !group.goals.Contains(this) && NodeStatus != NODE_STATUS.BLOCKED)
            {
                // Stores the origional value for the calculation
                float originalDiff          = diffusions[group.index];
                float originalBaseDiffusion = staticDiffusionBases[group.index];
                //specific goal (only goes straight to)
                float originalSpecificGoalDiffusion = goalTests[group.index];

                //reedirection diffusions when avatar is redirected
                float originalRedirDiff       = redirectionDiffusion[group.index];
                float originalRedirStaticDiff = redirectionStaticDiffusion[group.index];
                bool  isRedirGoal             = group.redirectToGoals.Contains(this) && openParking; //is this a open redirection goal

                // For each of the nodes neighbours

                foreach (EdgeScript edge in edges)
                {
                    // If they are not a blocked node use thier diffusion value for the equation
                    if (edge.GetTo().NodeStatus != NODE_STATUS.BLOCKED && !edge.GetTo().spawner)
                    {
                        try
                        {
                            staticDiffusionBases[group.index] += (myManager.diffusionCoeff * (edge.GetTo().staticDiffusionBases[group.index] - originalBaseDiffusion));
                            diffusions[group.index]           += (myManager.diffusionCoeff * (edge.GetTo().diffusions[group.index] - originalDiff));

                            goalTests[group.index] += (myManager.diffusionCoeff * (edge.GetTo().goalTests[group.index] - originalSpecificGoalDiffusion));

                            if (!isRedirGoal)
                            {
                                redirectionDiffusion[group.index]       += (myManager.diffusionCoeff * (edge.GetTo().redirectionDiffusion[group.index] - originalRedirDiff));
                                redirectionStaticDiffusion[group.index] += (myManager.diffusionCoeff * (edge.GetTo().redirectionStaticDiffusion[group.index] - originalRedirStaticDiff));
                            }
                        }
                        catch (IndexOutOfRangeException) {
                            //doesn't affect anything goes in due to bad referencing and race condition when placing new parking lot
                        }
                    }
                }

                staticDiffusionBases[group.index] = staticDiffusionBases[group.index] - (staticDiffusionBases[group.index] * (myManager.decayRate));
                diffusions[group.index]           = (diffusions[group.index] - (diffusions[group.index] * (myManager.decayRate))); // Apply the decay rate to the diffusion

                goalTests[group.index] = (goalTests[group.index] - (goalTests[group.index] * (myManager.decayRate)));

                if (!isRedirGoal)
                {
                    redirectionDiffusion[group.index]       = redirectionDiffusion[group.index] - (redirectionDiffusion[group.index] * (myManager.decayRate));
                    redirectionStaticDiffusion[group.index] = (redirectionStaticDiffusion[group.index] - (redirectionStaticDiffusion[group.index] * (myManager.decayRate)));
                }
            }
            // If the end hasn't been allocated only apply the decay rate
            else if (!myManager.GetEndAllocated())
            {
                staticDiffusionBases[group.index] = staticDiffusionBases[group.index] - (staticDiffusionBases[group.index] * (myManager.decayRate));
                diffusions[group.index]           = (diffusions[group.index] - (diffusions[group.index] * myManager.decayRate));

                goalTests[group.index]                  = (goalTests[group.index] - (goalTests[group.index] * (myManager.decayRate)));
                redirectionDiffusion[group.index]       = redirectionDiffusion[group.index] - (redirectionDiffusion[group.index] * (myManager.decayRate));
                redirectionStaticDiffusion[group.index] = (redirectionStaticDiffusion[group.index] - (redirectionStaticDiffusion[group.index] * (myManager.decayRate)));
            }


            // If the goal node
            if (group.goals.Contains(this))
            {
                // If there is parking available change the value based on the occupancy
                if (openParking)
                {
                    staticDiffusionBases[group.index] = goalDiffusion;
                    diffusions[group.index]           = goalDiffusion;
                    NodeStatus = NODE_STATUS.END;

                    if (group.origin == GetComponent <ParkingLot>())
                    {
                        goalTests[group.index] = goalDiffusion;
                    }
                }

                // If not open treat the node as a standard node
                else
                {
                    NodeStatus = NODE_STATUS.UNSEARCHED;
                    diffusions[group.index]           = 0;
                    staticDiffusionBases[group.index] = 0;
                }
            }
            //if if redir goals and actual goals overlap
            //MAKE ELSE IF IF YOU WANT TO NOT INCLUDE THE GOALS THAT ARE IN THE GOALS LIST
            if (group.redirectToGoals.Contains(this))
            {
                // If there is parking available change the value based on the occupancy
                if (openParking)
                {
                    redirectionDiffusion[group.index]       = goalDiffusion;
                    redirectionStaticDiffusion[group.index] = goalDiffusion;
                    NodeStatus = NODE_STATUS.END;
                }

                // If not open treat the node as a standard node
                else
                {
                    NodeStatus = NODE_STATUS.UNSEARCHED;
                    redirectionDiffusion[group.index]       = 0;
                    redirectionStaticDiffusion[group.index] = 0;
                }
            }
        }



        //update overall diffusions for redirected goals
        // If there is an end and this node isn't the end and not blocked
        //NONGOALS
        if (myManager.GetEndAllocated() && !goal && NodeStatus != NODE_STATUS.BLOCKED)
        {
            // Stores the origional value for the calculation
            float originalDiff          = diffusion;
            float originalBaseDiffusion = staticDiffusionBase;

            float sumDifference = 1f;

            float divne = 0;
            // For each of the nodes neighbours

            foreach (EdgeScript edge in edges)
            {
                // If they are not a blocked node use thier diffusion value for the equation
                if (edge.GetTo().NodeStatus != NODE_STATUS.BLOCKED && !edge.GetTo().spawner)
                {
                    staticDiffusionBase += (myManager.diffusionCoeff * (edge.GetTo().staticDiffusionBase - originalBaseDiffusion));
                    diffusion           += (myManager.diffusionCoeff * (edge.GetTo().diffusion - originalDiff));
                    divne += (originalBaseDiffusion - edge.GetTo().staticDiffusionBase);

                    sumDifference += (Math.Abs(edge.GetTo().div - div));
                }
            }
            div = divne;
            staticDiffusionBase = staticDiffusionBase - (staticDiffusionBase * (0.1f));

            diffusion = (diffusion + sumDifference * 1f) * (1 - 0.1f);    // Apply the decay rate to the diffusion
            //Debug.Log("diffusion is: "+(diffusion-originalDiff) + "sumdiff: " + sumDifference * 0.6f * (1 - myManager.decayRate));
        }
        // If the end hasn't been allocated only apply the decay rate
        else if (!myManager.GetEndAllocated())
        {
            staticDiffusionBase = staticDiffusionBase - (staticDiffusionBase * (myManager.decayRate));
            diffusion           = (diffusion - (diffusion * myManager.decayRate));
        }
        //GOALS
        // If the goal node is in the list of goals give it goal diffusion
        if (goal)
        {
            // If there is parking available change the value based on the occupancy
            if (openParking)
            {
                staticDiffusionBase = goalDiffusion;
                NodeStatus          = NODE_STATUS.END;
                diffusion           = goalDiffusion;
            }
            // If not open treat the node as a standard node
            else
            {
                NodeStatus          = NODE_STATUS.UNSEARCHED;
                diffusion           = 0;
                staticDiffusionBase = 0;
            }
        }



        // If there's any overlapping avatars
        // update each group outside of loop only once
        if (avatarsOverlapping >= 1)
        {
            overlappedTotalForArea.overlappedTotal += avatarsOverlapping;

            overlappedTotal   += avatarsOverlapping;                                                                                            //56 -> 5.6 -> 5.0 -> 0.5
            timeOfDayE         = (float)(GridManagerScript.hours * 1.0f + Math.Round((Math.Floor(GridManagerScript.minutes * 0.1f) * 0.1), 1)); //get the current time
            floats[timeOfDayE] = floats[timeOfDayE] + avatarsOverlapping;

            avatarsOvelapped[GridManagerScript.hours] = avatarsOvelapped[GridManagerScript.hours] + avatarsOverlapping;

            for (int i = 0; i < myManager.groups.Count; i++)
            {
                PeakingGroup group = groups[i].GetComponent <PeakingGroup>();

                // In not a destination node
                if (group.goals != null && !group.goals.Contains(this))
                {
                    diffusions[group.index] /= GridManagerScript.evasionStrength * avatarsOverlapping;
                }
            }
            //actual diffusion
            diffusion /= GridManagerScript.evasionStrength * avatarsOverlapping;
        }
    }
コード例 #6
0
    void Update()
    {
        //updates static
        if (myManager.groups.Count != groups.Length)
        {
            groups = myManager.groups.Select(x => x.GetComponent <PeakingGroup>()).ToArray();
            for (int i = 0; i < myManager.groups.Count; i++)
            {
                myManager.groups[i].GetComponent <PeakingGroup>().index = i;
            }
        }

        //updates local
        if (groups.Length != staticDiffusionBases.Length)
        {
            staticDiffusionBases       = new float[groups.Length];
            diffusions                 = new float[groups.Length];
            goalTests                  = new float[groups.Length];
            redirectionDiffusion       = new float[myManager.groups.Count];
            redirectionStaticDiffusion = new float[myManager.groups.Count];
        }



        //Next update

        /*
         * don't randomly spawn them
         * instead you should
         *
         *
         * Make it so that you give a number of cars to be spawned
         * you give a peak time for them to spawn and they spawn
         *
         * to achieve this you have to find out at each point (of time) how many cars you are supposed to spawn at each point
         *
         * check the z score for each time and make sure the % of cars that has to be spawned have been spawned
         *
         * TODO:
         * pre-compute Z table
         * and distribute spawn rate for each node
         *
         *
         *
         *
         */


        //randomly distributes injections
        //waves peak around mean (rush hour)
        if (spawner)
        {
            //timespeedlow less spawn
            //timespeedhigh more spawn

            //double flatRandNum = UnityEngine.Random.Range(0.0f, 1.01f);
            //double randNum = GridManagerScript.NextGaussianDoubleBoxMuller(0, 1); //calculate random Gausian double (mean is null)
            timeOfDayE = (float)(GridManagerScript.hours * 1.0f + (Math.Round(GridManagerScript.minutes * 0.1f / 10, 1) % 0.6)); //get the current time
            double timeOfDay = GridManagerScript.getTimeOfDay();                                                                 //get the current time
            //this is the x value

            /*foreach (GameObject obj in myManager.groups)
             * {
             *
             *  PeakingGroup group = obj.GetComponent<PeakingGroup>();
             *  double num = GridManagerScript.NormalDistribution(timeOfDay, group.rushHour, group.standartDeviation);
             *  num = timeOfDay <= group.rushHour ? num : 1-num;
             *
             *
             *  double randNumGroup = group.rushHour + group.standartDeviation * randNum;  //calculate for given mean and deviation //normally distributed
             *  if (randNumGroup < 0) randNumGroup = 24 + randNumGroup; // format for 24h time and check for negatives
             *                                                          // spawn more when nearing peak hour and scale chance by myManager.diffusionAvatarSpawnRate
             *                                                          //normal distributed chance around rush hour mean
             *
             *
             *
             *  if (UnityEngine.Random.Range(0.0f, 0.5f) < num
             *          && UnityEngine.Random.Range(0.0f, 1.0f) < group.spawnRate //injection control over current group
             *              && UnityEngine.Random.Range(0.0f, 1.0f) < myManager.diffusionAvatarSpawnRate) //injection control overall groups
             *  {
             *
             *      // chance to spawn pre-booked parking space car
             *      if (UnityEngine.Random.Range(0.0f, 1f) < group.reservedSpawnRate)
             *          myManager.SpawnDiffusionAvatar(this, group: group, prebooked: true);
             *      else
             *          myManager.SpawnDiffusionAvatar(this, group: group, prebooked: false);
             *  }
             * }
             */



            //itteration 2
            //check if you need to reset
            //reset if max spawned is reached already and the NumberOfCarsAtPointX is not the max
            //TODO if you just do a normal Z table map and spawn like that you'll solve the problem
            // foreach (GameObject obj in myManager.groups)
            // {

            //     PeakingGroup group = obj.GetComponent<PeakingGroup>();
            //     int numberSpawned = group.numberAlreadySpawned;
            //     int numberOfCarsToSpawn = group.spawnNumber;

            //     double percentageOfCarsAtPointX = GridManagerScript.NormalDistribution(timeOfDay, group.rushHour, group.standartDeviation);
            //     int NumberOfCarsAtPointX = (int)Math.Round(numberOfCarsToSpawn * percentageOfCarsAtPointX);

            //     int carsToBeSpawned = NumberOfCarsAtPointX - numberSpawned;

            //     if ( numberSpawned >= numberOfCarsToSpawn && NumberOfCarsAtPointX < numberSpawned)
            //         group.numberAlreadySpawned = 0;

            //     for (int i = 0; i < carsToBeSpawned; i++)
            //     {
            //         // chance to spawn pre-booked parking space car
            //         if (UnityEngine.Random.Range(0.0f, 1f) < group.reservedSpawnRate)
            //             myManager.SpawnDiffusionAvatar(this, group: group, prebooked: true);
            //         else
            //             myManager.SpawnDiffusionAvatar(this, group: group, prebooked: false);

            //         group.numberAlreadySpawned += 1;
            //     }

            // }


            //3rd itteration
            if (timeOfDay != previousTimeOfDay)
            {
                previousTimeOfDay = timeOfDay;
                foreach (GameObject obj in myManager.groups)
                {
                    PeakingGroup group = obj.GetComponent <PeakingGroup>();
                    if (groupsSpawnBuckets.ContainsKey(group))
                    {
                        int numberOfCarsToSpawn = groupsSpawnBuckets[group][timeOfDay];

                        //get current group spawns
                        int actualCurrentSumForGroup = spawnGroupSums[group];
                        //compensate for frame rate drops
                        //calculate expected sum at current time
                        //e.g. it's 1545 getSumUpUntilTime calculates spawned until 1544
                        //predicted number of current cars at 1544 is 500
                        //actual sum of spawned cars is 490
                        //frameCompensationForGroup is 500 - 490 = 10 (i.e. need to spawn 10 more cars
                        //to compensate for the frame skipping)
                        //that frameCompensation is then added to the number of cars to spawn
                        //each frame compensates for all previous frames
                        int predictedCurrentSum = getSumUpUntilTime(groupsSpawnBuckets[group], timeOfDay); //for one group
                        //calculate compensation
                        int frameCompensationForGroup = (predictedCurrentSum - actualCurrentSumForGroup) > 0?
                                                        (predictedCurrentSum - actualCurrentSumForGroup) : 0;
                        for (int i = 0; i < (numberOfCarsToSpawn + frameCompensationForGroup); i++)
                        {
                            spawnGroupSums[group] += 1;
                            // chance to spawn pre-booked parking space car commented out
                            //if (UnityEngine.Random.Range(0.0f, 1f) < group.reservedSpawnRate)
                            //  myManager.SpawnDiffusionAvatar(this, group: group, prebooked: true);
                            //else
                            myManager.SpawnDiffusionAvatar(this, group: group, prebooked: false);

                            GridManagerScript.numberOfVehicles[timeOfDay] += 1;
                        }
                    }
                }
            }
        }
    }