Search Unity

trying to do raycast-based 2d pathfinding (and failing so far...)

Discussion in 'Scripting' started by sh_code, Sep 24, 2015.

  1. sh_code

    sh_code

    Joined:
    Apr 8, 2015
    Posts:
    17
    Hi. So, unity project preset to 2d (stupid, stupid, should've done 3d preset and oriented everything along x and z, throw in NavMesh and be done with it, but i wanted to have a bit of training). First, please, no answers like "why reinvent the wheel?" and links to A* or other stuff, I'd love to get this solution of mine working...

    Secondly, the logic is supposed to go roughly like this:
    (agent-enemy has CircleCollider2D, walls are BoxCollider2D)
    1. cast a ray from current position to player
    2. if it hits nothing, add the end point as a waypoint, and we're done. if it hits a wall, add a point next to the wall to list of waypoints, then (recursively, by calling the function again) go along the wall to where its collider ends, add that point as another waypoint, and (again, by calling itself recursively) cast a ray from that point to the player.

    But, instead of pathing around the wall's collider, it flawlessly paths INTO the center of the collider...

    My (not yet complete, but the gist is there) code is this:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System;
    5.  
    6. public class EnemyNavigator : MonoBehaviour {
    7.     Transform player;
    8.     Vector3 targetPosition;
    9.     Vector3 targetShot;
    10.     public float rotationSpeed = 0.3f;
    11.     public int maxPathfindIterations = 30;
    12.     private List<Vector3> path;
    13.  
    14.     // Use this for initialization
    15.     void Start () {
    16.         player = GameObject.FindGameObjectWithTag("Player").transform;
    17.     }
    18.    
    19.     public bool PathfindTowards(Vector3 position)
    20.     {
    21.         path = PathfindTowardsRecursive(position, null, 0);
    22.         if (path == null) return false; else return true;
    23.     }
    24.  
    25.     private List<Vector3> PathfindTowardsRecursive(Vector3 position, Nullable<Vector3> from, int iteration=0){
    26.         if (iteration > maxPathfindIterations) return null;
    27.  
    28.         Debug.Log("PF(" + iteration + "): iteration: " + iteration);
    29.         //raycast towards position, if collides, store collision point as path point, and raycast within range along the possible direction
    30.         RaycastHit2D rh, rh2;
    31.         Vector3 newPoint;
    32.  
    33.         List<Vector3> localPath = new List<Vector3>();
    34.  
    35.         if(!from.HasValue) from = transform.position;
    36.         //rh = Physics2D.Raycast(from.Value, position - from.Value);
    37.         rh = Physics2D.CircleCast(from.Value, 1, position - from.Value);
    38.  
    39.         Debug.Log("PF(" + iteration + "): from: " + from.Value);
    40.  
    41.         if (rh.collider != null)
    42.         {
    43.             Debug.Log("PF(" + iteration + "): colPoint: " + rh.point);
    44.             localPath.Add(rh.centroid);
    45.             Debug.DrawLine(from.Value, (Vector3)rh.point, Color.blue, 10);
    46.  
    47.             float newTargetX, newTargetY;
    48.  
    49. //this is incomplete, handles/should handle only a case of vertical wall between enemy and player yet
    50.             if (transform.position.y > position.y) newTargetY = rh.collider.bounds.min.y - transform.lossyScale.y / 2;
    51.             else newTargetY = rh.collider.bounds.max.y + transform.lossyScale.y / 2;
    52.  
    53.             if (Mathf.Abs(transform.position.x - rh.collider.bounds.max.x) < Mathf.Abs(transform.position.x - rh.collider.bounds.min.x))
    54.                 newTargetX = rh.collider.bounds.max.x + transform.lossyScale.x / 2;
    55.             else
    56.                 newTargetX = rh.collider.bounds.min.x - transform.lossyScale.x / 2;
    57. //end of the incomplete part handling only vertical wall
    58.  
    59.             localPath.AddRange(PathfindTowardsRecursive(new Vector3(newTargetX, newTargetY, 0), rh.point, iteration+1));
    60.         }
    61.         else
    62.         {
    63.             localPath.Add(position);
    64.         }
    65.  
    66.         Debug.Log("PF-END(" + iteration + "): iteration: " + iteration);
    67.  
    68.         return localPath;
    69.     }
    70. }
    71.  
    Any ideas where and why I'm stupid? Thanks :)
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    I tried it out and with a simple scene setup it digs about 30 levels deep into recursion, then there is a complaint from c# about some collection identifier being null.

    See attached scene. Something is fishy... not sure if I set it up properly, but I took a whack at it...
     

    Attached Files:

  3. sh_code

    sh_code

    Joined:
    Apr 8, 2015
    Posts:
    17
    yeah, should've attached the scene from the start... the exception is from trying to AddRange(null), where the return from recursion call is. when it hits the 30 level depth limit, function just returns null (it's the first line in it), and i wasn't checking for that.

    still not working, but ...progress! unfortunately it's 3AM here, and i've been modifying the older code in your scene, at the same time as the current code in my project, where i did some more changes while waiting for the answer, so... i'm not exactly able to tell all the changes, and copypasting the whole function to your scene has different results than in my project, and what the hell...

    basically, I've got closer to it working correctly, but I can't tell you why and I'm sorry, but thank you very much for pointing out that stupid mistake and making me to look at it again so I made this progress. consider myself helped and the question answered :)
     
  4. sh_code

    sh_code

    Joined:
    Apr 8, 2015
    Posts:
    17
    p.s. currently in my project it goes 3 levels deep (as it should, with my obstacle setup) and only bugs out at the position of last waypoint, copying the whole function to your scene makes the rays bounce around inside the collider... oh... Physics2D has a setting "Queries start in colliders", which defaults to true, and in my project it's false, that's why in your scene the same code (with many corrections, as i said) bugs out while in mine it works almost correctly.

    I'll try to post the scene working after I get some sleep, so that we can both enjoy the goodfeels from having solved it ;)
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    I look forward to this! Sleep tight.