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 }
// Find a trajectory for which the trajectory's y is at least as high as any // of the vertices remaining in _edgesOnPrincipalPlane. private float GetTimeToTargetOnIntersection( PrincipalSpace3D principalSpace3D, PrincipalTrajectory principalTrajectory, Vector2 principalTargetPosition) { for (int index = 0; index < _edgesOnPrincipalPlane.vertexCount; index += 2) { if (_edgeClassifier.CrossesXBound( _edgesOnPrincipalPlane.vertices[index], _edgesOnPrincipalPlane.vertices[index + 1])) { return 0; } } float timeToTarget = 0.0f; for (int index = 0; index < _edgesOnPrincipalPlane.vertexCount; index += 2) { Vector2 vertex = _edgesOnPrincipalPlane.vertices[index]; if (principalTrajectory.PositionYAtX(vertex.x) < vertex.y) { /* Debug.DrawLine(principalSpace3D.p0, principalSpace3D.p0 + principalSpace3D.xAxis * vertex.x + principalSpace3D.yAxis * vertex.y, Color.grey); */ timeToTarget = PrincipalTimePlanners.GetTimeToTargetRGivenIntermediatePositionQ( principalTrajectory, principalTargetPosition, vertex); principalTrajectory.v0 = principalTrajectory.GetInitialVelocityGivenRelativeTargetAndTime( principalTargetPosition, timeToTarget); } } return timeToTarget; }