I'm STILL searching for an answer to this Charcater Animation Problem

OK this issue is REALLY frustrating me, I've asked it here before and I got no answere that worked. And the Unity script reference aint helpin. The animation examples they use are not like the one I'm trying to do. I've been at this for a month now and still no answere to this. And the REALLY crappy part is that I'll bet it's something simpele.

OK once again. I have created some alien Zombies in MAX 8, exported them into Unity as FBX. Their animations by them selves work out fine: Here is my Animation script I'm using:

var minimumRunSpeed = 1.0;

function Start () {
    // Set all animations to loop
    animation.wrapMode = WrapMode.Loop;

    // Except our action animations, Dont loop those
    animation["RunAttack"].wrapMode = WrapMode.Once;

    // Put idle and run in a lower layer. They will only animate if our action animations are not playing
    animation["idle"].layer = -1;
    animation["Walk"].layer = -1;
    animation["RunAttack"].layer = -1;

    animation.Stop();
}

function SetSpeed (speed : float) {
    if (speed > minimumRunSpeed)
        animation.CrossFade("RunAttack");
    else
        animation.CrossFade("idle");
}

Now the problem occures when I add this script:

I know the issue is in here somewhere but I'm at my wits end to find it... and I just DON't get it, this script work fine for the robots in the FPS tutorial but I can't get it to work for my Zombies and there REALLY can't be that much of a difference???

var speed = 3.0;
var rotationSpeed = 5.0;
var shootRange = 15.0;
var attackRange = 30.0;
var shootAngle = 4.0;
var dontComeCloserRange = 5.0;
var delayShootTime = 0.35;
var pickNextWaypointDistance = 2.0;
var target : Transform;
var GreenPlasmaBall;

private var lastShot = -10.0;

// Make sure there is always a character controller
@script RequireComponent (CharacterController)

function Start () {
    // Auto setup player as target through tags
    if (target == null && GameObject.FindWithTag("Player"))
        target = GameObject.FindWithTag("Player").transform;

    Patrol();
}

function Patrol () {
    var curWayPoint = AutoWayPoint.FindClosest(transform.position);
    while (true) {
        var waypointPosition = curWayPoint.transform.position;
        // Are we close to a waypoint? -> pick the next one!
        if (Vector3.Distance(waypointPosition, transform.position) < pickNextWaypointDistance)
            curWayPoint = PickNextWaypoint (curWayPoint);

        // Attack the player and wait until
        // - player is killed
        // - player is out of sight     
        if (CanSeeTarget ())
            yield StartCoroutine("AttackPlayer");

        // Move towards our target
        MoveTowards(waypointPosition);

        yield;
    }
}

function CanSeeTarget () : boolean {
    if (Vector3.Distance(transform.position, target.position) > attackRange)
        return false;

    var hit : RaycastHit;
    if (Physics.Linecast (transform.position, target.position, hit))
        return hit.transform == target;

    return false;
}

function Shoot () {
    // Start shoot animation
    animation.CrossFade("RunAttack", 0.3);

    // Wait until half the animation has played
    yield WaitForSeconds(delayShootTime);

    // Fire gun
    BroadcastMessage("Fire");

    // Wait for the rest of the animation to finish
    yield WaitForSeconds(animation["RunAttack"].length - delayShootTime);
}

function AttackPlayer () {
    var lastVisiblePlayerPosition = target.position;
    while (true) {
        if (CanSeeTarget ()) {
            // Target is dead - stop hunting
            if (target == null)
                return;

            // Target is too far away - give up 
            var distance = Vector3.Distance(transform.position, target.position);
            if (distance > shootRange * 3)
                return;

            lastVisiblePlayerPosition = target.position;
            if (distance > dontComeCloserRange)
                MoveTowards (lastVisiblePlayerPosition);
            else
                RotateTowards(lastVisiblePlayerPosition);

            var forward = transform.TransformDirection(Vector3.forward);
            var targetDirection = lastVisiblePlayerPosition - transform.position;
            targetDirection.y = 0;

            var angle = Vector3.Angle(targetDirection, forward);

            // Start shooting if close and play is in sight
            if (distance < shootRange && angle < shootAngle)
                yield StartCoroutine("RunAttack");
        } else {
            yield StartCoroutine("SearchPlayer", lastVisiblePlayerPosition);
            // Player not visible anymore - stop attacking
            if (!CanSeeTarget ())
                return;
        }

        yield;
    }
}

function SearchPlayer (position : Vector3) {
    // Run towards the player but after 3 seconds timeout and go back to Patroling
    var timeout = 3.0;
    while (timeout > 0.0) {
        MoveTowards(position);

        // We found the player
        if (CanSeeTarget ())
            return;

        timeout -= Time.deltaTime;
        yield;
    }
}

function RotateTowards (position : Vector3) {
    SendMessage("SetSpeed", 0.0);

    var direction = position - transform.position;
    direction.y = 0;
    if (direction.magnitude < 0.1)
        return;

    // Rotate towards the target
    transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
    transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);
}

function MoveTowards (position : Vector3) {
    var direction = position - transform.position;
    direction.y = 0;
    if (direction.magnitude < 0.5) {
        SendMessage("SetSpeed", 0.0);
        return;
    }

    // Rotate towards the target
    transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
    transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);

    // Modify speed so we slow down when we are not facing the target
    var forward = transform.TransformDirection(Vector3.forward);
    var speedModifier = Vector3.Dot(forward, direction.normalized);
    speedModifier = Mathf.Clamp01(speedModifier);

    // Move the character
    direction = forward * speed * speedModifier;
    GetComponent (CharacterController).SimpleMove(direction);

    SendMessage("SetSpeed", speed * speedModifier, SendMessageOptions.DontRequireReceiver);
}

function PickNextWaypoint (currentWaypoint : AutoWayPoint) {
    // We want to find the waypoint where the character has to turn the least

    // The direction in which we are walking
    var forward = transform.TransformDirection(Vector3.forward);

    // The closer two vectors, the larger the dot product will be.
    var best = currentWaypoint;
    var bestDot = -10.0;
    for (var cur : AutoWayPoint in currentWaypoint.connected) {
        var direction = Vector3.Normalize(cur.transform.position - transform.position);
        var dot = Vector3.Dot(direction, forward);
        if (dot > bestDot && cur != currentWaypoint) {
            bestDot = dot;
            best = cur;
        }
    }

    return best;
}

What Happens

Well, my Alien Zombie flips over out of his character controller and plays his animations horizontally face down!! (NOT a Ridgedbody) its an enemy for a FPS game. I'm basically trying to find someway to get these guys to attack without weapons, but right now I can't even get them to amimate properly. Someone MUST have an answere to this.

Yes sir! When you made your model in max you need to flip it's pivot point so it is imported into unity the right way round. You also need to do this before you animate otherwise the animations come up all screwed up. It's not a "simple" problem in my eyes so don't feel too frustrated that you couldn't fix it, we only learnt this from a peer in our class with a faulty animation. Try it and if it doesn't help I'll be watching this space for an update.

If your model is rotated wrong just place it into an empty GameObject. Now you can correct the rotation with the empty GO. You will need to change your script because the animation component will be on the child object and not on the empty gameobject. In most cases that should solve the problem, but without seeing what's going on i can't tell you more about that.

You should check if your model is rotated the right way. If you drag&drop your asset from your project into the scene, is the model rotated the right way? If not you can box it like i said or try if you can remove the bone animation curves for the pivot bone and just rotate the model. Unity doesn't support motion delta for animations so the animations have to be animated in place.


edit

Now we know what’s the problem we can go on from there :wink:

Just think of your enemy as a logical enemy. The model and animations are just visual sugar. Just create an empty GameObject. This GO will become your new enemy. So it needs the AI script a character controller and whatsoever. If the enemy is ready you just add the model as child object to your enemy. The big advantage is if it’s rotated differently you can fix that on the child object and keep the enemy object up right.

The AI script of course can't use the animation Component of your model since the script is not attached to the model. The script have to use the childs animation component.

The easiest way is that the script provides a public variable to which you can assign the animation component of your child.

example:

var modelAnimation : Animation;
var minimumRunSpeed = 1.0;

function Start () {
    // Set all animations to loop
    modelAnimation.wrapMode = WrapMode.Loop;

    // Except our action animations, Dont loop those
    modelAnimation["RunAttack"].wrapMode = WrapMode.Once;

    // Put idle and run in a lower layer. They will only animate if our action animations are not playing
    modelAnimation["idle"].layer = -1;
    modelAnimation["Walk"].layer = -1;
    modelAnimation["RunAttack"].layer = -1;

    modelAnimation.Stop();
}

function SetSpeed (speed : float) {
    if (speed > minimumRunSpeed)
        modelAnimation.CrossFade("RunAttack");
    else
        modelAnimation.CrossFade("idle");
}

If you have set up your enemy like i said you just have to drag the child model onto the `modelAnimation` variable in the inspector.

I hope that finally fixes your problem.

Good luck