private void EvaluateTargets() { //Heuristic -- target the lowest landing time as long as it is catchable if (analyzedElectrons.Count == 0) { return; } //Update catchability based on the cached data from the last analysis foreach (var pair in analyzedElectrons) { ProjectileTrajectoryData data = pair.Value; data.catchable = IsCatchable(data, localT.localPosition); //analyzedElectrons[pair.Key] = data; } var minimalCatchable = analyzedElectrons.Aggregate((minItem, nextItem) => //nextItem.Value.catchable && IsCatchable(nextItem.Value, localT.localPosition) && (nextItem.Value.landingTimestamp < minItem.Value.landingTimestamp) ? nextItem : minItem); movementTargetObj = minimalCatchable.Key.gameObject; //TODO: this can be null when the electron is being destroyed!? SetMovementPoint(minimalCatchable.Value.landingLocation); }
private bool IsCatchable(ProjectileTrajectoryData data, Vector3 currentCatcherPosition) { float distance = Vector3.Distance(data.landingLocation, currentCatcherPosition); float catchTimestamp = (distance / moveSpeed) + Time.time; //Check that the electron is reachable before it falls, and that it will fall within level bounds return(catchTimestamp < data.landingTimestamp && data.landingLocation.x > electronLauncher.electronSpawn.position.x && data.landingLocation.x < batteryDockPos.x); }
private ProjectileTrajectoryData AnalyzeTarget(Electron proj, Vector3 currentCatcherPosition) { //Calculate an electron's landing time and position based on its velocity //Store this in ProjectileTrajectoryData so we don't have to recalculate anything until a collision occurs float timeToGround; if (proj.rb.velocity.y > 0) { float timeToRise = proj.rb.velocity.y / -Physics.gravity.y; float maxHeight = proj.transform.position.y + proj.rb.velocity.y * timeToRise - (0.5f * -Physics.gravity.y * Mathf.Pow(timeToRise, 2)); float timeToFall = Mathf.Sqrt((2f * (maxHeight - landingPlaneHeight)) / -Physics.gravity.y); timeToGround = timeToRise + timeToFall; //Debug.Log("Upward projectile analysis for " + proj.gameObject.name + ": timeToGround = " + timeToGround + //", maxHeight = " + maxHeight + ", timeToFall = " + timeToFall); } else { timeToGround = (-proj.rb.velocity.y - Mathf.Sqrt(Mathf.Abs(Mathf.Pow(proj.rb.velocity.y, 2) - (2f * Physics.gravity.y * -(landingPlaneHeight - proj.transform.position.y))))) / Physics.gravity.y; //Debug.Log("Falling projectile analysis for " + proj.gameObject.name + ": timeToGround = " + timeToGround + //", y0 = " + proj.transform.position.y + ", Vy0 = " + proj.rb.velocity.y); } Vector3 landingLocation = new Vector3( proj.rb.velocity.x * timeToGround + proj.rb.position.x, landingPlaneHeight, proj.rb.velocity.z * timeToGround + proj.rb.position.z); float distance = Vector3.Distance(landingLocation, currentCatcherPosition); float timeToCatch = distance / moveSpeed; ProjectileTrajectoryData projectileData = new ProjectileTrajectoryData(); projectileData.landingTimestamp = timeToGround + Time.time; projectileData.landingLocation = landingLocation; projectileData.catchable = IsCatchable(projectileData, currentCatcherPosition); return(projectileData); }
//After each electron spawn or bounce, calculate any unknown/changed trajectories //Then evaluate them all to choose which electron to catch private void AnalyzeElectrons() { Vector3 adjustedCatchPosition = localT.localPosition; //adjustedCatchPosition.x += halfCollectionWidth; foreach (Electron electron in unanalyzedElectrons) { ProjectileTrajectoryData projData = AnalyzeTarget(electron, adjustedCatchPosition); if (analyzedElectrons.ContainsKey(electron)) { analyzedElectrons[electron] = projData; } else { analyzedElectrons.Add(electron, projData); } } unanalyzedElectrons.Clear(); EvaluateTargets(); }