- Home /
Move object in an arc
Hi.
I'm getting very close to being able to move object in an arc, but I just can't figure out the final piece. Here's the code I have.
I manage to get the object to move to 50 units from the center and then place newPos's around an arc, but then using Vector3.Lerp to move the object to these points makes it go in straight lines rather than following the same arc I'm using to draw them...
BTW in this I'm simply trying to get my object to rotate along an arc on the Z axis based on the Y axis of the camera.
I really all works how it should other than the object doesn't actually travel in arcs.
using UnityEngine;
public class rotateRelative : MonoBehaviour
{
[SerializeField]
Transform m_cameraTrans = null;
[SerializeField]
float m_speed = 10f;
const float RADIUS = 50f;
void Update()
{
float yRot = m_cameraTrans.eulerAngles.y * Mathf.Deg2Rad;
Vector3 newPos = new Vector3(Mathf.Cos(yRot), Mathf.Sin(yRot), 0f) * RADIUS;
transform.position = Vector3.Lerp(transform.position, newPos, Time.deltaTime * m_speed);
}
}
Answer by Cornelis-de-Jager · Jul 09, 2017 at 11:50 PM
I am going to explain two methods:
Method 1: Perfect Arc
So this method assumes that it will always be a perfect half circle arc towards the target location. Meaning if the Target is really far the arc will be huge.
/* Variables */
float counter;
bool endReached;
float speed = 1f;
Vector3 startPos;
void Start () {
counter = 0;
endReached = false;
startPos = transform.position;
}
void Update () {
if (endReached)
return;
// Still firing
Vector3 pos = new Vector3 (
startPos.x,
startPos.y + Mathf.Sin( Mathf.PI * 2 * counter / 360),
startPos.z + Mathf.Sin( Mathf.PI * 2 * counter / 360)
);
// Move the transform
transform.position = Vector3.lerp ( transform.position, pos, 1f);
// Update Counter
counter += speed;
// Break the loop
if (counter >= 180)
endReached = true;
}
Now if you are using collision there is no need to use the endReached variable.
Method 2: Missile Firing
Imagine I am firing missiles up in the air, they then lock-on to a target and head to wards that target. They might miss if the target moves but it all depends on the turning rate of the missile and if I set the target to be lock-on or not.
The only thing is you have to turn your transform in a direction at the start otherwise it will just move in straight line. The bad part is that this can actually miss the target or enter a straight line before the target is reached.
/* Variables */
Transform target;
Vector3 targetPos;
float smooth; // Kind like turn speed
float speed; // Movement speed
void Start () {
targetPos = target.position;
}
void Update () {
// If Lock:
if (isLockon)
targetPos = target.position;
// Rotate in arc
SmoothLookAt (targetPost);
// Move
transform.Translate (transform.forward * speed);
}
void SmoothLookAt(Vector3 target)
{
Vector3 dir = target - transform.position;
Quaternion targetRotation = Quaternion.LookRotation(dir);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * smooth);
}
Hope this helped.
That's really awesome. I haven't got time to test right now, though I see you are still using like me
transform.position = Vector3.lerp ( transform.position, pos, 1f);
which moves the object in straight lines right? Also, there's a slight misunderstanding of exactly what I am trying to achieve. The size of the circle around which the object makes a arc motion doesn't change.
I've mocked up an image to explain. Imagine this image is POV. In position A is an object. When I rotate my head to the left, the object moves from position A progressively to position B. And when I rotate my head to the right it moves to position C.
I have managed to do this with my code. The only thing wrong is that, when I do move my head to the right, the object moves from it's current position to position B in a straight line rather than along the arc (and BTW the arc radius is set by RADIUS in my code).
Answer by Jwizard93 · Jul 09, 2017 at 10:05 PM
So using Lerp to translate is always going to move in a straight line between the two input vectors. I believe using it in this manner would require lots of vectors to approximate an arc that would appear smooth to the player.
Let me suggest a different method.
When an object has a child and that child is located at some offset, then that offset is like a radius of rotation. You rotate the parent and the child moves in a circle around the parent.
So what you can do is have your object that is meant to travel in an arc be a child of another GameObject. Rotate the parent and the child moves in the arc. Each frame, after rotating the parent, you can set the child's rotation to be whatever you want and it won't affect the parent or the translation. So if you don't want the moving object to appear to rotate at all you can, for instance, store it's rotation before the movement occurs. And each frame, after updating the rotation of the parent, set the rotation of the child to be its original rotation again.
Does that make sense / suit your needs? Do you know how to do this if it does?
I might add that non-circular motion is going to be a bit more tricky. You would have to translate and rotate the parent object, but some study of ellipses or other mathematical curved shapes and paths should lead to a suitable solution.
I once studied the geometry involved and coded up the proper translation.. it worked and I thought I was cool... but the method I mentioned above is just so much neater and easier.
Thanks for the answer. This is in fact the first method I tried. I had the gameObject attached to a pivot, and I'd rotate the pivot. The issue I had with this is that I found it impossible to add any delay to the movement. The code I was using was: transform.localEulerAngles = Vector3.Lerp(transform.localEulerAngles, new Vector3(0, 0, rot), 1f);
Where rot
is the Y rotation of the camera. This script would be attached to the pivot. It would definitely work, but as soon as I want to add delay to the object, for example doing transform.localEulerAngles = Vector3.Lerp(transform.localEulerAngles, new Vector3(0, 0, rot), 0.5f);
Everything would break.
Now with this new method, I can add delay easily and it works, though now the object moves in a straight line to another point on the circle!
I've also tried using Quaternion: transform.rotation = Quaternion.Slerp(transform.rotation, playerCamera.transform.rotation, Time.time * 0.001f);
When I put this on the pivot, it works, so the object moves to the rotation of the camera. And with a delay! But... It moves in all directions and I can figure out how to clamp it to only move along one axis.
Answer by Contato · Aug 17, 2018 at 10:43 PM
so, how did this end up?
what i am trying to achievie is making Vector3.Slerp to work clockwise and counter-clockwise when i choose to