Hello,
I’m trying to figure out how to properly use inter-object communication in Unity. I’ve read (many times) that I should avoid using too many GetComponent calls at runtime. So I’m dealing with it basically by getting the components during Awake() and assigning what I need to variables.
However, it seems I’m doing something wrong because there are many occasions where I don’t see any other solution besides using GetComponent, even in my very simple 2D shooter.
Consider this: a Spaceship Controller script is instantiating a bullet every time the player fires (yes, I know about object pooling, I’ll do that later…), the bullet is using OnTriggerEnter2D to get whatever enemy it hits. This has to be reported to the GameManager script so the bullet script passes the object reference onwards to the GameManager. Now the GameManager has to do lots of stuff with that object, figure out what type it is, run a couple of methods attached to it, read some C# properties off it, so it has to have access to its scripts. But then I find myself using GetComponent all the time.
It’s the same if I have the “enemy” handle some of that instead of having GameManager take care of it, it just moves the problem elsewhere.
Is there a cleaner way to handling this?
e.g. my PlayerController script has this (simplified):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour {
public int RotationScaler = 5;
public int ThrustScaler = 2;
private Rigidbody2D rb;
private SpriteSwitcher spriteSwitcher;
public GameObject prefabWeaponBullet;
private Transform anchorMainGun;
void Awake()
{
rb = GetComponent<Rigidbody2D>();
spriteSwitcher = GetComponentInChildren<SpriteSwitcher>();
anchorMainGun = transform.Find("AnchorMainGun");
}
void FixedUpdate ()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Instantiate(prefabWeaponBullet, anchorMainGun.position, transform.rotation);
}
}
}
The bullet script has this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeaponBullet : MonoBehaviour {
public float speed = 1.0f;
private Rigidbody2D rb;
private GameManager gameManager;
void Awake()
{
// Get the Rigidbody2D when instantiated
rb = (Rigidbody2D)GetComponent(typeof(Rigidbody2D));
gameManager = FindObjectOfType<GameManager>();
}
void Start ()
{
// Add forward impulse
rb.AddRelativeForce(Vector2.up * speed * 10, ForceMode2D.Impulse);
}
void FixedUpdate()
{
// Destroy if left the screen
Vector3 positionVP = Camera.main.WorldToViewportPoint(transform.position);
if (positionVP.x > 1.0 || positionVP.x < 0 || positionVP.y > 1.0 || positionVP.y < 0)
{
Destroy(gameObject);
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "Asteroid")
{
gameManager.HitAsteroid(collision.gameObject);
Destroy(gameObject);
}
}
}
And the mess in the GameManager looks likes this for now:
public void HitAsteroid(GameObject go)
{
// Get phase of destroyed asteroid
int phase = go.GetComponent<AsteroidController>().Phase;
if (phase < 3)
{
SpawnAsteroid(go.transform.position, phase + 1);
SpawnAsteroid(go.transform.position, phase + 1);
}
Destroy(go);
}
private void SpawnAsteroid(Vector2 pos, int phase)
{
float x = Random.Range(pos.x - 0.5f, pos.x + 0.5f);
float y = Random.Range(pos.y - 0.5f, pos.y + 0.5f);
float rot = Random.Range(0f, 1f);
GameObject ast = Instantiate(pfAsteroid, new Vector2(x, y), new Quaternion(0, 0, rot, 0));
AsteroidController astController = ast.GetComponent(typeof(AsteroidController)) as AsteroidController;
astController.Phase = phase;
Rigidbody2D rb = ast.GetComponent(typeof(Rigidbody2D)) as Rigidbody2D;
float dirX = Random.Range(-1f, 1f);
float dirY = Random.Range(-1f, 1f);
rb.AddRelativeForce(new Vector2(dirX, dirY) * 20 * phase, ForceMode2D.Force);
rb.AddTorque(Random.Range(-10, 10), ForceMode2D.Force);
}
Thanks a lot.