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 snuffysam · Oct 13, 2015 at 11:25 AM · rigidbodyai problems

Custom pathing for AI is slow and doesn't work

I'm making a racing game. In it, I want there to be AI-controlled characters. I would use a pathing algorithm like A* for this, but I want my AI to only pull from certain actions- Turn left, Drift right, boost, etc.

So I wrote a custom pathing algorithm using a special Move class and had it determine what sequence of moves to use with breadth-first search.

However, the algorithm doesn't work right. The List of Moves returned by the method is often empty, the racer often bumps into walls, the sequence of moves doesn't actually get the racer to their target destination, and there's a noticeable delay each time the game has to run the algorithm (which is often, since the List is often empty).

The only reasons I see for this happening are the displacement being wrong, the velocity being wrong, and my loop that checks for walls being wrong- but if they are, I can't figure out what to do right.

Here's all the relevant code (you may have to copy-paste it elsewhere for it to be readable):

 public class Move{ //the custom move class       
                 private int turn;
                 private int moving;
                 private int drift;
                 private int prevDrift;
                 private int dBoost;
                 private int power;
                 private Vector3 start;
                 private Vector3 forward;
                 private Vector3 velocity;
                 private Move previous;
                 private Quaternion rot;
                 private Vector3 trans;
                 private Vector3 disp;
                 private MovementScript movement;
                 public string name;
         
                 public Move (int t, int m, int d, int db, int k, Vector3 s, Vector3 f, Vector3 v, Move p, MovementScript move){
                     turn = t;
                     moving = m;
                     drift = d;
                     dBoost = db;
                     power = k;
                     start = s;
                     forward = f;
                     float dragForceMagnitude = v.sqrMagnitude * move.GetComponent<Rigidbody>().drag;
                     Vector3 dragForceVector = dragForceMagnitude * -v.normalized;
                     velocity = v + dragForceVector;
                     previous = p;
                     movement = move;
                     if (previous != null) {
                         prevDrift = previous.GetDrift ();
                     } else if (dBoost > 0) {
                         prevDrift = (int)(movement.driftDir);
                     } else {
                         prevDrift = 0;
                     }
                     rot = MakeRotation ();
                     trans = MakeTranslation ();
                     disp = MakeDisplacement ();
                 }
         
                 public int GetTurn (){
                     return turn;
                 }
         
                 public int GetMoving (){
                     return moving;
                 }
         
                 public Move GetPrevious (){
                     return previous;
                 }
         
                 public int GetDrift (){
                     return drift;
                 }
         
                 public int GetDriftBoost (){
                     return dBoost;
                 }
         
                 public int GetPreviousDrift (){
                     return prevDrift;
                 }
         
                 public int GetPower (){
                     return power;
                 }
         
                 public Vector3 GetStart (){
                     return start;
                 }
         
                 public Vector3 GetForward (){
                     return forward;
                 }
         
                 public Vector3 GetVelocity (){
                     return velocity;
                 }
         
                 public Quaternion GetRotation (){
                     return rot;
                 }
         
                 public Vector3 GetTranslation (){
                     return trans;
                 }
         
                 public Vector3 GetDisplacement (){
                     return disp;
                 }
         
                 private Quaternion MakeRotation (){
                     if (drift == turn) {
                         return Quaternion.Euler (0, movement.handling * turn * 4 / 5, 0);
                     } else if (drift == turn * -1) {
                         Quaternion.Euler (0, movement.handling * turn / 8, 0);
                     } else if (drift == 0 && turn != 0) {
                         return Quaternion.Euler (0, movement.handling * turn / 2, 0);
                     } else if (turn == 0 && drift != 0) {
                         return Quaternion.Euler (0, movement.handling * drift / 6, 0);
                     }
                     return Quaternion.Euler (0, 0, 0);
                 }
         
                 private Vector3 MakeTranslation (){
                     Vector3 temp = velocity;
                     if (prevDrift != 0 && drift == 0) {
                         temp += forward * Mathf.Sqrt (dBoost) * 6;
                         dBoost = 0;
                     }
                     if (moving > 0) {
                         if (velocity.magnitude < (movement.speed + 3.0) / 2 * 5) {
                             temp += forward * (float)((movement.acceleration + 3.0) / 2.0) * 1.0f / 2;
                         } else if (!sameAngle (velocity, forward)) {
                             temp += forward * (float)((movement.acceleration + 3.0) / 2.0) * 1.0f / 4;
                         }
                         if (moving == 2 && velocity.magnitude < (movement.speed + 3.0) / 2.0 * 5.0 * (5.7 + (movement.boost + 3.0) / 2.0) / 2.2) {
                             if (!movement.super || movement.special != 23)
                                 power -= (int)((Mathf.Sqrt (movement.acceleration / 3.0f) + 1f) * 3.0f / 4.0f);
                             temp += forward * (float)((movement.acceleration + 6.0) / 3.0) * (float)(3.0 / 4.0);
                         }
                     }
                     return temp;
                 }
         
                 private Vector3 MakeDisplacement (){
                     return rot * trans;
                 }
         
             }
     }



 public SortedDictionary<string, Move> AllMoves (int dBoost, int power, Vector3 start, Vector3 forward, Vector3 velocity, Move previous)
     { //makes the set of all possible moves
         SortedDictionary<string, Move> moves = new SortedDictionary<string, Move> ();
         moves.Add ("stop", new Move (0, 0, 0, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("turn left", new Move (-1, 0, 0, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("turn right", new Move (1, 0, 0, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("move", new Move (0, 1, 0, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("move left", new Move (-1, 1, 0, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("move right", new Move (1, 1, 0, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("boost", new Move (0, 2, 0, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("boost left", new Move (-1, 2, 0, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("boost right", new Move (1, 2, 0, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("drift straight left", new Move (0, 1, -1, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("drift left correct", new Move (-1, 1, -1, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("drift right wrong", new Move (1, 1, -1, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("boost drift straight left", new Move (0, 2, -1, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("boost drift left correct", new Move (-1, 2, -1, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("boost drift right wrong", new Move (1, 2, -1, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("drift straight right", new Move (0, 1, 1, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("drift left wrong", new Move (-1, 1, 1, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("drift right correct", new Move (1, 1, 1, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("boost drift straight right", new Move (0, 2, 1, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("boost drift left wrong", new Move (-1, 2, 1, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
         moves.Add ("boost drift right correct", new Move (1, 2, 1, dBoost, power, start, forward, velocity, previous, GetComponent<MovementScript> ()));
 
         SortedDictionary<string, Move> finalmoves = new SortedDictionary<string, Move> ();
         foreach (KeyValuePair<string, Move> kvd in moves) {
             if (previous == null || kvd.Value.GetDrift () == 0 || kvd.Value.GetDrift () == previous.GetDrift ()) {
                 finalmoves.Add (kvd.Key, kvd.Value);
             }
             kvd.Value.name = kvd.Key;
         }
 
         return finalmoves;
     }



 public Stack<Move> GeneratePath (Vector3 targetPosition)
     {//the algorithm that creates the path
         List<Move> finalMoves = new List<Move> ();
         Queue<Move> nodes = new Queue<Move> ();
         while (finalMoves.Count < (cpuLevel+1)*3) {
             SortedDictionary<string, Move> possibleMoves;
             Move node;
             if (nodes.Count == 0) {
                 node = null;
                 possibleMoves = AllMoves (driftBoost, energy, transform.position, transform.forward, GetComponent<Rigidbody> ().velocity, null);
             } else {
                 node = nodes.Dequeue ();
                 possibleMoves = AllMoves (node.GetDriftBoost (), node.GetPower (), node.GetStart () + node.GetVelocity() + node.GetDisplacement (), node.GetRotation () * node.GetForward (), node.GetVelocity() + node.GetDisplacement (), node);
             }
             if (node != null && (node.GetStart () - targetPosition).magnitude <= (node.GetVelocity() + node.GetDisplacement ()).magnitude) {
                 finalMoves.Add (node);
             } else {
                 int ignored = 0;
                 foreach (KeyValuePair<string, Move> kvd in possibleMoves) {
                     if (kvd.Value.GetPower () > 0) {
                         RaycastHit[] r = Physics.RaycastAll (kvd.Value.GetStart (), kvd.Value.GetRotation () * kvd.Value.GetForward (), (kvd.Value.GetVelocity() + kvd.Value.GetDisplacement ()).magnitude);
                         bool b = false;
                         for (int i = 0; i < r.Length; i++) {
                             if (r [i].collider.CompareTag ("Wall")) {
                                 b = true;
                                 break;
                             }
                         }
                         if (!b) {
                             nodes.Enqueue (kvd.Value);
                         }
                     }
                 }
             }
         }
 
         int index = Random.Range (0, finalMoves.Count);
         Move m = null;
         if (finalMoves.Count > 0)
             m = finalMoves.ToArray () [index];
         Stack<Move> path = new Stack<Move> ();
         while (m != null) {
             path.Push (m);
             m = m.GetPrevious ();
         }
         return path;
 
     }



 //the part of Update that sets the AI's movement
 //targetPosition is obtained earlier in the code, and it's definitely working
 if (AIpath == null || AIpath.Count == 0) {
                     AIpath = GeneratePath (targetPosition);
                 }
                 Move m = null;
                 if (AIpath != null && AIpath.Count > 0)
                     m = AIpath.Pop ();
 
                 if (m != null) {
                     turn = m.GetTurn ();
                     moving = m.GetMoving ();
                     drift = m.GetDrift ();
                     driftBoost = m.GetDriftBoost ();
                     energy = m.GetPower ();
                     rb.velocity += m.GetDisplacement ();
                     rb.MoveRotation (rb.rotation * m.GetRotation ());
                 }



 //for reference, here is the completely working player code
 moving = direction;
                 drift = (int)(driftDir);
                 if (Input.GetAxis ("Gas") > 0) {
                     direction = 1;
                     if (rb.velocity.magnitude < (speed + 3.0) / 2 * 5) {
                         rb.velocity += transform.forward * (float)((acceleration + 3.0) / 2.0) * Input.GetAxis ("Gas") / 2;
                     } else if (!sameAngle (rb.velocity, transform.forward)) {
                         rb.velocity += transform.forward * (float)((acceleration + 3.0) / 2.0) * Input.GetAxis ("Gas") / 4;
                     }
                 } else if (Input.GetAxis ("Brake") > 0 && ((direction == 1 && rb.velocity.magnitude > 0) || rb.velocity.magnitude > speed * 6)) {
                     rb.velocity -= transform.forward * (float)((acceleration + 3.0) / 2.0) / 5;
                     if (rb.velocity.magnitude < speed / 2 || reverseAngle (rb.velocity, transform.forward)) {
                         direction = 0;
                     }
                 } else if (Input.GetAxis ("Brake") > 0 && direction <= 0 && rb.velocity.magnitude < speed * 2) {
                     direction = -1;
                     rb.velocity -= transform.forward * (float)((acceleration + 3.0) / 2.0) * Input.GetAxis ("Brake") / 7;
                 } else if (rb.velocity.magnitude > 0) {
                     rb.velocity -= transform.forward / 10;
                     if (rb.velocity.magnitude < speed / 2) {
                         direction = 0;
                     }
                 } else if (direction < 0) {
                     rb.velocity += transform.forward / 10;
                     if (rb.velocity.magnitude < speed / 2) {
                         direction = 0;
                     }
                 }
                 if (Input.GetAxis ("Horizontal") != 0) {
                     turn = (int)Mathf.Sign (Input.GetAxis ("Horizontal"));
                     if (Input.GetAxis ("Brake") > 0 && direction != 0) {
                         if (direction == 1) {
                             if (driftDir == 0 || driftDir == Input.GetAxis ("Horizontal") / Mathf.Abs (Input.GetAxis ("Horizontal"))) {
                                 driftDir = Input.GetAxis ("Horizontal") / Mathf.Abs (Input.GetAxis ("Horizontal"));
                                 var deltaRotation = Quaternion.Euler (0, handling * Input.GetAxis ("Horizontal") * Input.GetAxis ("Brake") * 4 / 5, 0);
                                 rb.MoveRotation (rb.rotation * deltaRotation);
                                 driftBoost++;
                             } else {
                                 var deltaRotation = Quaternion.Euler (0, handling * Input.GetAxis ("Horizontal") / 8, 0);
                                 rb.MoveRotation (rb.rotation * deltaRotation);
                             }
                         }
                         if (direction == -1) {
                             var deltaRotation = Quaternion.Euler (0, handling * Input.GetAxis ("Horizontal") / -4, 0);
                             rb.MoveRotation (rb.rotation * deltaRotation);
                         }
                     } else {
                         var deltaRotation = Quaternion.Euler (0, handling * Input.GetAxis ("Horizontal") / 2, 0);
                         rb.MoveRotation (rb.rotation * deltaRotation);
                         //Debug.Log ("AAAAA");
                     }
                 }
                 if (Input.GetAxis ("Horizontal") == 0 && driftDir != 0) {
                     var deltaRotation = Quaternion.Euler (0, handling * driftDir / 6, 0);
                     rb.MoveRotation (rb.rotation * deltaRotation);
                 }
                 if (Input.GetAxis ("Boost") > 0 && rb.velocity.magnitude < (speed + 3.0) / 2.0 * 5.0 * (5.7 + (boost + 3.0) / 2.0) / 2.2) {
                     if (!super || special != 23)
                         energy -= (int)((Mathf.Sqrt (acceleration / 3.0f) + 1f) * 3.0f / 4.0f);
                     rb.velocity += transform.forward * (float)((acceleration + 6.0) / 3.0) * Input.GetAxis ("Boost") * (float)(3.0 / 4.0);
                 } 
 
                 if (Input.GetAxis ("Boost") > 0) {
                     moving = 2;
                 } 
                 if (Input.GetAxis ("Brake") == 0 && driftDir != 0 && direction != -1 && Input.GetAxis ("Gas") > 0) {
                     rb.velocity += transform.forward * Mathf.Sqrt (driftBoost) * 6;
                     driftBoost = 0;
                     driftDir = 0;
                 }







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 snuffysam · Oct 13, 2015 at 08:03 PM 0
Share

I can clarify any part of the code if it's confusing, but the main point is that the movement for the AI is exactly the same as the movement for the player, so there has to be some external factor that's making it not work.

0 Replies

· Add your reply
  • Sort: 

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

3 People are following this question.

avatar image avatar image avatar image

Related Questions

How to stop MoveRotation when rigidbody is facing a specific euler angle 2 Answers

Moving sphere tremble in moving camera view[Solved] 0 Answers

Smooth Player Ball Rolling 1 Answer

Further collision beyond the OnCollisionEnter() event 1 Answer

How to change velocity of object which move by Rigidbody. 1 Answer


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