This ended up being simpler than I expected. Here is the process I followed so you can follow a similar process in the future:
I started writing the basic physics 101 equations with some values in 2d space because it's easier to think about:
a = (0, -9.8) // this is just gravity down
v = v0 + a*t // velocity is starting velocity + acceleration times time
p = p0 + v0*t + (1/2)*a*t^2 // the position
and then, I assumed the target position would be relative to the start position, so p0 drops out. Rearraging to find v0, I got:
v0 = p - .5*a*t^2 / t
At this point, there are two things to solve for, v0, and t. This makes sense, you can throw a baseball right at your friend or way up high and still have it land at your friends location, even though it will take longer.
So, I took this and created the following two classes that have the desired effect.
public class Jumper : MonoBehaviour
{
private Vector3 _velocity = Vector3.zero;
public Vector3 _gravity = 9.8f * Vector3.down;
public void Update()
{
_velocity += Time.deltaTime * _gravity;
transform.position += Time.deltaTime * _velocity;
}
public void SetVelocityToJump(GameObject goToJumpTo, float timeToJump)
{
var toTarget = goToJumpTo.transform.position - this.transform.position;
_velocity = (toTarget - (Mathf.Pow(timeToJump, 2) * 0.5f * _gravity)) / timeToJump;
}
}
public class JumpTarget : MonoBehaviour
{
public Jumper Jumper;
public float TimeToJump;
public void Start()
{
if (Jumper != null) Jumper.SetVelocityToJump(gameObject, TimeToJump);
}
}
Edit to address comment
If you want to keep the same position in the jump as the target moves, then you are no longer talking about a step-wise physics solution, at least not while the jump is happening. It is easily achieved, however, with a coroutine to handle the jump.
using UnityEngine;
using System.Collections;
public class Jumper : MonoBehaviour
{
public Vector3 _gravity = 9.8f * Vector3.down;
public void SetVelocityToJump(GameObject goToJumpTo, float timeToJump)
{
StartCoroutine(jumpAndFollow(goToJumpTo, timeToJump));
}
private IEnumerator jumpAndFollow(GameObject goToJumpTo, float timeToJump)
{
var startPosition = transform.position;
var targetTransform = goToJumpTo.transform;
var lastTargetPosition = targetTransform.position;
var initialVelocity = getInitialVelocity(lastTargetPosition - startPosition, timeToJump);
var progress = 0f;
while (progress < timeToJump)
{
progress += Time.deltaTime;
if (targetTransform.position != lastTargetPosition)
{
lastTargetPosition = targetTransform.position;
initialVelocity = getInitialVelocity(lastTargetPosition - startPosition, timeToJump);
}
transform.position = startPosition + (progress * initialVelocity) + (0.5f * Mathf.Pow(progress, 2) * _gravity);
yield return null;
}
}
private Vector3 getInitialVelocity(Vector3 toTarget, float timeToJump)
{
return (toTarget - (0.5f * Mathf.Pow(timeToJump, 2) * _gravity)) / timeToJump;
}
}
GameObject
but you want proper gravity as in your current code? If not, please explain and we can rollback the changes or edit accordingly. \$\endgroup\$