okay, so this isn’t the usual newbie forgetting to put stuff in the inspector(although i often do, haha)
my problem is this, i have enemies that hunt down the player and his base, the base is made out of blocks that the player builds, they can be destroyed either by the player interacting with the build/destroy menu or by taking damage(like all other IDamageable interface stuff in the game)
the problem is this, when an enemy is tracking a block and the block gets destroyed, the enemy script seems to go wonky, i’m clearly checking if it’s null 3 line before the error occurs so my first guess is that the object was destroyed by another thing between those lines, by sadly this isn’t this simple, for starters i use Destroy and not DestroyImmediate, second is even if that’s the case, the error keeps on happening, spamming the log and the enemy freezes while all else plays the same.
am i missing something that happens with a ref. to an interface instead an any “normal” script, mb or not?
this is the part of the enemy script getting the error, the strafe part doesn’t really have anything to do with it.
public class Mob_Flying : MonoBehaviour, IDamageable, Ipool {
Rigidbody rb;
IDamageable target;
[SerializeField]GameObject destroyedPrefab;
public bool active{ get; private set; }
float health;
//bool engaged = false;
bool strafe = false;
Vector3 wantedPosition;//target position
Quaternion wantedRotation;
bool move = false;
bool stop = false;
[SerializeField]float maxHealth = 100;
[SerializeField]float detectionRange = 350f;
[SerializeField]float shootingRange = 75f;
[SerializeField]float attackBubble = 250f;
[SerializeField]float rotSpeed = 2;
[SerializeField]float speed = 10;
[SerializeField]float explosionStr = 250f;
[SerializeField]float explosionSize = 10f;
[SerializeField]float DPS = 10;
[SerializeField]float maxFiringAngle = 3f;
AudioSource audioS;
LineRenderer lazer;
float crashCheckDis = 30;
[SerializeField]List<RayDir>Rays = new List<RayDir>();
[SerializeField]LayerMask enemyLM;
public Transform _transform{ get { return transform; } }
float sqrShootingRange { get { return shootingRange * shootingRange; } }//TODO maybe cache this?
Vector3 AttackBubble(){
return new Vector3 (Random.Range (-attackBubble, attackBubble), attackBubble, Random.Range (-attackBubble, attackBubble));
}
void Update(){
if (active == false || GameMaster.instance.paused)
return;
if (target != null) { //attack target
if (strafe) {
wantedPosition = target._transform.position;
move = true;
float sqrDist = (transform.position - wantedPosition).sqrMagnitude;
if (sqrDist < sqrShootingRange) {//target below min range
wantedPosition = target._transform.position + AttackBubble ();
strafe = false;
lazer.enabled = false;
audioS.Stop ();
} else if (sqrDist < sqrShootingRange * 2) {//target below max range
ShootLazer ();
}
} else {//hover around target
if (Vector3.Distance (transform.position, wantedPosition) < crashCheckDis) {
if (CanSeeTarget()) {
strafe = true;
} else {
wantedPosition = target._transform.position + AttackBubble ();
}
}
move = true;
}
wantedRotation = Quaternion.LookRotation (wantedPosition - transform.position);
} else { //move toward cented
target = Scan ();
wantedPosition = (target == null) ? Vector3.up * 10 : target._transform.position + AttackBubble (); //TODO replace ve3.up with highest hex in center
wantedRotation = Quaternion.LookRotation (wantedPosition - transform.position);
move = true;
}
//Movement & collision detection
Quaternion offset = rb.rotation;
foreach (RayDir ray in Rays) {
if (Physics.Raycast (ray.rayDirection.position, ray.rayDirection.forward, crashCheckDis)) {
offset *= Quaternion.LookRotation (ray.offsetDirection);
Debug.DrawRay (ray.rayDirection.position, ray.rayDirection.forward * crashCheckDis, Color.red);
} else {
Debug.DrawRay (ray.rayDirection.position, ray.rayDirection.forward * crashCheckDis, Color.cyan);
}
}
if (Physics.Raycast (transform.position, transform.forward, crashCheckDis / 2))
stop = true;
rb.rotation = Quaternion.Slerp (rb.rotation, (offset == rb.rotation) ? wantedRotation : offset, rotSpeed * 2 * Time.deltaTime);
}
IDamageable Scan () { // Returns first enemy found
Collider[] cols = Physics.OverlapSphere (transform.position, detectionRange, enemyLM);
RaycastHit hit;
for (int i = 0; i < cols.Length; i++) {
hit = new RaycastHit ();
IDamageable id = cols[i].gameObject.GetComponentInParent<IDamageable>();
if (id != null && Physics.Raycast (transform.position, cols [i].transform.position - transform.position, out hit, detectionRange) && hit.collider == cols [i])
return id;
}
return null;
}
/*IDamageable[] Scan () { // Returns all enemies in sight
Collider[] cols = Physics.OverlapSphere (transform.position, detectionRange, enemyLM);
List<IDamageable> ids = new List<IDamageable> ();
RaycastHit hit;
for (int i = 0; i < cols.Length; i++) {
hit = new RaycastHit ();
IDamageable id = cols[i].gameObject.GetComponentInParent<IDamageable>();
if (id != null && Physics.Raycast (transform.position, cols[i].transform.position - transform.position, out hit, detectionRange) && hit.collider == cols[i])
ids.Add (id);
}
if (ids.Count > 0)
return ids.ToArray ();
else
return null;
}*/
bool CanSeeTarget(){
RaycastHit hit;
Physics.Raycast (transform.position, target._transform.position - transform.position, out hit, detectionRange);
if (hit.rigidbody != null && hit.rigidbody.transform == target._transform)
return true;
else
return false;
}
void FixedUpdate(){
if (stop)
rb.drag = 35;
else
rb.drag = 1;
if (move && !stop)
rb.AddForce (transform.forward.normalized * speed * Time.timeScale, ForceMode.Impulse);
move = false;
stop = false;
}
void ShootLazer(){
if (Mathf.Abs (Vector3.Angle (lazer.transform.forward, target._transform.position - lazer.transform.position)) < maxFiringAngle && CanSeeTarget ()) {
if (!audioS.isPlaying)
audioS.Play ();
lazer.enabled = true;
lazer.SetPosition (0, transform.position);
lazer.SetPosition (1, target._transform.position);
target.GetDamage (new HitInfo(DPS*Time.deltaTime,this.gameObject));
} else{
//lazer.SetPosition (0, Vector3.zero);
audioS.Stop ();
lazer.enabled = false;
}
}
public void GetDamage (HitInfo hit){
if (active) {
health -= hit.damage;
if (health <= 0) {
Die ();
} else if (hit.attacker != null) {
//attack back
IDamageable id = hit.attacker.GetComponent<IDamageable> ();
if (id != null) {
strafe = true;
target = id;
}
}
}
}
public void Ini (){
active = false;
rb = GetComponent<Rigidbody> ();
audioS = GetComponent<AudioSource> ();
lazer = GetComponentInChildren<LineRenderer> ();
gameObject.SetActive (false);
}
public void SpawnObj (Vector3 pos){
target = null;
health = maxHealth;
transform.position = pos + (Vector3.up * 350);
transform.rotation = Quaternion.LookRotation (Vector3.up);
wantedPosition = Vector3.up * 10;
wantedRotation = transform.rotation;
active = true;
}
void OnCollisionEnter(Collision col){
if (col.relativeVelocity.sqrMagnitude > 75)
GetDamage (new HitInfo (col.relativeVelocity.magnitude));
}
void Die(){
//Debug.Log ("Enemy dead " + Time.time);
active = false;
Wreck w = PoolManager.instance.Spawn (destroyedPrefab, transform.position).GetComponent<Wreck>();
w.SetRotation (rb.rotation, rb.angularVelocity);
w.SetVelocity (rb.velocity);
Explode ();
gameObject.SetActive (false);
}
void Explode(){
Collider[] trgs = Physics.OverlapSphere (transform.position, explosionSize);
foreach (Collider col in trgs) {
IDamageable id = col.GetComponentInParent<IDamageable> ();
if (id != null) {
float dis = Vector3.Distance (transform.position, col.transform.position);
if (dis < 1)
id.GetDamage (new HitInfo (explosionStr));
else
id.GetDamage (new HitInfo (explosionStr / dis));
}
}
Collider[] cols = Physics.OverlapSphere (transform.position, explosionSize);
Vector3 t = new Vector3 (Random.Range (-explosionStr, explosionStr), Random.Range (-explosionStr, explosionStr), Random.Range (-explosionStr, explosionStr));
foreach (Collider col in cols) {
if (col.attachedRigidbody != null) {
col.attachedRigidbody.AddExplosionForce (explosionStr, transform.position, 25, 0, ForceMode.Impulse);
col.attachedRigidbody.AddTorque (t,ForceMode.Impulse);
}
}
}
}
this is the way i destroy the game object, please tell me if i’m wrong
this is the script attached to the GameObject
public class HexRep : MonoBehaviour, IDamageable {
bool active;
float health;
[SerializeField]float maxHealth;
public Transform _transform{ get { return transform; } }//Part of IDamageable
public Hex myHex;
void Start(){
health = maxHealth;
active = true;
}
public void GetDamage(HitInfo hi){ //Part of IDamageable
health -= hi.damage;
if (health < 0 && active)
Die ();
}
void Die(){
active = false;
MapMaster.instance.RemoveHex (myHex);
}
}
and this is the MapMaster RemoveHex function:
public void RemoveHex(Hex hex){
if (hex == null) {
Debug.LogError ("No hex to destroy!");
return;
}
if (hexes.ContainsKey (hex.coord) == false) {
Debug.LogError ("Hex at: " + hex.coord.ToString() + " isn't registered!");
return;
}
Destroy (hex.rep.gameObject);
hex.rep = null;
hexes.Remove (hex.coord);
}