Hey all,
I was looking at one of my “finished” scripts to add a new feature to it and I noticed something that I did which may be considered poor practice and because I’ve probably done it with several scripts, I’d like to know what you guys/gals think.
Basically, there are certain objects that have references to other objects that, once the referenced object is destroyed, something happens. For example, my remote bombs have a reference to the player who deployed them: player 1 or player 2 (this is a local two-player versus game). Player 1 deploys red remote bombs and player 2 deploys blue. When a player dies, however, they lose ownership over their remote bombs. The way that it has worked since I introduced the remote bomb power-up is that these remote bombs become neutral (animated with red and blue colours) indicating that either player can detonate them. In most cases, players will immediately detonate their remote bombs as soon as they become neutral, so it’s usually not very interesting. Instead, I’d like to swap ownership.
Here is the remote bomb script:
using UnityEngine;
using System.Collections;
public class RemoteBombScript : BombScript
{
public bool neutral = true; // is this bomb controlled by a player? If not, neutral is true.
private int playerNum = 1; // the playerNum of the player that threw this bomb. Default is 1. It would be zero, but that might cause errors with the Input Manager.
private PlayerController playerController; // a reference to the player's PlayerController script (to avoid repeated GetComponent calls)
protected override void SetUpBomb()
{
hazardName = "remote";
throwPower = new Vector2 (10, 10);
neutralThrowAngle = new Vector2(1, 0);
yHop = 0; // how much y-velocity is added when this bomb is hit with a melee attack
blastPower = 100;
anim = GetComponent<Animator>();
}
public override void Start()
{
base.Start();
if (transform.parent && transform.parent.gameObject.GetComponent<PlayerController>())
{
playerController = transform.parent.gameObject.GetComponent<PlayerController>();
playerNum = playerController.playerNum;
anim.SetInteger("player", playerNum);
neutral = false;
}
else
SetNeutral();
}
// Update is called once per frame
override public void Update ()
{
// if there is no reference to the player who threw this (or there was no such player; it came from an exploded crate)...
if (Time.timeScale != 0)
{
if (!player && !exploded)
{
if (!neutral)
SetNeutral();
if (Input.GetButtonDown("Circle_1") || Input.GetButtonDown("Circle_2"))
StartCoroutine(Explode ());
}
else
{
if (Input.GetButtonDown("Circle_" + playerNum) && !exploded && thrown)
StartCoroutine(Explode ());
}
}
}
public override void Cook(GameObject p = null)
{
sprite.enabled = true;
if (p)
player = p;
}
public override void Throw(Vector2 aimdir)
{
base.Throw(aimdir);
anim.SetBool("thrown", thrown);
GetComponent<Rigidbody2D>().AddTorque(20 * -Mathf.Sign(GetComponent<Rigidbody2D>().velocity.x)); // add a bit of a spin
// Play looping "beep" sound effect !!!
}
// deploy this bomb wihout applying any throwing force
public override void Drop()
{
try
{
if (bombCollider)
{
bombCollider.enabled = true;
}
if (body)
body.isKinematic = false;
GetComponent<Rigidbody2D>().velocity = Vector2.up * -1;
if (transform.parent)
{
transform.parent = null;
transform.localScale = new Vector3(1,1,1);
}
transform.rotation = Quaternion.Euler(new Vector3(0, 0, Mathf.Atan2(GetComponent<Rigidbody2D>().velocity.y, GetComponent<Rigidbody2D>().velocity.x) * Mathf.Rad2Deg));
thrown = true;
justThrown = true;
StartCoroutine(TransitionFromJustThrown());
anim.SetBool("thrown", thrown);
GetComponent<Rigidbody2D>().AddTorque(20f);
}
catch (UnityException e)
{
Debug.Log (e.Message);
}
}
public override void TakeExplosionDamage(Vector2 dir, int dmg, BombScript explosionSource)
{
// remote bombs do not explode from other bombs, instead they are knocked around.
GetComponent<Rigidbody2D>().AddForce(dir * dmg * 7);
}
private void SetNeutral()
{
playerController = null;
anim.SetInteger("player", 0);
neutral = true;
}
private void SwitchOwnership()
{
// Not sure what the best way to find the other player is. Could use FindObjectWithTag.
}
}
As you can see, the update function is constantly checking to see if its player reference is null. I really don’t know how expensive/wasteful this is. Stages that have remote bomb power-up crates generally have less than four remote bombs on the stage at once, and my game’s performance has never lead me to believe this has been harmful in this case. This is just the best example I have for my general question about checking for null object references.
Thanks for reading.
PS: I know it’s ugly, but it works for now.