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?