Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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 SomeRandomGuy · Feb 26, 2013 at 11:45 AM · pathfindingfunctionsstates

AI states switching before functions in state finishes

Hi, I wrote the following code, and for some reason or the other, it will just keep switching between the follow and find state. The find state has a pathfinding function in it that should be executed to find a path, and then move the enemy along that path. For some reason it won't do this, and instead switches between the two states every frame or so.

 #pragma strict
 
 import System.Collections.Generic;
 
 var startNode: node;
 var targetNode: node;
 var curNode: node;
 
 var player: Transform;
 
 var map: AstarGrid;
     map = Terrain.activeTerrain.GetComponent(AstarGrid);
     
 var openList = new List.<node>();
 var closedList = new List.<node>();
 var pathList = new List.<node>();
 var neighbors: node[];
     neighbors = new node[4];
     
 var mapScale: float;
 var speed: float = 5;
 
 enum AIState
 {
     idle = 0,
     attack = 1,
     follow = 2,
     find = 3,
     death =4
 }
 var state: AIState = AIState.follow;
 
 function Awake()
 {
     player = GameObject.FindWithTag("Player").transform;
     
 }
 
 function Start()
 {
     mapScale = Terrain.activeTerrain.GetComponent(AstarGrid).nodeSize;
     InitStartFinish(transform,player);
 }
 
 function Update()
 {
     switch(state)
     {        
         case AIState.follow:
         
             var layerMask = 1 << 17;
             layerMask = ~layerMask;
             if (!Physics.Linecast(transform.position, player.position, layerMask))
             {
                 transform.LookAt(Vector3(player.position.x,transform.position.y,player.position.z));
                 if(Vector3.Distance(transform.position,player.position)>3)
                 {
                     transform.Translate(Vector3.forward*speed*Time.deltaTime);
                 }
                 Debug.DrawLine (transform.position, player.position, Color.green);    
                 print("following");
             }
             
             else
             {
                 state = AIState.find;
             }
             
         break;
         
         case AIState.find:
         
             if (Physics.Linecast(transform.position, player.position, layerMask))
             {
         
                 FindPath(curNode);
                 print("pathfinding");
             }
             
             else
             {
                 state = AIState.follow;
             }
             
         break;
         
         case AIState.idle:
         print("Idling");
         break;
         
         case AIState.attack:
         print("attacking");
         break;
 
         case AIState.death:
         print("dieing");
         break;
         
     }
 }
 
 //Set pixel based positions for start & end nodes. 
 function InitStartFinish(cur: Transform, target: Transform)
 {
     var tempNode: node;
         tempNode = new node();
     
     tempNode.pos.x = Mathf.Round(cur.position.x/mapScale);
     tempNode.pos.y = Mathf.Round(cur.position.z/mapScale);
     
     for(var i:int=0;i<map.nodes.Length;i++)
     {
         if(map.nodes[i].pos == tempNode.pos)
         {
             startNode = map.nodes[i];            
         }
     }
     
     tempNode.pos.x = Mathf.Round(target.position.x/mapScale);
     tempNode.pos.y = Mathf.Round(target.position.z/mapScale);
     
     for(i=0;i<map.nodes.Length;i++)
     {
         if(map.nodes[i].pos == tempNode.pos)
         {
             targetNode = map.nodes[i];
         }
     }
     curNode = startNode;
     openList.Add(curNode);
     CalcF(curNode);
 }
 //Cleans pathfinding arrays and such for the start of a new search.
 function clearPath()
 {
     map.InitGrid();
     openList = new List.<node>();
     closedList = new List.<node>();
     pathList = new List.<node>();
 }
 
 function FindPath(cur: node)
 {
     InitStartFinish(transform,player);
     while(curNode != targetNode)
     {
         //remove current node from open and add to closed
         openList.Remove(cur);
         closedList.Add(cur);
         
         //find neighbor nodes
         neighbors[0] = map.nodes[cur.ID-map.gridSize];
         neighbors[1] = map.nodes[cur.ID+1];
         neighbors[2] = map.nodes[cur.ID+map.gridSize];
         neighbors[3] = map.nodes[cur.ID-1];
         
         //for each neighboring node, check if it is walkable, not on either open or closed list, if so add to openlist, set parent to current node, and calculate F scores
         for(var i:int=0;i<neighbors.Length;i++)
         {
             if(neighbors[i].walkable == true)
             {
                 if(!closedList.Contains(neighbors[i]))
                 {
                     if(!openList.Contains(neighbors[i]))
                     {
                         openList.Add(neighbors[i]);
                         neighbors[i].parent = cur;
                         CalcF(neighbors[i]);
                     }
                     //if neighbor is in openlist, check G scores to see if current path is shorter or not. If so change parent to current node and recalculate F scores
                     if(openList.Contains(neighbors[i]))
                     {
                         if(cur.G+1< neighbors[i].G)
                         {
                             neighbors[i].parent = cur;
                             CalcF(neighbors[i]);
                         }
                     }
                 }
             }
         }
         //Find lowest F in openList
         curNode = openList[0];
         for(i=0;i<openList.Count;i++)
         {
             if(openList[i].F < openList[0].F)
             {
                 curNode = openList[i];
             }
         }
     }
     if(curNode == targetNode)
     {
         TracePath();
     }
 }
 //calculates F score for a node
 function CalcF(node: node)
 {
     //CalcG    
     if(node.parent==null)
     {
         node.G = 0;
     }
     else
     {
         node.G=1+node.parent.G;
     }
     
     //CalcH
     node.H = Mathf.Abs(node.pos.x-targetNode.pos.x) + Mathf.Abs(node.pos.y-targetNode.pos.y);
     
     //CalcF
     node.F = node.G + node.H;
 }
 //traces path when pathfinding is complete, follows it and draws it on the map.
 function TracePath()
 {
     var temp: node;
         temp = targetNode;
     for(var i:int=0;i<closedList.Count;i++)
     {
         Terrain.activeTerrain.GetComponent(AstarGrid).map.SetPixel(closedList[i].pos.x, closedList[i].pos.y, Color.yellow);
         Terrain.activeTerrain.GetComponent(AstarGrid).map.Apply();
     }
     
     while(temp != startNode)
     {
         pathList.Add(temp);
         Terrain.activeTerrain.GetComponent(AstarGrid).map.SetPixel(temp.pos.x, temp.pos.y, Color.red);
         Terrain.activeTerrain.GetComponent(AstarGrid).map.Apply();
         temp = temp.parent;
     }
     pathList.Reverse();
     
     for(i=0;i<pathList.Count && Vector3.Distance(pathList[i].RLPos, transform.position)<1;i++)
     {
         transform.LookAt(Vector3(pathList[i].RLPos.x,transform.position.y,pathList[i].RLPos.z));
     }
     transform.position = Vector3.MoveTowards(transform.position, pathList[i].RLPos, Time.deltaTime*speed); 
 }
 
 public class node
 {
     var ID: int;
     var parent: node;
     var pos: Vector2 = Vector2(0,0);
     var RLPos: Vector3;
     var walkable: boolean = true;
     var F: int = 0;
     var G: int = 0;
     var H: int = 0;    
 }

So I'm wondering, is my pathfinding function not completing, or is it getting cut off by something, or what? Any tips to fix/improve this?

Comment
Add comment · Show 4
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 SubatomicHero · Feb 26, 2013 at 04:12 PM 1
Share

After reading some of the code instantly I see that in your switch statement you should probably not have the state changing here in the else statement:

 switch(state)
     {   
        case AIState.follow:
  
          var layer$$anonymous$$ask = 1 << 17;
          layer$$anonymous$$ask = ~layer$$anonymous$$ask;
          if (!Physics.Linecast(transform.position, player.position, layer$$anonymous$$ask))
          {
           transform.LookAt(Vector3(player.position.x,transform.position.y,player.position.z));
           if(Vector3.Distance(transform.position,player.position)>3)
           {
               transform.Translate(Vector3.forward*speed*Time.deltaTime);
           }
           Debug.DrawLine (transform.position, player.position, Color.green);  
           print("following");
          }

          // $$anonymous$$aybe look at moving the following code outside of the update function
          // and control it somewhere else
          else
          {
           state = AIState.find;
          }
avatar image SomeRandomGuy · Feb 26, 2013 at 05:13 PM 0
Share

Why would I not want that? I do want the state to change to find when there is something blocking the path, so I should change it there, right?

avatar image SubatomicHero · Feb 26, 2013 at 05:17 PM 0
Share

well maybe the else is too vague, that the conditions are changing to the other state too easily and the else should become an else if. $$anonymous$$ake the criteria more rigid :D

avatar image SomeRandomGuy · Feb 26, 2013 at 05:21 PM 0
Share

Hmm that might work, but still not too sure why the states would keep switching when there are absolutely no changes in position

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by Owen-Reynolds · Feb 26, 2013 at 04:08 PM

The code says to quickly flip between find/follow when the linecast hits/misses. So maybe the linecast is occasionally hitting something?

The line goes from trans.position to player.position -- is that from your feet to the player's feet? If so, a tiny rise would block it. Could toss in a RayCastHit and print the name of what you're hitting (ex: "in follow: hit tree1")

I'd probably not have Follow flip to Find by being blocked for a single frame -- what if a tree got in the way? Might only switch to Find if I haven't seen the player for 0.5 second or more.

In Find, you're running a pathfind every frame. The path isn't going to change that much as the player moves (unless doors are closing, but you could have those signal you. Or does the player teleport?) Could only do a find if that last one was >5 seconds ago, or you reach the end.

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 SomeRandomGuy · Feb 26, 2013 at 05:11 PM 0
Share

As of right now my enemies aren't moving at all and all of them have something blocking their path. That's one of the reasons I find it strange that even tho nothing moves the states keep switching.

$$anonymous$$y pathfinding function should also not be called every frame, right now it's supposed to get a starting and end point, find a path to that point(this is what the while loop is for) then trace the path and move along it.

That's what one single call of that function is supposed to do. I thought it would complete that cycle before checking the linecast again, but If it really is being called all the time, I wonder how I could make it a one time call, before linecasting again to see if there's a straight path to the target or not.

I do agree that I should probably not switch to find state right after an obstruction, but that shouldn't be causing this kind of problem, right?

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

11 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Create spaceship attack logic [and other logic eventually] 1 Answer

A* pathfinder - next target 1 Answer

Modification of AIFollow.cs Pathfinding 0 Answers

How to edit navmesh at a runtime? 1 Answer

Pathfinding Returned Path dips AI into the ground 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