x


Waypoint To Ignore Height & Add Smoothness

Hello Unity Fans,

I've been using a simple AI waypoint system for sometime, and it has only just occurred to me that it causes my enemies to follow the same height as my waypoints too. In other words, if I position my waypoints 50 on the Y axis, then the enemies will be walking 50 above the floor.

What would I do to my script to ignore the Y axis of the waypoints?

Also, if you would be kind enough to make my enemies turn 'smoother' from one waypoint to another? Right now, the enemy walk to one waypoint, and then 'snap' to the other (Linier) - any way of making this smooth?

var waypoint : Transform[];
static var speed : float = 5;
private var currentWaypoint : int;
private var TurningSpeed : float = 15;


function Update () 
{
    if(currentWaypoint < waypoint.length)
    {
        var target : Vector3 = waypoint[currentWaypoint].position;
        var moveDirection : Vector3 = target - transform.position;
        var velocity = rigidbody.velocity;

        if(moveDirection.magnitude < 1)
        {
            currentWaypoint++;
        }
        else
        {
            velocity = moveDirection.normalized*speed;
        }
    }

    rigidbody.velocity = velocity;

    var lookAt = waypoint[currentWaypoint].position - transform.position;
    lookAt.y = 0;
    var rotation = Quaternion.LookRotation(lookAt);//target.position - transform.position
            transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * TurningSpeed);

}

Thanks folks!

more ▼

asked Dec 12 '10 at 06:20 PM

oliver-jones gravatar image

oliver-jones
2.5k 206 226 254

(comments are locked)
10|3000 characters needed characters left

5 answers: sort voted first

What would I do to my script to ignore the Y axis of the waypoints?

// This line you already have.
var moveDirection : Vector3 = target - transform.position;

// Add this line to ignore y.
moveDirection.y = 0;

// This line is modified to have "simple (incorrect) gravity".
velocity = (moveDirection.normalized - (Vector3.up * 20.0f))  * speed;

Since your solution overrides the previous velocity of the rigid body, you might want to keep another variable updating the rate of fall, for gravity. The method I showed won't look pretty, but it won't slow down near the checkpoints due to the moveDirection is wrong.

I hate to hand it out to you, but I think you have a problem with your solution all together. Why did you use rigid bodies? They are hard to get right and is probably not what you need for most problems anyhow. Why don't you at least add forces instead of overwriting the velocity, so gravity and other forces are accounted for? Why not use the character controllers that are out there?

Anyhow, try the change with the last line of code to see if you get your desired effect.

more ▼

answered Dec 15 '10 at 12:15 PM

Statement gravatar image

Statement ♦♦
20.1k 35 70 175

I tried this and it works, BUT, if my terrain goes negative (walking down a hill), then it doesn't work because its following the 0. I've tried making it a negative number, such as -20, but then the enemy walks slower due to the 'pulling mass'.

Dec 15 '10 at 04:37 PM oliver-jones

It sounds like your character just have to apply gravity?

Dec 15 '10 at 04:47 PM Statement ♦♦

I have gravity applied - what do you suggest for a new approach then? All my enemy do is to follow one waypoint after another in sequence.

Dec 15 '10 at 08:02 PM oliver-jones

How about you give proper pathfinding a shot? http://www.arongranberg.com/unity/a-pathfinding/

Dec 16 '10 at 03:08 PM Statement ♦♦

I know I'm far to late, but I felt like I just had to say this: Use moveDirection.y = transform.position.y. That way it will really ignore the y, placing it on the level as the enemy. Gravity and all the other physics will still work as normal.

Apr 01 '11 at 12:57 PM e.bonneville
(comments are locked)
10|3000 characters needed characters left

For smooth rotation without physics, you can use this:

public static bool RotateTowards(Transform objectTransform, Vector3 targetLookAt, 
   float rotationSpeed)
{
  Vector3 targretDirection = 
    (targetLookAt - objectTransform.position).normalized;

  Vector3 newDirection = 
    Vector3.RotateTowards(objectTransform.forward, targretDirection, rotationSpeed, 1000f);

  objectTransform.LookAt(objectTransform.position + newDirection);

  return (newDirection - targretDirection).sqrMagnitude < 0.001f;
}

The function should be called in Update. It returns true when the object is in the correct rotation, that is, it is facing the point targetLookAt. The transform passed to the function is the transform you wish to rotate. The rotationSpeed controls how fast the object rotates (start with 0.1f).

The magic number of 1000f you see there is one that works for me, but I don't really understand what it does :( The docs on Vector3.RotateTowards is not very clear.

The following is a JavaScript version (I am not a JavaScript native speaker, if anyone sees anything amiss, please let me know). It is not static, so you have to make put it in the same file as the thing you wish to rotate.

function RotateTowards(
    objectTransform : Transform, 
    targetLookAt : Vector3, 
    rotationSpeed : float )
{
   var targretDirection : Vector3 = 
     (targetLookAt - objectTransform.position).normalized;

   var newDirection : Vector3 = 
     Vector3.RotateTowards(objectTransform.forward, targretDirection, rotationSpeed, 1000f);

   objectTransform.LookAt(objectTransform.position + newDirection);

   return (newDirection - targretDirection).sqrMagnitude < 0.001f;
};
more ▼

answered Dec 16 '10 at 08:13 AM

Herman Tulleken gravatar image

Herman Tulleken
1.6k 25 36 56

Looks good - I'm trying to convert it into JavaScript, but I keep getting errors. Could you give me a hand? Cheers :)

Dec 16 '10 at 02:48 PM oliver-jones

@oliver-jones I updated my answer.

Dec 16 '10 at 03:15 PM Herman Tulleken
(comments are locked)
10|3000 characters needed characters left

I post another answer because this isn't related to my previous one.

How about you give proper pathfinding a shot? Then I think you have to worry less about all the different special cases such as slopes and colliders.

more ▼

answered Dec 16 '10 at 03:16 PM

Statement gravatar image

Statement ♦♦
20.1k 35 70 175

I had a look at this - but its not really for my game - mines more of a tower defence type - so the enemy follow a specific path.

Dec 16 '10 at 09:38 PM oliver-jones

Then simply do this. Ignore the rigidbody all together. Use the velocity to find the next position. (nextPosition = position + velocity * Time.deltaTime). Then sample the Y coordinate of your terrain and replace nextPosition.Y with that sample. Finally position your character at nextPosition. Done.

Dec 16 '10 at 11:40 PM Statement ♦♦

I like the idea of this - Could you please collaborate some more? Maybe give an example of code in your post? Thanks

Dec 17 '10 at 02:56 AM oliver-jones
(comments are locked)
10|3000 characters needed characters left

To make turning smoother, try rigidbody.AddRelativeTorque() and then stopping it from rotating when it's pointing towards the way point. See here for another way to do it from the Unity docs.

Here is some example code for looking at and then moving towards a waypoint called waypoint. Replace waypoint with some code to figure out the current waypoint.

var waypoint : Transform;
var speed : int = 3; // var something : int? That may be wrong. If it is, just remove it

function Update() {
   transform.LookAt(waypoint);
   transform.Rotate(transform.rotation.x, 0, transform.rotation.z);

   while (transform.position.x != waypoint.position.x && transform.position.z != waypoint.position.z) {
      rigidbody.AddRelativeForce(0, 0, speed);
   }
}

The way this works is that the gameObject this script is attached to looks at the gameObject waypoint, sets it y-axis rotation to zero, then keeps moving forward until it's x and z positions are the same as the waypoint's

more ▼

answered Dec 15 '10 at 04:30 AM

fireDude67 gravatar image

fireDude67
945 9 15 30

I keep getting errors like: 'position is not a member of Unity transform[]'

Dec 16 '10 at 02:53 PM oliver-jones
(comments are locked)
10|3000 characters needed characters left

You might also want to try using a dynamically-created Empty GameObject, instanced in the AI object's Awake(). Set the x&z position of this to where you want to go (say the waypoint's x&z), then you can set y to whatever you like (terrain height, etc). You can then move the AI Target to wherever you want when you want the target to change, without needing to touch its seeking code once you're happy with it. Also, using a Transform means you can treat your AI target like one with regard to handy functions like Translate(). It is however less optimised and streamlined than simply storing a target x and z number.

For smooth turning, AddRelativeTorque() does indeed work well, although Mathf.MoveTowardsAngle() and Mathf.SmoothDampAngle() can be useful too for this purpose, particularly if you aren't using rigidbodies.

more ▼

answered Dec 15 '10 at 10:31 AM

Novodantis 1 gravatar image

Novodantis 1
1.7k 14 22 40

(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x208
x170
x95
x38

asked: Dec 12 '10 at 06:20 PM

Seen: 1591 times

Last Updated: Jul 16 '11 at 09:34 PM