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; } } } } }
public void removeSpawnBucket(PeakingGroup g) { this.groupsSpawnBuckets.Remove(g); this.spawnGroupSums.Remove(g); }
public void addSpawnBucket(PeakingGroup g, Dictionary <double, int> carSpawnerBuckets) { this.groupsSpawnBuckets[g] = carSpawnerBuckets; spawnGroupSums[g] = 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; } }
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; } } } } } }