Animating objects along paths.

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?

Any help would be appreciated.

Cheers,

Simon.

You may find this code useful.

WaypointMover.js

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;
}

This code is from SmokymonkeyS Devlog a Japanese Unity game designer blog.

FYI doesn’t work for iPhone. The above site would be great if it weren’t in Japanese :frowning:

I wonder why, I never tried it on iphone. I’ll look into it.