I’ve had a look around the forums and couldn’t find much on the subject so please excuse me if I missed a forum post which previously addressed this question.
What I’m wondering is if there is a way to create a track in unity which and object which follow.
I.e. I am creating a city scene, In the background there are cars on the roads. Would it be possible to draw a curve or something similar which the car models will automatically follow as opposed to creating key-framed animation for all of the cars on an individual basis?
Make an Empty Game object and name it like: “WaypointsCar1” then inside the empy game object
order your other empty game objects like “Waypoint01, Waypoint02”
Add the WaypointCar1 to the Waypoints Root
Add the car to the Target
@script ExecuteInEditMode
var target:Transform;
var waypointsRoot:Transform;
var moveSpeed:float = 10.0;
var rotationSpeed:float = -1.0;
var isLockHorizontal:boolean = false;
var isLookAtRoot:boolean = false;
private var lineColor:Color = new Color(0.6, 0.7, 1.0, 0.5);
private var cubeColor:Color = new Color(0.8, 0.8, 1.0, 0.8);
private var cubeSize:float = 3.0;
private var way:WaypointMover_point[];
private var uIDs:Hashtable = new Hashtable();
private var initialized:boolean = false;
private var nextIndex:int = 0;
class WaypointMover_point extends System.IComparable {
var name:String;
var point:Transform;
function WaypointMover_point(pos_:Transform, name_:String) {
name = name_;
point = pos_;
}
function CompareTo(obj:Object):int {
var other:WaypointMover_point = obj as WaypointMover_point;
return this.name.CompareTo(other.name);
}
}
function Start() {
if (waypointsRoot) {
way = getWaypoints(waypointsRoot);
waypointsRoot.gameObject.SetActiveRecursively(false);
}
}
function Update() {
if (Application.isPlaying target way) {
if (way.length > 0) {
if (!initialized) {
target.position = way[0].point.position;
initialized = true;
}
doMove();
}
}
}
private var moveDir:Vector3;
private var tempDir:Vector3;
private function doMove():void {
if (Vector3.Distance(way[nextIndex].point.position, target.position) <= moveSpeed *Time.deltaTime) {
nextIndex++;
if (nextIndex >= way.length) {
nextIndex = 0;
}
}
moveDir = (way[nextIndex].point.position -target.position).normalized;
if (rotationSpeed > 0) {
tempDir = Vector3.RotateTowards(tempDir, moveDir, rotationSpeed *Time.deltaTime, Vector3.Angle(tempDir, moveDir));
moveDir = tempDir.normalized;
}
target.position += moveDir *moveSpeed *Time.deltaTime;
if (isLookAtRoot) {
moveDir = waypointsRoot.position -target.position;
}
target.rotation = Quaternion.LookRotation(moveDir, Vector3.up);
if (isLockHorizontal) {
target.rotation.eulerAngles.x = 0;
target.rotation.eulerAngles.z = 0;
}
}
private function getWaypoints(root_:Transform):WaypointMover_point[] {
uIDs.Clear();
var idx:int = 0;
var result:WaypointMover_point[] = new WaypointMover_point[root_.childCount];
for (var child:Transform in root_) {
result[idx] = new WaypointMover_point(child, child.name);
uIDs.Add(child.GetInstanceID(), result[idx]);
idx++;
}
System.Array.Sort(result);
return result;
}
function OnDrawGizmos() {
if (waypointsRoot) {
if (way) {
if (way.length > 0) {
if (checkChildsUpdate(waypointsRoot)) {
way = getWaypoints(waypointsRoot);
}
for (var i:int = 0; i < way.length -1; i++) {
Gizmos.color = cubeColor;
Gizmos.DrawCube(way[i].point.position, Vector3.one *cubeSize);
Gizmos.color = lineColor;
Gizmos.DrawLine(way[i].point.position, way[i +1].point.position);
}
Gizmos.color = cubeColor;
Gizmos.DrawCube(way[way.length -1].point.position, Vector3.one *cubeSize);
Gizmos.color = lineColor;
Gizmos.DrawLine(way[way.length -1].point.position, way[0].point.position);
} else {
way = getWaypoints(waypointsRoot);
}
} else {
way = getWaypoints(waypointsRoot);
}
}
}
private function checkChildsUpdate(root_:Transform):boolean {
var result:boolean = false;
for (var child:Transform in root_) {
var id:int = child.GetInstanceID();
if (!uIDs.ContainsKey(id)) {
result = true;
break;
} else {
if (uIDs[id].name.CompareTo(child.gameObject.name) != 0) {
result = true;
break;
}
}
}
if (!result) {
if (way.length != root_.childCount) {
result = true;
}
}
return result;
}