- Home /
Moving an object along a circular path
I am trying to make an object follow a path made up of nodes like the image below.
There have been many others questions similar to this, but my problem is a bit different. I can make an object move from one point to the next, then the next, and so on, but where things become tricky is the turns. When going from one node to the next, I want the object to smoothly turn to face the forward direction of the next node (like between nodes (1) and (2) above or (3) and (4)). The object should always face the direction it is moving.
If possible, I would also like this to work if the nodes were moving during gameplay (which I can also already do).
EDIT: There were some misunderstandings with my question, so I will elaborate more here instead of buried in a reply.
That green path was drawn in photoshop. All I have in Unity in terms of positions are those blue nodes. Currently, I can make a path that looks like this by moving straight from one point to the next:
What I want to achieve is the circular movements from node (1) to node (2) and node (3) to node (4). I also want the forward direction of each node to determine which way the object going along the path (imagine a spaceship, I guess) should be turning to face.
The game is also 3d, so the path could go in all directions, on any axis, and aren't locked to a plane. The flat pictures were for simplicity. Preferably, I would like to not use physics nor the navmesh system, but rather manipulating transforms. I also can't bake an animation since the path can change if one node is moving back and forth or it there is a split path.
One idea I did have is that I could make the object move forward relative to itself, and then turn towards the next node as it's moving, but I am unsure of how I would calculate that rotation speed so that it goes through the next node and not past it.
EDIT 2: Here is my code currently. The NodeInfo class is a script on every node that I'm using for things beyond the scope of this question, like changing speeds and looping to different parts of the path. The turning is working fine, but the path is still just linear. I've tried many things like using forces, lerping, calculating new in-between points, a bezier curve asset from the asset store, and now using percentages.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveF : MonoBehaviour {
public NodeInfo[] nodes;
private int currentNode = 1;
private int lastNode = 0;
private float perc = 0;
void Update () {
perc += nodes[currentNode].speed * Time.deltaTime;
transform.position = Vector3.Lerp (nodes[lastNode].transform.position, nodes[currentNode].transform.position, perc);
transform.rotation = Quaternion.Lerp (nodes[lastNode].transform.rotation, nodes[currentNode].transform.rotation, perc);
if (Vector3.Distance(transform.position, nodes[currentNode].transform.position) <= 0.1f && Quaternion.Angle(transform.rotation, nodes[currentNode].transform.rotation) <= 1f)
{
lastNode = currentNode;
if (nodes[currentNode].nodeType == NodeInfo.NodeType.normal)
{
currentNode++;
if (currentNode >= nodes.Length)
{
enabled = false;
}
}
else if (nodes[currentNode].nodeType == NodeInfo.NodeType.loop)
{
currentNode = nodes[currentNode].loopTo;
}
perc = 0;
}
}
}
EDIT 3: Here is a video of my progress so far with this and should give a better idea of what I want to achieve: https://www.youtube.com/watch?v=cezdf_hCieE&feature=youtu.be The plan is that enemies will come in waves like a combination of Galaga or Space Invaders as you move through an environment going from point a to point b. It works so far but the turns are very snappy because there is no roundedness in the turns.
Post your code first, what did you try? The question must be more precise than "give me a ready script".
Answer by CyberChroma · Sep 06, 2018 at 04:52 PM
I was finally able to get this to work by manipulating the cosine law. For anyone that comes across this, I will paste my working code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveF : MonoBehaviour {
public NodeInfo[] nodes;
private int currentNode = 1;
private int lastNode = 0;
private float perc = 0;
private Vector3 midPoint;
private Vector3 m1;
private Vector3 m2;
void Update () {
perc += (1 / Vector3.Distance(nodes[lastNode].transform.position, nodes[currentNode].transform.position)) * nodes[currentNode].speed * Time.deltaTime;
if (Vector3.Angle(nodes[lastNode].transform.forward, nodes[currentNode].transform.position - nodes[lastNode].transform.position) > 0)
{
midPoint = nodes[lastNode].transform.position + nodes[lastNode].transform.forward * Vector3.Distance(nodes[lastNode].transform.position, nodes[currentNode].transform.position) / Mathf.Sqrt(2 * (1 - Mathf.Cos((180 - 2 * Vector3.Angle(nodes[lastNode].transform.forward, nodes[currentNode].transform.position - nodes[lastNode].transform.position)) * Mathf.Deg2Rad)));
}
else
{
midPoint = (nodes[lastNode].transform.position + nodes[currentNode].transform.position) / 2;
}
m1 = Vector3.Lerp(nodes[lastNode].transform.position, midPoint, perc);
m2 = Vector3.Lerp(midPoint, nodes[currentNode].transform.position, perc);
transform.position = Vector3.Lerp (m1, m2, perc);
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Slerp(nodes[lastNode].transform.rotation, nodes[currentNode].transform.rotation, perc), 0.5f);
if (Vector3.Distance(transform.position, nodes[currentNode].transform.position) <= 0.1f && Quaternion.Angle(transform.rotation, nodes[currentNode].transform.rotation) <= 1f)
{
lastNode = currentNode;
if (nodes[currentNode].nodeType == NodeInfo.NodeType.normal)
{
currentNode++;
if (currentNode >= nodes.Length)
{
enabled = false;
}
}
else if (nodes[currentNode].nodeType == NodeInfo.NodeType.loop)
{
currentNode = nodes[currentNode].loopTo;
}
perc = 0;
}
}
}
Answer by eses · Sep 04, 2018 at 01:38 PM
@Superspeedy
Your question is bit mixed; heading is "Making an object follow a path" but you say you already have this working.
By "galiga style game" do you mean classic game called "Galaga" perhaps?
Then you say " but where things become tricky is the turns." - so the turning is the problem?
What @tormentoarmagedoom mentioned could work - players don't know if objects are moving on invisible plane or not...
Maybe look into using some spline asset from asset store, or some tweening kit? Some of those have path / spline support.
Facing towards path next point problem - Get current and next point or point on path little bit forward in time, then calculate a direction vector from these. Use this as your transform forward for the moving object.
Yes, I meant Galaga. I'll update the question to give more detail as to what I mean.
Answer by tormentoarmagedoom · Sep 04, 2018 at 12:47 PM
Good day.
Use the nav mesh system, and configure the angular acceleration of the nav mesh agent to a low value.
Bye.
As far as I know, a nav mesh can only be made on surfaces. I need something that will work in the air. I am making a galiga style game. The game area consisting of the player, camera, boundaries, ect. will be moving along this path to be traversing an environment.
Your answer
Follow this Question
Related Questions
Movement and animation 1 Answer
Prefab Position 2 Answers
Object slows down when moving to a NavPoint, speed is not constant 1 Answer
help with not working AI system 2 Answers
How to lock an int as a playerPref? 1 Answer