Slerp, lerp or something else?

So I’m trying to achieve the same effect that launching plants achieve in Plants versus Zombies. Where an object targets a moving enemy…get’s tossed in the air and eventually hits it’s target.

The hieght of the arc is dictated by the distance the object needs to travel to get to it’s target. At first I thought this was a slerp, but perhaps this is something else.

here’s a video showcasing the type of dynamic arch I’m trying to achieve.

gameplay video

My limited experience of a slerp has the speed the object travels varied to have it hit the target at the desired time. In the video, the speed is constant, and the arc of the object is adjusted to insure that the object hit’s the target at the desired time.

It wouldn’t take much to simulate the throw with some simple physics calculations, but for what is done in the video, I think a simple Sin() function will do the job. It is not only that the object is flying in an arc, but that the movement up/down under the influence of gravity need to look right. Here is a sample script. I’ve calculated the height as half of the distance traveled. You can adjust this for the specific feel of your throws. In looking at the video, it seemed that objects had a speed rather than a time. That is an object thrown from a further distance took more time. It was hard for me to tell. I’ve implement the code with speed, but you can just set ‘time’ to a fixed value if you want the object to travel in a fixed amount of time no matter what the distance. To test:

  • Create a new scene
  • Create a sphere at the origin
  • Scale the sphere down (0.4, 0.4 0,4)
  • Attach the following script
  • While running the app, click the left mouse button

var speed = 4.0;
private var lobbing = false;

function Lob(dest : Vector3) {
	lobbing = true;
	var start = transform.position;
	var dist = (dest - transform.position).magnitude;
	var height = 0.5 * dist;
	var timer = 0.0;
	var time = dist / speed;
	var fraction = 0.0;
	
	do {
		fraction = timer / time;
		var pos = Vector3.Lerp(start, dest,  fraction);
		pos.y += Mathf.Sin(Mathf.PI * fraction) * height;
		transform.position = pos;
		timer += Time.deltaTime;
		yield;
	} while (fraction < 1.0);
	
	transform.position = dest;
	lobbing = false;
}

function Update () {
	if (!lobbing && Input.GetMouseButtonDown(0)) {
		var pos = Input.mousePosition;
		pos.z = 10;
		pos = Camera.main.ScreenToWorldPoint(pos);
		Lob(pos);
	}
}

I’ve done something similar with making a character walk to a way point but walking in a curve to get there.

First you set up a vector 3 to give a direction from the spawn of the projectile to the enemy;

Vector3 vDir = (enemy.transform.position - spawn.transform.position).normalized;

Then give the projectile speed;

float fMovementDelta = (speed * Time.deltaTime) * transform.root.localScale.x;

Now tell it to move;

projectile.transform.position += projectile.transform.forward * fMovementDelta;
            Vector3 vLocalPosition = projectile.transform.localPosition;
            vLocalPosition.y = 0;
            projectile.transform.localPosition = vLocalPosition;

Now the part you want, tell it to always have one of its axis facing the enemy;

Quaternion qTo = Quaternion.LookRotation(vDir, transform.up);

Now tell it to curve using Quaternion.Lerp;

projectile.rotation = Quaterion.Lerp(projectile.transform, qTo, (speed*4)*Time.deltaTime);

Im sorry this is in C# but that’s all i know in this depth, hopefully if you really cant use this someone can convert it for you.
If there is any part of this you don’t understand leave a comment and i will help as soon as i can :slight_smile:

Maybe you would be better off with moving your objects along a bezier curve?

With one control point (position of which you can make slightly random and dependant upon the distance between shooter and the target) you can achieve a similar effect.