Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Resolved AI getting stuck into corner of the map

Discussion in 'Scripting' started by Marks_M, Dec 17, 2021.

  1. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27
    Hello everyone! I use Ai Behaviors Made Easy for my game development. I was going to ask how can I stop Ai from becoming forced into the corners of a map when it's fleeing from player,so it doesn't look like it's "running in place"? How can I start improving the flee state, so it's more realistic - so the player cant force the ai into the corners of the map when it's fleeing? How that would look in a script? I'm guessing I have to use raycast so the Ai detects when it's close to a wall or corner of the map and so it needs to create a new waypoint (away from the player)? Please help me out!

    Here's what I mean : https://media.giphy.com/media/k0cS1FnluJnECXOFUb/giphy.gif
     
    Last edited: Dec 19, 2021
  2. Lethn

    Lethn

    Joined:
    May 18, 2015
    Posts:
    1,583
    A quick and dirty way to deal with this problem would be to place colliders at the edge of the map and have the agent avoid those areas if they trigger it. To me though this looks more like a bit of a raycast solution where your agent should detect how far away it is from the ledge you've got so it knows that it exists.The reason this is happening is because the agent doesn't really know that the barrier exists, so naturally it's going to be dumb and just keep running in that direction while getting stuck to get away from the player.

    When dealing with any kind of NPC or computer 'player' you as the programmer have to take into account everything that the player sees and interacts with if you want to make believable enemies. Otherwise they'll simply break if the player does something unexpected which is why playtesting is so important.
     
    Last edited: Dec 17, 2021
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,067
    There's no general case that will work 100% of the time.

    For instance if you're blocking the only way out of an area with an enemy inside it, what could he do?

    One way that works pretty well is to pre-author a bunch of points around the edge of your level and have the enemy simply choose the farthest one and path towards it until the enemy decides it can relax again and come back. This won't address the above case of you blocking his way or otherwise waiting for him at a turn, but it's a better way than just pure "run away," which as you noted leads to corner-heading.
     
    Marks_M likes this.
  4. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27
    Can someone please provide a script example?
     
  5. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27
    I see. And thank you for your response. Can you provide an example of how that would look in code though?
     
  6. Lethn

    Lethn

    Joined:
    May 18, 2015
    Posts:
    1,583
    Marks_M likes this.
  7. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27
    Hi Lethn, I found a way to DETECT when the Ai is CLOSE to the corner of the map. Once it's close enough, then, Debug.Log (''Message'');. However I dont know how can i set the ai's waypoint AWAY from that edge and also ,then, AWAY from the player. Here's the code I found works so far :

    Code (CSharp):
    1.  
    2.                     UnityEngine.AI.NavMeshHit hit;
    3.                     float distanceToEdge = 1;
    4.  
    5.  
    6.                     if (UnityEngine.AI.NavMesh.FindClosestEdge(transform.position, out hit, UnityEngine.AI.NavMesh.AllAreas))
    7.                     {
    8.                         distanceToEdge = hit.distance;
    9.                     }
    10.  
    11.                     if (distanceToEdge < 1f)
    12.                     {
    13.                         Debug.Log("Corner");
    14.                     }
     
  8. Serge_Billault

    Serge_Billault

    Joined:
    Aug 26, 2014
    Posts:
    190
    Last edited: Dec 19, 2021
    Marks_M likes this.
  9. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27
    Actually this method only finds edges not the actual corners. Is there a way for it to detect CORNERS only?
     
  10. Serge_Billault

    Serge_Billault

    Joined:
    Aug 26, 2014
    Posts:
    190
    If Unity do not provide a built-in solution for detecting corners you can always implement a clean navmesh edges detection that do not only return the nearest, in which case you have a corner when you detect 2 or more edges in the detection radius which are facing each other, with an angle threshold as parameter. Or if you are only interested in L shape corners, not any too tight passage way that your NPC cant get through, you can restrict this edges detection to edges that are adjacents. You can also bake L shapes corners so that at run time it's just a matter of checking distances from these baked corners positions.
     
    Last edited: Dec 19, 2021
    Marks_M likes this.
  11. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27
    Hi and thank you for your response. Can you please provide script example? Would love to see how that would look in a code.
     
  12. Serge_Billault

    Serge_Billault

    Joined:
    Aug 26, 2014
    Posts:
    190
    Let say your detection return these 2 edges:
    Vector3 e0;
    Vector3 e1;
    Vector3 up = Vector3.up;
    * They are facing each other if 0 <= Vector3.Angle( e1, e2, up ) <= threshold

    (Do not take it literally, you have to make sure that the edges vectors are computed in such a way that the angle reflect the corner one)
     
    Last edited: Dec 19, 2021
    Marks_M likes this.
  13. Serge_Billault

    Serge_Billault

    Joined:
    Aug 26, 2014
    Posts:
    190
    I made you an exemple:

    When you press Play, the class NavMeshAnalytics computes 3 things:
    * bake NavMesh boundaries edges (blue lines in the screenshot)
    * bake NavMesh areas that are layer ignoring (blue lines in the screenshot)
    * bake corners (yellow spheres in the screenshot)

    You can know if you are near a corner with NavMashAnalytics.IsNearCorner( Vector3 pos, float dist ). Or you can create triggers from code at these locations.

    Link to sample project is here: https://drive.google.com/file/d/1NIMtkMJqXgQXyXCBfG0eLKGEZEMpYIPv/view?usp=sharing

    PS: if your level is moving, you of course first convert pos in the navmesh local space. (Games like God Of War have moving nav meshes that follow moving level chunks). But Unity is mainly a toy, so it's possible it only supports static nav meshes as the navmesh baking tool suggest.

    screenshot.jpg

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.AI;
    6.  
    7. //************************************************************************************
    8. //
    9. //************************************************************************************
    10.  
    11. public class NavMeshAnalytics : MonoBehaviour
    12. {
    13.     //********************************************************************************
    14.     //
    15.     //********************************************************************************
    16.  
    17.     public struct Edge { public int v0, v1; public Edge( int param_v0, int param_v1 ) { v0 = param_v0; v1 = param_v1; } }
    18.  
    19.     public struct Area { public List< int > edges; }
    20.  
    21.     //********************************************************************************
    22.     //
    23.     //********************************************************************************
    24.  
    25.     static private NavMeshTriangulation NAVMESH_DATAS      = default;
    26.  
    27.     static private List< Edge >         NAVMESH_BOUNDARIES = new List< Edge     >( 8  );
    28.  
    29.     static private List< Area >         NAVMESH_AREAS      = new List< Area     >( 8  );
    30.  
    31.     static private List< Vector3  >     NAVMESH_CORNERS    = new List< Vector3  >( 64 );
    32.  
    33.     //********************************************************************************
    34.     //
    35.     //********************************************************************************
    36.  
    37.     static public void Clear()
    38.     {
    39.         NAVMESH_BOUNDARIES.Clear();
    40.  
    41.         NAVMESH_AREAS.Clear     ();
    42.  
    43.         NAVMESH_CORNERS.Clear   ();
    44.     }
    45.  
    46.     //********************************************************************************
    47.     //
    48.     //********************************************************************************
    49.  
    50.     static public void Bake()
    51.     {
    52.         Clear();
    53.  
    54.         NAVMESH_DATAS = NavMesh.CalculateTriangulation();
    55.  
    56.         BakeBoundaries();
    57.  
    58.         BakeAreas     ();
    59.                  
    60.         BakeCorners   ();
    61.     }
    62.  
    63.     //********************************************************************************
    64.     //
    65.     //********************************************************************************
    66.  
    67.     static private bool TriContains( Vector3[] verts, int[] tris, int t, int v )
    68.     {
    69.         if( verts == null )
    70.         {
    71.             if( v == tris[ t     ] ) return true;
    72.  
    73.             if( v == tris[ t + 1 ] ) return true;
    74.  
    75.             if( v == tris[ t + 2 ] ) return true;
    76.         }
    77.         else
    78.         {
    79.             Vector3 pos = verts[ v ];
    80.  
    81.             if( pos == verts[ tris[ t     ] ] ) return true;
    82.  
    83.             if( pos == verts[ tris[ t + 1 ] ] ) return true;
    84.  
    85.             if( pos == verts[ tris[ t + 2 ] ] ) return true;
    86.         }
    87.  
    88.  
    89.         return false;
    90.     }
    91.  
    92.     //********************************************************************************
    93.     //
    94.     //********************************************************************************
    95.  
    96.     static private List< int > GetAdjacentTris( int[] tris, int v )
    97.     {
    98.         List< int > result = new List< int >( 8 );
    99.  
    100.         for( int t = 0, nb_tris = tris.Length; t < nb_tris; t += 3 )
    101.         {
    102.             if( TriContains( null, tris, t, v ) ) result.Add( t );
    103.         }
    104.  
    105.         return result;
    106.     }
    107.  
    108.     //********************************************************************************
    109.     //
    110.     //********************************************************************************
    111.  
    112.     static private bool EdgesAreConnected( Vector3[] verts, Edge e0, Edge e1 )
    113.     {
    114.         if( verts == null )
    115.         {
    116.             if( ( e0.v0 == e1.v0 ) || ( e0.v0 == e1.v1 ) ) return true;
    117.  
    118.             if( ( e0.v1 == e1.v0 ) || ( e0.v1 == e1.v1 ) ) return true;
    119.         }
    120.         else
    121.         {
    122.             Vector3 e0_v0 = verts[ e0.v0 ];
    123.  
    124.             Vector3 e1_v0 = verts[ e1.v0 ];
    125.  
    126.             Vector3 e1_v1 = verts[ e1.v1 ];
    127.  
    128.             if( ( e0_v0 == e1_v0 ) || ( e0_v0 == e1_v1 ) ) return true;
    129.  
    130.  
    131.             Vector3 e0_v1 = verts[ e0.v1 ];
    132.  
    133.             if( ( e0_v1 == e1_v0 ) || ( e0_v1 == e1_v1 ) ) return true;
    134.         }
    135.  
    136.         return false;
    137.     }
    138.  
    139.     //********************************************************************************
    140.     //
    141.     //********************************************************************************
    142.  
    143.     static private bool IsBoundaryEdge( Vector3[] verts, int[] tris, int t, int v0, int v1 )
    144.     {
    145.         for( int other = 0, nb_tris = tris.Length; other < nb_tris; other += 3 )
    146.         {
    147.             if( other != t )
    148.             {
    149.                 if( TriContains( verts, tris, other, v0 ) && TriContains( verts, tris, other, v1 ) )
    150.                 {
    151.                     return false;
    152.                 }
    153.             }
    154.         }
    155.  
    156.         return true;
    157.     }
    158.  
    159.     //********************************************************************************
    160.     //
    161.     //********************************************************************************
    162.  
    163.     static private List< Edge > GetBoundaryEdges( Vector3[] verts, int[] tris )
    164.     {
    165.         List< Edge > edges = new List< Edge >( 16 );
    166.  
    167.         for( int t = 0, nb_tris = tris.Length; t < nb_tris; t += 3 )
    168.         {
    169.             Edge e0 = new Edge( tris[ t     ], tris[ t + 1 ] );
    170.  
    171.             Edge e1 = new Edge( tris[ t + 1 ], tris[ t + 2 ] );
    172.  
    173.             Edge e2 = new Edge( tris[ t + 2 ], tris[ t     ] );
    174.  
    175.             if( IsBoundaryEdge( verts, tris, t, e0.v0, e0.v1 ) ) edges.Add( e0 );
    176.  
    177.             if( IsBoundaryEdge( verts, tris, t, e1.v0, e1.v1 ) ) edges.Add( e1 );
    178.  
    179.             if( IsBoundaryEdge( verts, tris, t, e2.v0, e2.v1 ) ) edges.Add( e2 );
    180.         }
    181.  
    182.         return edges;
    183.     }
    184.  
    185.     //********************************************************************************
    186.     //
    187.     //********************************************************************************
    188.  
    189.     static private bool GetNextConnectedEdge( Vector3[] verts, List< Edge > edges, int e_bgn, ref int e_cur, BitArray consumed )
    190.     {
    191.         for( int other = 0, count = edges.Count; other < count; ++other )
    192.         {
    193.             if( consumed.Get( other ) == false )
    194.             {
    195.                 if( EdgesAreConnected( verts, edges[ e_cur ], edges[ other ] ) )
    196.                 {
    197.                     e_cur = other;
    198.  
    199.                     return   true;
    200.                 }
    201.             }
    202.         }
    203.  
    204.         return false;
    205.     }
    206.  
    207.     //********************************************************************************
    208.     //
    209.     //********************************************************************************
    210.  
    211.     static private void BakeBoundaries()
    212.     {
    213.         NAVMESH_BOUNDARIES.Clear();
    214.  
    215.         NAVMESH_BOUNDARIES = GetBoundaryEdges( NAVMESH_DATAS.vertices, NAVMESH_DATAS.indices );
    216.  
    217.         Debug.Log( $"NavmeshAnalytics: baked {NAVMESH_BOUNDARIES.Count} boundary edges" );
    218.     }
    219.  
    220.     //********************************************************************************
    221.     //
    222.     //********************************************************************************
    223.  
    224.     static private void BakeAreas()
    225.     {
    226.         NAVMESH_AREAS.Clear();
    227.  
    228.         Vector3[]   verts = NAVMESH_DATAS.vertices;
    229.  
    230.         BitArray consumed = new BitArray( NAVMESH_BOUNDARIES.Count );
    231.  
    232.         for( int e = 0, count = NAVMESH_BOUNDARIES.Count; e < count; ++e )
    233.         {
    234.             if( consumed.Get( e ) == false )
    235.             {
    236.                 Area  area = new Area();
    237.  
    238.                 area.edges = new List< int >( 16 );
    239.  
    240.                 NAVMESH_AREAS.Add( area );
    241.  
    242.  
    243.                 int e_bgn = e;
    244.  
    245.                 int e_cur = e;
    246.  
    247.                 area.edges.Add( e_bgn );
    248.  
    249.                 consumed.Set( e_bgn, true );
    250.  
    251.                 while( GetNextConnectedEdge( verts, NAVMESH_BOUNDARIES, e_bgn, ref e_cur, consumed ) )
    252.                 {
    253.                     area.edges.Add( e_cur );
    254.  
    255.                     consumed.Set( e_cur, true );
    256.                 }
    257.  
    258.                 for( int E = 0; E < area.edges.Count; ++E )
    259.                 {
    260.                     int  i0 = area.edges[ E ];
    261.  
    262.                     int  i1 = area.edges[ ( E + 1 ) % area.edges.Count ];
    263.  
    264.                     Edge e0 = NAVMESH_BOUNDARIES[ i0 ];
    265.  
    266.                     Edge e1 = NAVMESH_BOUNDARIES[ i1 ];
    267.  
    268.                     if( verts[ e0.v1 ] != verts[ e1.v0 ] )
    269.                     {
    270.                         int tmp = e1.v1;
    271.  
    272.                         e1.v1 = e1.v0;
    273.  
    274.                         e1.v0 = tmp;
    275.  
    276.                         NAVMESH_BOUNDARIES[ i1 ] = e1;
    277.                     }
    278.                 }
    279.             }
    280.         }
    281.  
    282.         Debug.Log( $"NavmeshAnalytics: baked {NAVMESH_AREAS.Count} areas" );
    283.     }
    284.  
    285.     //********************************************************************************
    286.     //
    287.     //********************************************************************************
    288.  
    289.     static private void BakeCorners()
    290.     {
    291.         NAVMESH_CORNERS.Clear();
    292.  
    293.         Vector3[] verts = NAVMESH_DATAS.vertices;
    294.  
    295.         for( int a = 0; a < NAVMESH_AREAS.Count; ++a )
    296.         {
    297.             Area area = NAVMESH_AREAS[ a ];
    298.  
    299.             for( int e = 0; e < area.edges.Count; ++e )
    300.             {
    301.                 Edge    e0 = NAVMESH_BOUNDARIES[ area.edges[ e ] ];
    302.                    
    303.                 Edge    e1 = NAVMESH_BOUNDARIES[ area.edges[ ( e + 1 ) % area.edges.Count ] ];
    304.  
    305.                 Vector3 s0 = ( verts[ e0.v1 ] - verts[ e0.v0 ] );
    306.  
    307.                 Vector3 s1 = ( verts[ e1.v1 ] - verts[ e1.v0 ] );
    308.  
    309.                 if( ( 180f - Vector3.Angle( s0, s1 ) ) <= 90.0f )
    310.                 {
    311.                     NAVMESH_CORNERS.Add( verts[ e0.v1 ] );
    312.                 }
    313.             }
    314.         }
    315.  
    316.         Debug.Log( $"NavmeshAnalytics: baked {NAVMESH_CORNERS.Count} corners" );
    317.     }
    318.  
    319.     //********************************************************************************
    320.     //
    321.     //********************************************************************************
    322.  
    323.     static public bool IsNearCorner( Vector3 pos, float dist )
    324.     {
    325.         float sqr_dist = dist * dist;
    326.  
    327.         for( int c = 0; c < NAVMESH_CORNERS.Count; ++c )
    328.         {
    329.             Vector3 corner = NAVMESH_CORNERS[ c ];
    330.  
    331.             Vector3 sep    = corner - pos;
    332.  
    333.             if( sep.sqrMagnitude < sqr_dist ) return true;
    334.         }
    335.  
    336.         return false;
    337.     }
    338.  
    339.     //********************************************************************************
    340.     //
    341.     //********************************************************************************
    342.  
    343.     private void Awake() { Bake(); }
    344.  
    345.     //********************************************************************************
    346.     //
    347.     //********************************************************************************
    348.  
    349.     private void OnDrawGizmos()
    350.     {
    351.         Color restore = Gizmos.color;
    352.  
    353.             Vector3[] verts = NAVMESH_DATAS.vertices;
    354.  
    355.                 int[]  tris  = NAVMESH_DATAS.indices;
    356.  
    357.             int    nb_verts = ( verts != null ) ? verts.Length : 0;
    358.  
    359.             int    nb_tris  = ( tris  != null ) ? tris.Length  : 0;
    360.  
    361.             if( nb_verts > 0 )
    362.             {
    363.                 Gizmos.color  = Color.red;
    364.  
    365.                 Vector3  size = Vector3.one * 0.2f;
    366.  
    367.                 for( int v = 0; v < nb_verts; ++v )
    368.                 {
    369.                     Gizmos.DrawCube( verts[ v ], size );
    370.                 }
    371.  
    372.  
    373.                 Gizmos.color = Color.blue;
    374.  
    375.                 for( int a = 0; a < NAVMESH_AREAS.Count; ++a )
    376.                 {
    377.                     Area area = NAVMESH_AREAS[ a ];
    378.  
    379.                     for( int e = 0; e < area.edges.Count; ++e )
    380.                     {
    381.                         Edge edge = NAVMESH_BOUNDARIES[ area.edges[ e ] ];
    382.  
    383.                         Gizmos.DrawLine( verts[ edge.v0 ], verts[ edge.v1 ] );
    384.                     }
    385.                 }
    386.  
    387.  
    388.                 Gizmos.color = Color.yellow;
    389.  
    390.                 for( int c = 0; c < NAVMESH_CORNERS.Count; ++c )
    391.                 {
    392.                     Gizmos.DrawSphere( NAVMESH_CORNERS[ c ], 0.5f );
    393.                 }
    394.             }
    395.  
    396.         Gizmos.color = restore;
    397.     }
    398. }
    399.  
    400.  
     
    Last edited: Dec 20, 2021
    Marks_M likes this.
  14. Serge_Billault

    Serge_Billault

    Joined:
    Aug 26, 2014
    Posts:
    190
    I had totally forgot about that.

    Here: https://drive.google.com/file/d/1NIMtkMJqXgQXyXCBfG0eLKGEZEMpYIPv/view?usp=sharing
    The nearest points on detected edges within the radius parameter are the magenta cubes.

    I recommend using a BSP or something in that spirit to speed up edges detection. The order of operations is usually as follow:
    * BSP or similar -> edge bounding box/sphere intersection -> GetNearestPointOnEdge()

    screenshot1.jpg

    Code (CSharp):
    1.  
    2.     //********************************************************************************
    3.     //
    4.     //********************************************************************************
    5.  
    6.     static private bool GetNearestPointOnEdge( Vector3 pos, Edge edge, float sqr_dist, ref Vector3 p )
    7.     {
    8.         Vector3 v0 = NAVMESH_DATAS.vertices[ edge.v0 ];
    9.  
    10.         Vector3 v1 = NAVMESH_DATAS.vertices[ edge.v1 ];
    11.  
    12.         Vector3 V  = v1  - v0;
    13.  
    14.         Vector3 v  = pos - v0;
    15.  
    16.         if     ( Vector3.Dot( v,        V       ) <= 0.0f ) p = v0;
    17.  
    18.         else if( Vector3.Dot( pos - v1, v0 - v1 ) <= 0.0f ) p = v1;
    19.  
    20.         else   { Vector3 unit_V = V.normalized; p = v0 + ( Vector3.Dot( v, unit_V ) * unit_V ); }
    21.  
    22.         return ( p - pos ).sqrMagnitude <= sqr_dist;
    23.     }
    24.  
    25.     //********************************************************************************
    26.     //
    27.     //********************************************************************************
    28.  
    29.     public struct EdgeHit
    30.     {
    31.         public Vector3 p;
    32.      
    33.         public EdgeHit( Vector3 param_p ) { p = param_p; }
    34.     }
    35.  
    36.     static public bool FindNearestEdges( Vector3 pos, float dist, ref List< EdgeHit > edges )
    37.     {
    38.         if( edges == null ) edges = new List< EdgeHit >( 8 );
    39.  
    40.         else                edges.Clear();
    41.  
    42.  
    43.         float   sqr_dist = dist * dist;
    44.  
    45.         Vector3 p = Vector3.zero;
    46.  
    47.         for( int e = 0, nb_edges = NAVMESH_BOUNDARIES.Count; e < nb_edges; ++e )
    48.         {
    49.             if( GetNearestPointOnEdge( pos, NAVMESH_BOUNDARIES[ e ], sqr_dist, ref p ) )
    50.             {
    51.                 edges.Add( new EdgeHit( p ) );
    52.             }
    53.         }
    54.  
    55.         return edges.Count > 0;
    56.     }
    57.  
     
    Last edited: Dec 20, 2021
    Marks_M likes this.
  15. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27
    Wow. This is phenomenal. More than I could ask for. Thank you. But, I have no idea where to even begin, like it's complicated and excellent at the same time haha..
    I'm having trouble understanding how in the world I would integrate this in the Ai script. Here is the part of the script that makes the ai flee from the player :

    Code (CSharp):
    1. case FleeMode.AwayFromNearestTaggedObject:
    2. Vector3 nearestObjectPosition = fsm.GetClosestPlayer(objectFinder.GetTransforms()).position;
    3. Vector3 fsmPosition = fsm.aiTransform.position;
    4. Vector3 direction = (fsmPosition - nearestObjectPosition).normalized * stopFleeDistance;
    5.  
    6. result = fsmPosition + direction;
    7. break;
    Lets just say if the ai reaches the corner of the map, then i would simply want Debug.Log ("message"); (Im going to get to more complicated stuff, like setting waypoints, when it's near the corner - away from it and away from player, later on). How can I go on about achieving something like that? Can you provide an example with the script I've given? Anyway, thank you alot for your help and time, Im going to put this thread on "resolved", cause, I guess, there's all I need to make things work. But as of now, can you help me with the integration?
     
    Last edited: Dec 20, 2021
  16. Serge_Billault

    Serge_Billault

    Joined:
    Aug 26, 2014
    Posts:
    190
    To integrate it you add a game object in your test scene and attach the NavMeshAnalytics to it.
    From your AI script you can call NavMeshAnalytics.IsNearCorner( this.transform.pos, <detectionradius> );
    Tweak NavMeshAnalytics accessors and change them from private to public according to your needs.
    As you become more comfortable with coding, throw away this exemple and use your own mesh analytics.
     
    Marks_M likes this.
  17. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27
    Can you please edit the script example I've given you?
     
  18. Serge_Billault

    Serge_Billault

    Joined:
    Aug 26, 2014
    Posts:
    190
    Code (CSharp):
    1.  
    2. case FleeMode.AwayFromNearestTaggedObject:
    3. Vector3 nearestObjectPosition = fsm.GetClosestPlayer(objectFinder.GetTransforms()).position;
    4. Vector3 fsmPosition = fsm.aiTransform.position;
    5. Vector3 direction = (fsmPosition - nearestObjectPosition).normalized * stopFleeDistance;
    6. result = fsmPosition + direction;
    7.  
    8. if( NavMeshAnalytics.IsNearCorner( fsmPosition, <detection radius> ) )
    9. {
    10.    Debug.Log( "Cornered" );
    11.    select a destination far from nearestObjectPosition
    12.    plot a path to reach destination
    13.    switch to RallyDestinationMode from inside your path calculation completion callback
    14. }
    15. break;
    16.  
    You calc a path with https://docs.unity3d.com/ScriptReference/AI.NavMesh.CalculatePath.html
    You assign a path to your AI with https://docs.unity3d.com/ScriptReference/AI.NavMeshAgent.SetPath.html
    You check the path calc completion with https://docs.unity3d.com/ScriptReference/AI.NavMeshPath.html and https://docs.unity3d.com/ScriptReference/AI.NavMeshPath-status.html
     
    Last edited: Dec 21, 2021
    Marks_M likes this.
  19. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27



    Serge, what is wrong with this script? Why am i getting errors:

    error CS0246: The type or namespace name 'NavMeshAnalytics' could not be found (are you missing a using directive or an assembly reference?)

    error CS0246: The type or namespace name 'NavMeshAnalytics' could not be found (are you missing a using directive or an assembly reference?)

    error CS0103: The name 'NavMeshAnalytics' does not exist in the current context



    Code (CSharp):
    1. NavMeshAnalytics navMeshAnalytics;
    2.  
    3.                     navMeshAnalytics = GameObject.FindGameObjectWithTag("Game").GetComponent<NavMeshAnalytics>();
    4.  
    5.                     if (NavMeshAnalytics.IsNearCorner(fsmPosition, 5 ))
    6.                     {
    7.                         Debug.Log("Cornered");
    8.                     }
     
  20. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27
    Never mind. Moved the NavMeshAnalytics script to the same folder as the ai flee state script. Now it works! Thank you for everything! Good luck to you.
     
  21. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27

    Serge, how can I make AI avoid the corner of the map?

    Edit : Im just at loss, I cant figure this out. I tried bunch of methods but it just doesnt work. How can I make an AI Avoid the corners of the navmesh? Please provide an example that can be used.
     
    Last edited: Dec 25, 2021
  22. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27
    The only thing I got working is something like this :

    Code (CSharp):
    1.         Vector3 fsmPosition = fsm.aiTransform.position;
    2.         Vector3 fwd = transform.TransformDirection(Vector3.back); // this
    3.  
    4.         if (NavMeshAnalytics.IsNearCorner(fsmPosition, 3))
    5.         {
    6.  
    7.             fsm.MoveAgent (fwd, movementSpeed, rotationSpeed);
    8.             Debug.DrawRay(transform.position, fwd * 10, Color.red);
    9.         }
    10.     }
    I dont like it. It works, but it's not smooth. I would like the ai to turn left or right And away from the corner, not just in straight line away from it.
     
    Last edited: Dec 25, 2021
  23. Serge_Billault

    Serge_Billault

    Joined:
    Aug 26, 2014
    Posts:
    190
    You can smooth changements of direction by interpolating between a current direction and the direction to follow.
     
    Marks_M likes this.
  24. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27
    Im trying to access Vector3 corner = NAVMESH_CORNERS[ c ]; starting position but i get the following error : error CS0122: 'c' is inaccessible due to its protection level

    I tried making it "public" but then i get bunch of other errors so it messes it all up. How can I make Vector3 corner = NAVMESH_CORNERS[ c ]; accessible to other scripts?
     
  25. Serge_Billault

    Serge_Billault

    Joined:
    Aug 26, 2014
    Posts:
    190
    NavMeshAnalytics have no member named c. So you have declared a variable of your own somewhere that you later did make public and the errors are coming from some code you added but did not post, so we cant help you.
     
    Last edited: Dec 26, 2021
    Marks_M likes this.
  26. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27
    How can I do that?
     
  27. Serge_Billault

    Serge_Billault

    Joined:
    Aug 26, 2014
    Posts:
    190
    By allowing the character direction changes only in small increments each frame using interpolation. I'm growing increasingly suspicious about your level of knowledge of Unity and programming in general, or even your intents.
     
  28. Marks_M

    Marks_M

    Joined:
    Nov 12, 2021
    Posts:
    27
    Yeah you're right. Thanks.