- Home /
Reactivating a GameObject that was deactivated from another script
Hi all, I am making a game which uses power ups. The game is based off the unity tutorial - survival shooter. I've added in a power up which changes the appearance, damage, lighting of the gun bullets by deactivating the regular bullet component 'GunBarrelEnd' and activating 'SuperGunBarrelEnd'. This works perfectly when the powerup object (a cube with a script attached to it) is activated. The script attached to the cube tells unity to disable the 'SuperGunBarrelEnd' unless the player collides with the cube. It then deactivates the regular barrel end and activates the super one for a set period of time. However, when the cube object with the script attached is not active in the game, the gun shoots both types of bullets at once (as there is nothing to deactivate 'SuperGunBarrelEnd'. I am trying to tell unity to deactivate the super bullets unless the cube with the script attached is active in the game. I've done this by attaching the following code to void Update in another script that is always active in the game:
SuperGun = GameObject.FindWithTag ("SuperGun");
void Update ()
{
if (GameObject.FindGameObjectWithTag ("PickupGun") == null) {
SuperGun.SetActive (false);
}
else
{
SuperGun.SetActive(true);
}
This successfully deactivates the super bullets when the cube 'PickupGun' isn't present in the game but when it is activated, the original script is no longer able to activate the 'SuperGunBarrelEnd' component. I've tried multiple ways of getting around this but can't find a solution to it. Am I perhaps using void Update wrong? The code that manages the powerup (attached to the cube) is also below incase this gives any clue as to what is going on. Any help would be really appreciated, thanks!
public class BulletPickup : MonoBehaviour {
private Renderer rend;
private BoxCollider coll;
private Light light;
private GameObject StandardGun;
private GameObject SuperGun;
private GameObject player;
void Start()
{
rend = GetComponent<Renderer> ();
coll = GetComponent<BoxCollider> ();
light = GetComponent<Light> ();
StandardGun = GameObject.FindWithTag("StandardGun");
SuperGun = GameObject.FindWithTag("SuperGun");
SuperGun.SetActive(false);
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
AudioSource audio = GetComponent<AudioSource>();
audio.Play();
rend.enabled = false;
coll.enabled = false;
light.enabled = false;
StandardGun.SetActive(false);
SuperGun.SetActive(true);
StartCoroutine (DeactivateSuper ());
}
}
IEnumerator DeactivateSuper()
{
yield return new WaitForSeconds (10);
StandardGun.SetActive (true);
SuperGun.SetActive (false);
}
}
Answer by Daemonhahn · Nov 09, 2017 at 11:52 AM
Why not have one gun start as disabled and the other start as active (the one they are meant to start with).
When you enable one, disable the other, and vice versa. As long as for the two guns one of them starts disabled and one enabled, then it will always work.
You could use a method like this:
void EnableGuns(bool super)
{
if(super)
{
SuperGun.SetActive(true);
StandardGun.SetActive(false);
}
else
{
SuperGun.SetActive(false);
StandardGun.SetActive(true);
}
}
also don't use a co-routine.
Instead use a timer, something like this:
float timer = 0f;
public float timerInterval; // set this to whatever you want in the inspector
void Update()
{
if(timer > 0f)
{
if(!SuperGun.isActiveInHeirarchy) EnableGuns(true);
timer += Time.deltaTime;
if(timer <= 0)
{
// disable gun here as powerup has run out
EnableGuns(false);
}
}
}
Then when you want the powerup, just set the timer to a number such as 5. It will then count down and the power will last for 5 seconds. you can use the public timerInterval variable as this value if you want.
This is a cleaner better way to do this. P.S my code was done off by heart, I haven't checked it in an editor so there will be errors so do not copy and paste
' EDIT: Example usage, if you wanted to start the powerup:
void StartPowerup(float secondsActive)
{
timer = secondsActive;
}
Thanks for the response! That did occur to me but I've actually got two versions of the super gun (so three bullet types), I don't think a boolean would work? (I didn't mention the third gun barrel end originally to simplify things!). The third gun barrel end works exactly the same besides different effects. As for the float timer over the co-routine, what's the advantage of this? Is it less resource intensive?
Co-routines do not necessarily stop or start when you expect them to, and they can interact with each other in weird ways or even stall / not finish.
They are simply not dependable, we have a major client project that we have mainly used co-routines in for over a year and we are having to change the entire project to take them out due to unforeseen errors linked to them.
As for the Boolean, that's fine just make an enum:
public enum GunType
{
standard,
super1,
super2
}
public GunType type;
then set the type to whatever you want at start, and pass that into the change gun method ins$$anonymous$$d:
void EnableGuns(GunType type)
{
if(type == GunType.standard)
{
SuperGun.SetActive(false);
StandardGun.SetActive(true);
SuperGun2.SetActive(false);
}
else if(type == GunType.super1)
{
SuperGun.SetActive(false);
StandardGun.SetActive(true);
SuperGun2.SetActive(false);
}
else if(type == GunType.super2)
{
SuperGun.SetActive(false);
SuperGun2.SetActive(true);
StandardGun.SetActive(false);
}
}
etc etc
Please select my answer as the correct one if I have been helpful! :)
Answer by Harinezumi · Nov 09, 2017 at 12:33 PM
I think you have an organization problem (instead of a programming problem).
First off, please don't use GameObject.FindGameObjectWithTag() in Update(), it is a relatively slow operation and calling it on every frame within Update() is not recommended. Instead you could put a script on the PickUpGun object that deactivates all SuperGuns when it gets created.
What I would do is that the player would have the StandardGun and the SuperGun already attached, and let the script on the player control what is active. For example, BulletPickup.OnCollisionEnter() could look for a Player component, and tell it to Player.ActivateSuperGun(). This would do the switch and start a timer in Player (btw, in my opinion using coroutines for this is fine), and at the end it would switch back.
Maybe I didn't catch all the details of the issue, but I think this would work.
Thanks for the response. I think I'm nearly there using Daemonhahn's method but I do appreciate the help! Incidentally, I was having a problem with spawning enemies in another script. I had three GameObject.FindGameObjectWithTag() operations running in my Update function that is designed to check if there are any active enemies in the level (it stops spawning when it finds an enemy present. This lead to a huge number of enemies being spawned. Reading what you've said suggests to me that the find with tag is slowing down the update function meaning that a large number of enemies are spawned before update has had chance to stop them. Does that make sense? Can you suggest there a more efficient means of finding the enemy game objects?
Not sure that that does make sense, no. Your Update function will be running on the same thread as the spawning code, so the former being slow wouldn't normally mean there's more time for the latter.
I'd recommend getting rid of the Find calls entirely. Your collection of enemies should only change when they're created or destroyed (or maybe when they change state in some other way), right? So maintain a list yourself and change it as required. $$anonymous$$ost people would probably put this into some kind of enemymanager class that handles the spawning/destroying as well as maintaining the collection.
Apologies, it's been a long day haha! I've changed my code to get rid of the find with tags but am still getting an endless stream of enemies spawning. I'm sure there's something simple that's causing it but I'm struggling to see it!
Your answer
Follow this Question
Related Questions
Deactivate an object - and all scripts in that object deactivated? 1 Answer
Vehicle Enter Script Errors HELP! 0 Answers
How to activate/deactivate a component(Animator) when a specific game object was activated 0 Answers
Sharing components amongst different gameobjects 1 Answer
How to trigger udpate in editor mode only when I modify component parameters 1 Answer