- Home /
Throwing Object with acceleration equation/script?
I would like to script the animated movement of an object between two positions. So there is the start vector and the end vector. The start and end positions are important, and the trajectory should look something roughly like in the image below, but it shouldn't be too precise.
Because the end position should be a fixed one, I can't really use rigidbody physics. I tried using Vector3.Slerp and Vector3.Lerp, but I couldn't manage to get an acceleration at the end of the trajectory curve.
Could you please give me a few hints, as I forgot the math behind these things?
Thanks a lot!
Answer by duck · Nov 26, 2009 at 04:19 PM
You're on the right track with Vector3.Lerp (but not Slerp - that's more for interpolating directional vectors rather than positions).
What you need is to just add a curve-based value to the object's height in addition to the straight-line interpolation that Lerp gives you. You can get a nice curved value range which goes from 0 to 1 and back to 0, by feeding a range from zero to PI into the Mathf.Sin function.
Here's a small c# example script which demonstrates:
using UnityEngine; using System.Collections;
public class Trajectory : MonoBehaviour {
Vector3 startPos = new Vector3(0, 0, 0);
Vector3 endPos = new Vector3(0, 0, 10);
float trajectoryHeight = 5;
// Update is called once per frame
void Update () {
// calculate current time within our lerping time range
float cTime = Time.time * 0.2f;
// calculate straight-line lerp position:
Vector3 currentPos = Vector3.Lerp(startPos, endPos, cTime);
// add a value to Y, using Sine to give a curved trajectory in the Y direction
currentPos.y += trajectoryHeight * Mathf.Sin(Mathf.Clamp01(cTime) * Mathf.PI);
// finally assign the computed position to our gameObject:
transform.position = currentPos;
}
}
This solution works great. Thank you. I understand Time.time might be not good. We can change it to an incrementor float variable as shown in the code below:
using UnityEngine;
using System.Collections;
public class $$anonymous$$ove : $$anonymous$$onoBehaviour
{
Vector3 startPos = new Vector3(0, 0, 0);
Vector3 endPos = new Vector3(0, 0, 10);
float height = 4f;
bool startThrow = false;
float incrementor = 0;
// Update is called once per frame
void Update()
{
if (startThrow)
{
incrementor += 0.04f;
Vector3 currentPos = Vector3.Lerp(startPos, endPos, incrementor);
currentPos.y += height * $$anonymous$$athf.Sin($$anonymous$$athf.Clamp01(incrementor) * $$anonymous$$athf.PI);
transform.position = currentPos;
}
if (transform.position == endPos)
{
startThrow = false;
incrementor = 0;
Vector3 tempPos = startPos;
startPos = transform.position;
endPos = tempPos;
}
if (Input.Get$$anonymous$$ouseButtonDown(0))
{
startThrow = true;
}
}
}
It works great just make this change: float cTime; .....
void Update() { cTime += TIme.deltaTime * 0.2f;
....
Time.time worked better for me. Time.deltaTime really messed up the behavior
Answer by BogdanDude · Nov 26, 2009 at 05:19 PM
Thanks a lot for your quick reply. In my case your code didn't really work. Using Time.time isn't the best idea (it would probably work only when you first hit play in the editor, as it accumulates)
Here's the code I used, which does pretty much what I wanted:
Vector3 targetPosition = target.position;
float timerThrow = (object.position - targetPosition).magnitude;
float cTime = timerThrow;
Vector3 startPos = object.position;
while ((object.position - targetPosition).sqrMagnitude > 0.01F)
{
cTime -= 0.4F;
object.position = Vector3.Slerp(targetPosition, startPos, cTime / timerThrow);
yield return 0;
}
Because I added the distance between the 2 points in the equation (the magnitude), the animation has the same speed regardless of the distance between the 2 points. If you know any good way to optimize the above code, to run even faster, please let me know.
Yes, of course - Time.time was used an example, in the absence of knowing exactly when you want the animation to occur within your particular project. Sorry if I didn't make that clear. Other than that, it does exactly what you wanted though, right?
A couple of notes about your script:
I'm interested in your use of 'Slerp' here - I think this will mean that your objects will be moved spherically around the world origin, which might cause problems if your start & end positions aren't evenly positioned either side of it.
Also, your 'while' loop is going to run at the same speed as Update() is called, which will vary across different computers - so rather than subtracting a fixed amount from 'cTime', you should be using Time.deltaTime to make sure that the movement completes at the same speed, irrespective of the frame rate.
As for optimising the code, I would say that it needs no optimisation at all. This code is pretty optimal as-is.
Yup, I forgot to take Time.deltaTime into consideration. I'll replace cTime -= 0.4F; with cTime -= Time.deltaTime * Constant; You were right about the Slerp too :) It only makes a round curve around the world origin (I tested it around that point). I'll use your approach. Thanks again!