5
\$\begingroup\$

I've been trying to implement this steering behavior in Unity: Understanding Steering Behaviors: Collision Avoidance

However, I'm getting strange results. Here's the code for the script, feel free to suggest better ways to code some things..

#pragma strict
#pragma downcast

public var test: boolean;

private var stop:boolean;

private var vel: Vector3; //Velocity
private var qa: Vector3;
private var ahead: Vector3; //Ahead vector - A point in front of this unit
private var ahead2: Vector3; // Shorter Ahead Vector - Used for detecting closer objects


private var spwnScript    : EnemySpawner_2; //Reference to script of Spawner
private var otherColliderLst: List.<SphereCollider>; //Should holds reference to variable of other script's (spawner) collider list.
private var otherCollider   : SphereCollider; // Used to store individual colliders from list
private var ownCollider   : SphereCollider;
private var closestCollider  : SphereCollider;
private var spwnObj : GameObject;

//Steering Behavior Variables 
private var steering : Vector3; //Variable used to add to the velocity, and to have other behaviors assigned to it.
private var avoidance_frc : Vector3; //Avoidance Force
private var isCollision : boolean;


//CONSTANTS
private var MAX_QUEUE_ahead: float; 
private var MAX_AVOID_FRC: float;

private var speed:float = 70;
private var damage:int = 25;

function Awake()
{
    //Destroy(gameObject, 3);
    MAX_AVOID_FRC = 2f;
    MAX_QUEUE_ahead = 30f;
    stop = false;
    steering = Vector3(0f,0f,0f);
    otherCollider = null;
    ownCollider = gameObject.GetComponent("SphereCollider") as SphereCollider;

    spwnObj        = GameObject.Find("EnemySpawn_2").gameObject;
    spwnScript     = spwnObj.GetComponent(EnemySpawner_2);
    otherColliderLst = spwnScript.colliderList;
}

function Start () 
{
    //GameObject.Find("EnemySpawner_2").transform.GetComponent("EnemySpawner_2");

    yield WaitForSeconds(Random.Range(1f, 1.3f));
    stop = true;
}

function Update () {

    if(!stop){
        vel = Vector3(0,0,-speed * Time.deltaTime);
        steering += collisionAvoidance();

        Debug.Log(steering);
        vel += steering;

        transform.Translate(vel);
    }
}


function OnCollisionEnter(col:Collision)
{
    if(col.gameObject.tag == "Player")
    {
        yield WaitForSeconds(.1); //So that bullets seems to have an effect when they touch a part of the ship, instead of an invisible box
        NotificationCenter.DefaultCenter().PostNotification(this, "PlayerHit",damage);
        //playerScript.ReceiveDamage(damage);
        Destroy(gameObject);
    }
}

// Functions used by Steering Behaviors //
/////////////////////////////////////////

private function collisionAvoidance() : Vector3 {

    qa = vel.normalized * MAX_QUEUE_ahead; 
    ahead = qa + transform.position;
    ahead2 = qa * 0.5f + transform.position;

    otherCollider = findNextClosestSphere() ;

    avoidance_frc = Vector3(0f,0f,0f);

    if(otherCollider != null) {
        avoidance_frc.x = ahead.x - otherCollider.transform.position.x;
        avoidance_frc.y = ahead.y - otherCollider.transform.position.y;
        avoidance_frc.z = ahead.z - otherCollider.transform.position.z;

        Debug.Log("AVOID"+avoidance_frc);
        avoidance_frc.Normalize();
        avoidance_frc.Scale(Vector3(MAX_AVOID_FRC, MAX_AVOID_FRC, MAX_AVOID_FRC));
    }
    else{
        avoidance_frc.Scale(Vector3(0f, 0f, 0f)); // nullifty the avoidance force
    }
    return avoidance_frc;
}

private function findNextClosestSphere() : SphereCollider {

    closestCollider = null;

    for(var i:int = 0; i < otherColliderLst.Count; i++)
    {
        if(otherColliderLst[i].transform.position != ownCollider.transform.position)
        {
            otherCollider = otherColliderLst[i];
            isCollision = lineIntersectsSphere(ahead, ahead2, otherCollider);

            if(isCollision && (closestCollider == null || distance(gameObject.transform.position, otherCollider.transform.position) < distance(gameObject.transform.position, closestCollider.transform.position))) {
                closestCollider = otherCollider; 
            }
        }
    }

    //Set Sphere Collider

    //For readability purposes, the function returns back a vector. 
    //An alternative, would be for the function to simply set the value of the otherCollider variable
    //and not return anything.
    //The variable sits outside any function, and can be used anywhere in the script.

    return closestCollider;
}

private function distance(a:Vector3, b:Vector3){
    return Mathf.Sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y)*(a.y - b.y) + (a.z - b.z) * (a.z - b.z));
}

private function lineIntersectsSphere(ahd:Vector3, ahd2:Vector3, sphCol:SphereCollider) : boolean
{   
    return distance(sphCol.transform.position, ahd) <= sphCol.radius || distance(sphCol.transform.position, ahd2) <= sphCol.radius;
}

I have another script titled EnemySpawner_2, which is attached to a gameobject in the scene, and is responsible for spawning and saving spheres to a list, which can be accessed by the above script with the otherColliderLst variable.

Now the issue is that the enemies that spawn, do NOT actually do any collision avoidance at all. Rather, they spawn one by one, from the same area, and they rush in the same direction (on one axis) towards the nearest enemy that is detected. I'm trying to understand why this behavior is happening. I realized that part of the problem is that not all axes have values in the avoidance_frc variable at the end collisionAvoidance() so the force is only applied to one axis, when it should be done in two, which is the z AND the x axis (The axis that currently contains no value).

But I don't understand how the code does not run into these issues in the other tutorial. I've basically done a Unity copy of the code and have been debugging for this for hours.. what have I done wrong?

\$\endgroup\$
  • \$\begingroup\$ What does "otherCollider" display when logged? Also, what does "otherColliderLst.Count" display when logged? I am guessing the issue might relate to one of those two things - either no colliders are attached or that othercolliderlist is not properly being added to. \$\endgroup\$ – return true Feb 3 '15 at 10:54
  • \$\begingroup\$ Could you elaborate what part is problematic and how you translated from AS3 to Unity? It may have gone wrong there. \$\endgroup\$ – Mast Mar 5 '15 at 10:31
0
\$\begingroup\$

How do you assign the enemy "Find Target" behavior? Maybe I missed it, haven't had my coffee yet, but I only see the collision avoidance behavior added. Steering behaviors relies on forces and take advantage of the properties of vector operations. If you, for example, give a (1,0,0) steering force towards a target ad a (0,0.5,0) force to avoid an obstacle, the entity will have a total velocity of (-, 0.5, 0).

On the other hand, if you assign the velocity elsewhere to make the entity walk towards a target, make sure it doesn't override the steering forces.

Also, have you tried to Gizmo.DrawLine on the steering forces to check that the avoidance force isn't just too weak? You should weight and truncate the forces for a proper behavior.

\$\endgroup\$
  • \$\begingroup\$ Not sure what you mean by Find Target beehavior, the Collision avoidance in my example works with spheres acessed from another script. The script above is attached to enemies. Steering Behaviors are commonly implemented as separate scripts and then attached to the enemy, correct? The Collision Avoidance is the only steering behavior I've been working on, trying to take it one step at a time. Haven't heard of Gizmo.DrawLine.. but Ive been looking for ways to make the vectors visible.. how would that be implemented in the script? \$\endgroup\$ – GelatinFox Aug 7 '14 at 5:35
  • \$\begingroup\$ I think @Alessio's point is that you need to have "find target" behavior for any kind of steering to work. \$\endgroup\$ – Alex F Apr 26 at 14:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.