public override bool PlanTimeToTarget(Projectile3D projectile3D, Vector3 initialPosition, Vector3 targetPosition, ref float timeToTarget) { if (timeToTarget > 0) return false; PrincipalProjectile principalProjectile; PrincipalSpace3D principalSpace3D = PrincipalSpace3D.Create(projectile3D, initialPosition, targetPosition, out principalProjectile); Vector2 principalTargetPosition = principalSpace3D.ToPrincipalPosition(targetPosition); float slope = principalSpace3D.ToPrincipalSlope(targetSlope); if (!float.IsNaN(slope)) { float newTimeToTarget = PrincipalTimePlanners.GetTimeToTargetRGivenTargetSlopeA( principalProjectile, principalTargetPosition, slope); if (newTimeToTarget > 0) { timeToTarget = newTimeToTarget; return true; } } return false; }
public override bool PlanTimeToTarget(Projectile3D projectile3D, Vector3 initialPosition, Vector3 targetPosition, ref float timeToTarget) { // Don't override the timeToTarget if there's already another valid plan. if (timeToTarget > 0) return false; PrincipalProjectile principalProjectile; PrincipalSpace3D principalSpace3D = PrincipalSpace3D.Create(projectile3D, initialPosition, targetPosition, out principalProjectile); Vector2 principalTargetPosition = principalSpace3D.ToPrincipalPosition(targetPosition); float newTimeToTarget = PrincipalTimePlanners.GetTimeToTargetRGivenInitialSpeedS( principalProjectile, principalTargetPosition, initialSpeed, highArc); if (newTimeToTarget > 0) { timeToTarget = newTimeToTarget; return true; } return false; }
public override bool PlanTimeToTarget(Projectile3D projectile3D, Vector3 initialPosition, Vector3 targetPosition, ref float timeToTarget) { // Allow this planner to only modify an already existing plan, not create a new one. if (timeToTarget <= 0) return false; // Convert the problem to principal space PrincipalProjectile principalProjectile; PrincipalSpace3D principalSpace3D = PrincipalSpace3D.Create(projectile3D, initialPosition, targetPosition, out principalProjectile); Vector2 principalTargetPosition = principalSpace3D.ToPrincipalPosition(targetPosition); PrincipalTrajectory principalTrajectory = new PrincipalTrajectory(principalProjectile); principalTrajectory.v0 = principalTrajectory.GetInitialVelocityGivenRelativeTargetAndTime( principalTargetPosition, timeToTarget); // notify helper classes/structs of the trajectory to test _trajectoryOverGameObjectHelper.SetupTrajectory(principalSpace3D, principalTrajectory, principalTargetPosition, marginDistance); // (Re-)check all the gameobjects until no further intersections are detected, or until // an intersecting gameobject is found that can't have a trajectory passing over it. int lastIntersectingGameObjectIndex = -1; //bool foundAnotherIntersection; //do { //foundAnotherIntersection = false; for (int index = 0; index < obstacles.Length; ++index) { if (index != lastIntersectingGameObjectIndex) { float foundTimeToTarget = _trajectoryOverGameObjectHelper.GetTimeToTargetOverGameObject(obstacles[index]); if (foundTimeToTarget >= 0) // found intersection { //foundAnotherIntersection = true; lastIntersectingGameObjectIndex = index; timeToTarget = foundTimeToTarget; if (timeToTarget == 0) { return true; // trajectory over the object is impossible, so give up } // use the new initial velocity in the tested trajecory principalTrajectory.v0 = principalTrajectory.GetInitialVelocityGivenRelativeTargetAndTime( principalTargetPosition, timeToTarget); // notify helper classes/structs of the new trajectory to test _trajectoryOverGameObjectHelper.SetupTrajectory(principalSpace3D, principalTrajectory, principalTargetPosition, marginDistance); } } } } //while (foundAnotherIntersection); return lastIntersectingGameObjectIndex >= 0; // true iff the plan changed }
// See the base class for an explanation of the parameters. public override bool PlanTimeToTarget(Projectile3D projectile3D, Vector3 initialPosition, Vector3 targetPosition, ref float timeToTarget) { // Don't override the timeToTarget if there's already another valid plan. if (timeToTarget > 0) return false; timeToTarget = this.timeToTarget; return true; }
// projectile in principal space // Create a principalSpace3D and PrincipalTrajectory from a given Projectile3D, // the launch position and another point on the plane (e.g. a 3d target). // Implements Equation 10 from the paper. public static PrincipalSpace3D Create( Projectile3D projectile3D, // projectile in world space Vector3 worldP0, // the launch position Vector3 worldP1, // any other position on the principal plane out PrincipalProjectile principalProjectile) { principalProjectile = new PrincipalProjectile( projectile3D.k, projectile3D.vInfinity.magnitude); Vector3 yAxis = projectile3D.vInfinity / -principalProjectile.vInfinity; Vector3 deltaPos = worldP1 - worldP0; Vector3 xAxis = deltaPos - Vector3.Dot(yAxis, deltaPos) * yAxis; float squaredXScale = xAxis.sqrMagnitude; if (squaredXScale == 0) { xAxis = Misc.GetAnyVector3PerpendicularTo(yAxis); squaredXScale = xAxis.sqrMagnitude; } xAxis /= Mathf.Sqrt(squaredXScale); return new PrincipalSpace3D(worldP0, xAxis, yAxis); }
// Call all planners in order and return the flightTime if at least one planner // found a solution. The return value is only true if the last planner that found a // plan had mayLaunch = true. private static bool RunPlanners(ICollection <TrajectoryPlannerBase> planners, ProjectileKinematics projectileKinematics, Vector3 predictedLauncherPosition, Vector3 predictedTargetPosition, out float flightTime) { Projectile3D projectile3D = projectileKinematics.Projectile3D; flightTime = 0; bool mayLaunch = false; foreach (TrajectoryPlannerBase planner in planners) { if (planner.PlanTimeToTarget(projectile3D, predictedLauncherPosition, predictedTargetPosition, ref flightTime)) { mayLaunch = planner.mayLaunch; } } return(mayLaunch); }
// Based on the incoming positions, velocities and timing information, this function // uses dead reckoning to work out the TrajectoryXXXPlanner inputs to plan plan the // next projectile's trajectory with. The planners are called from lo to high // PlanNumber. If any (future) plan is available, it returns the initial velocity for // that plan. Otherwise, it returns Vector3.Zero. Furthermore, if a future plan is // found AND it allows launching AND the target is within reach AND // minimumTimeToNextLaunch <= 0, then shouldLaunch = true. public static Vector3 UpdatePlan(ICollection <TrajectoryPlannerBase> planners, ProjectileKinematics projectileKinematics, Vector3 launcherPosition, Vector3 launcherVelocity, Vector3 targetPosition, Vector3 targetVelocity, float minimumTimeToNextLaunch, ref float lastFlightTime, out bool shouldLaunch) { // Work out where the launcher and the target are most likely to be when // minimumTimeToNextLaunch becomes zero again. minimumTimeToNextLaunch = Mathf.Max(0.0f, minimumTimeToNextLaunch); float timeToTarget = minimumTimeToNextLaunch + lastFlightTime; Vector3 predictedLauncherPosition = launcherPosition + launcherVelocity * minimumTimeToNextLaunch; Vector3 predictedTargetPosition = targetPosition + targetVelocity * timeToTarget; // Run the planners bool mayLaunch = RunPlanners(planners, projectileKinematics, predictedLauncherPosition, predictedTargetPosition, out lastFlightTime); // Calculate the projectile spawn velocity if a flight time estimate is available Vector3 projectileVelocity = Vector3.zero; if (lastFlightTime > 0) { Projectile3D projectile3D = projectileKinematics.Projectile3D; projectileVelocity = projectile3D.GetInitialVelocityGivenRelativeTargetAndTime( predictedTargetPosition - predictedLauncherPosition, lastFlightTime); } // Set shouldLaunch to true iff the planners presented a plan and // the time is right. shouldLaunch = mayLaunch && minimumTimeToNextLaunch <= 0; return(projectileVelocity); }
// Create a principalSpace3D and PrincipalTrajectory from a given Projectile3D, // the launch position and another point on the plane (e.g. a 3d target). // Implements Equation 10 from the paper. public static PrincipalSpace3D Create( Projectile3D projectile3D, // projectile in world space Vector3 worldP0, // the launch position Vector3 worldP1, // any other position on the principal plane out PrincipalProjectile principalProjectile) // projectile in principal space { principalProjectile = new PrincipalProjectile( projectile3D.k, projectile3D.vInfinity.magnitude); Vector3 yAxis = projectile3D.vInfinity / -principalProjectile.vInfinity; Vector3 deltaPos = worldP1 - worldP0; Vector3 xAxis = deltaPos - Vector3.Dot(yAxis, deltaPos) * yAxis; float squaredXScale = xAxis.sqrMagnitude; if (squaredXScale == 0) { xAxis = Misc.GetAnyVector3PerpendicularTo(yAxis); squaredXScale = xAxis.sqrMagnitude; } xAxis /= Mathf.Sqrt(squaredXScale); return new PrincipalSpace3D(worldP0, xAxis, yAxis); }
public Projectile3D(Projectile3D projectile3D) { this.k = projectile3D.k; this.vInfinity = projectile3D.vInfinity; }
public Trajectory3D(Projectile3D projectile3D, Vector3 p0, Vector3 v0) : base(projectile3D) { this.p0 = p0; this.v0 = v0; }
public Trajectory3D(Projectile3D projectile3D) : base(projectile3D) { }
// Plan a trajectory in terms of flight time from initialPosition and targetPosition // using the settings in projectile3D. It's the responsibility of each implementated // subclass to decide whether or not to override provided timeToTarget, making it // possible to use the same interface for simple planners, backup planning and plan // modifiers. The function returns true if it modified the timeToTarget. To convert // the (new) timeToTarget to a 3D initial velocity use the projectile3D's // GetInitialVelocityGivenRelativeTargetAndTime() function. public abstract bool PlanTimeToTarget(Projectile3D projectile3D, Vector3 initialPosition, Vector3 targetPosition, ref float timeToTarget);