Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by straydogstrut · May 15, 2010 at 03:27 PM · rotationwaypoint

Problem with NPC rotating around a waypoint

[EDITED FOR A THIRD TIME]

Brief overview of the problem:

Created a simple waypoint script attached to an npc with a character controller component. It rotates him towards the current waypoint, moves him towards it and when he's within a certain radius of it, tells him to aim at the next waypoint. When he gets to the end he aims for the first waypoint again.

Later added functionality to have the NPC patrol back and forth between a series of points or go round the waypoints in a loop. A boolean determines which behaviour this NPC performs. Worked perfectly at first, but then a problem appeared: When the npc reaches the first waypoint he just rotates around and around and doesn't select the next waypoint as his target.

Based on SpinalJack and Johan's answers, the problem seems to be that the NPC is overshooting the waypoint radius. Making a bigger radius works, but i'd rather implement Johan's suggestion re. the Dot Product as this should be more accurate.

Update

I couldn't get it to work using the Dot Product. To be honest, I didn't really understand what it was doing. Looking at Johan's suggestion again, it seems using the Dot Product and squaring the distance are two different solutions, rather than two I should implement simultaneously? I say this because squaring the distance successfully stops the spinning problem.

It seems though, that all this is doing is creating a bigger radius to reduce the risk of the npc overshooting? If that's true, then it's not really any different than setting a bigger radius to begin with. It still seems to break at sizes less than my moveSpeed variable (3), so i'm thinking that setting my radius to my moveSpeed variable will make it work in any situation (even if my npc moves at different speeds)?

That's the approach i've taken below, the squared radius coming out as 9m with the default settings. Both the LoopWaypoints and PatrolWaypoints functions work but there does seem to be quite a bit of duplicate code in there that i'd like to tidy up, if anyone has any ideas? There's also a noticeable delay in both when reaching the end of the waypoints and deciding where to go next.

var waypoints = new Array();

var moveSpeed = 3.0; var rotationSpeed = 3.0;

var waypointLoop : boolean = false; var myWaypoints : Transform;

private var currentWaypoint : int; private var returning : boolean;

private var forward; private var moveDirection : Vector3;

var waypointDirection : Vector3; var waypointDistance : float; var waypointRadius : float = moveSpeed;

function Start(){

 for (var child : Transform in myWaypoints) {

     waypoints.Add(child);
 }   

 currentWaypoint = 0;
 returning = false;

}

function Update(){

 forward = transform.TransformDirection(Vector3.forward);
 moveDirection = forward * moveSpeed;

 if(waypoints.length<=0){
     print("WARNING!! - No waypoints have been set for "+gameObject.name);
 } else {

     if(waypointLoop){
         LoopWaypoints();
     } else {
         PatrolWaypoints();
     }
 }

}

function LoopWaypoints(){

 if(currentWaypoint < waypoints.length){

     waypointDirection = waypoints[currentWaypoint].position - transform.position;
     waypointDistance = waypointDirection.sqrMagnitude;

     if(waypointDistance <= (waypointRadius * waypointRadius)){

         currentWaypoint++;
     } else {
         RotateTowards(waypointDirection);
         MoveForward();
     }

 } else {

     currentWaypoint = 0;
 }

}

function PatrolWaypoints(){

 if(!returning){

     if(currentWaypoint < waypoints.length){

         waypointDirection = waypoints[currentWaypoint].position - transform.position;
         waypointDistance = waypointDirection.sqrMagnitude;

         if(waypointDistance <= (waypointRadius * waypointRadius)){

             currentWaypoint++;
         } else {
             RotateTowards(waypointDirection);
             MoveForward();
         }

     } else {

         currentWaypoint--;
         returning = true;           

     }

 } else {

     if(currentWaypoint > 0){


         waypointDirection = waypoints[currentWaypoint].position - transform.position;
         waypointDistance = waypointDirection.sqrMagnitude;

         if(waypointDistance <= (waypointRadius * waypointRadius)){

             currentWaypoint--;
         } else {
             RotateTowards(waypointDirection);
             MoveForward();
         }

     } else {

         returning = false;
     }
 }

}

Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image straydogstrut · May 16, 2010 at 08:07 PM 0
Share

Edit - tried moving the waypoints around a bit more and it shows the spinning problem on the last one. If someone could explain how to implement Johan's solutions correctly/or an alternative approach, i'd be grateful.

3 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by straydogstrut · May 22, 2010 at 01:29 PM

Answer from Andeeee on the Unity forums:

This "orbiting" effect occurs when the character is moving at its maximum speed and also turning at its maximum angular rate. If you are moving and turning at a constant rate, you are going in a circle and if the circle's radius is greater than the proximity distance for the waypoint, the character will orbit indefinitely. The best solution to this is to allow the character to slow down in proportion to the angle it has to turn. One easy way to do this is to multiply the speed by the dot product of the character's forward direction and the normalised direction of the next waypoint:-

var speedFactor = Vector3.Dot(waypointDirection.normalized, transform.forward);

var speed = moveSpeed * speedFactor;

This can give some slightly strange effects if the path has a "hairpin" turn around a single point, but it should usually work OK.

Unforunately I didn't have time to implement this in the project - it was our final piece of coursework on my Games Design degree - but it's nice to know why the problem occurs. I'm accepting this answer but thank you to SpinalJack and Johan for trying to help with this too.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0
Best Answer

Answer by spinaljack · May 15, 2010 at 04:02 PM

Try making the distance required bigger or the turning speed faster, you can also make the npc slow down near the way point to be certain he doesn't over shoot it. It could also be that the way point you're trying to reach is too high or too low in the ground for the npc to ever reach it. One way to fix this is to change the distance check to a 2D test and ignore the y axis. Or you could go around your map and make sure every way point is reachable.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image straydogstrut · May 15, 2010 at 04:15 PM 0
Share

Hi Spinaljack, thanks for the response. $$anonymous$$aking the waypoint radius larger has fixed it. I've now discovered other problems with my looping codes but I should be able to fix those. Thanks again=)

avatar image
0

Answer by johan-skold · May 15, 2010 at 04:03 PM

The problem you're likely encountering is that your NPC never reaches a position that is within waypointRadius units from the waypoint. Let's assume your NPC uses the default values, moving 3 units every frame and having to be within 1 unit of the target before moving to the next one. What happens if the NPC ends up at 1.5 units away from the target? He'll walk straight through and appear on the other side, ending up at 1.5 units away on that side instead, and keep doing this.

For a much more reliable way of doing it, compare the dot product of the direction vector before and after movement. If it is less than 0, you're on the other side of the target. A very simple and half-efficient example below, build it in however you see fit.

var beforeMovement : Vector3 = waypoints[currentWaypoint].position - transform.position; var moveDirection : Vector3 = forward * moveSpeed; var afterMovement : Vector3 = beforeMovement - moveDirection;

if (Vector3.Dot(beforeMovement, afterMovement) <= 0.0f) { // you will end up on the other side of the target after this movement }

Other than that, there's a few things you might want to look over with your code, that will do nothing but make it more time-efficient. For one, calculating distance between two points is expensive (at minimum a square root, a division, three multiplications and two additions) while calculating the square of the distance is cheap (three multiplications and two additions). Calculating square root and dividing is a lot more time consuming than one multiplication, therefore you'll want to use the square of the distance where you can. This is one such example. You could use this code instead, inside the LoopWaypoints and PatrolWaypoints methods;

var waypointDirection : Vector3 = waypoints[currentWaypoint].position - transform.position; var waypointDistance : float = waypointDirection.sqrMagnitude;

// if we are moving up through the waypoints (ie. not returning) if(!returning){ // if we have not reached the last waypoint (the -1 is necessary to avoid an Index Out of Range error) if(currentWaypoint < waypoints.length-1){ // if we have reached the current waypoint, aim for the next one if(waypointDistance <= (waypointRadius * waypointRadius)){

Since the comparison is using the square of waypointRadius in this example, it is fine if we only determine the square of the distance. Also, instead of moving a set value each frame, you'll probably want to make it time dependent (with Time.deltaTime), unless the SimpleMove method already does this.

var moveDirection = forward * (moveSpeed * Time.deltaTime);
Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image johan-skold · May 15, 2010 at 04:09 PM 0
Share

Just realized you were using javascript, updated the examples.

avatar image straydogstrut · May 15, 2010 at 04:30 PM 0
Share

Thanks Johan, you were both right about the radius and it's nice to know why it was a problem. I'll definitely try implementing your other suggestions to make it more efficient.

avatar image straydogstrut · May 16, 2010 at 01:04 PM 0
Share

Hi Johan, ran into some difficulty trying to implement your suggestions (completely the fault of my own inexperience). I've amended my question above.

Your answer

Hint: You can notify a user about this post by typing @username

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

Answers Answers and Comments

No one has followed this question yet.

Related Questions

Waypoint System Does Not Rotate Enemy? 2 Answers

rotate object to waypoints rotation 1 Answer

iTween and 2D Platforming Tutorial Merge: Rotation of player and camera needed 1 Answer

Keep rotation at (0,0,0) while transforming? 1 Answer

What's causing my NPC Controller to invert? Please Help!! 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges