Is there a way to check if a GameObject has been destroyed? - c#

I'm creating a game and i want to show a panel when the player is dead
I've tried different approaches but none seems to do what I want
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DeadOrAlive : MonoBehaviour
{
public GameObject Player;
public GameObject deadPanel;
void Update()
{
if (!GameObject.FindWithTag("Player"))
{
deadPanel.SetActive(true);
}
}
}

To check if a object has been destroyed, you should use MonoBehavior's OnDestroy like so:
// Attach this script to the player object
public class DeadOrAlive : MonoBehaviour
{
public GameObject deadPanel;
void OnDestroy()
{
deadPanel.SetActive(true);
}
}
You can also instead of destroying the player object, set it to active/inactive, but to check if the player is dead or alive this way, you will need a separate object which checks the active state:
//Attach this to a object which isn't a child of the player, maybe a dummy object called "PlayerMonitor" which is always active
public class DeadOrAlive : MonoBehaviour
{
public GameObject deadPanel;
void Update()
{
if (!GameObject.FindWithTag("Player"))
{
deadPanel.SetActive(true);
}
}
}
Haven't used unity in a while and forgot how weird it could get.

Thanks to #VincentBree this is how I did it
void Update()
{
if (!Player.activeSelf)
{
deadPanel.SetActive(true);
}
}

Related

Unity 2D: Making the Player Gameobject Reactivate after being turned off

I can't get the Player Gameobject to reappear. The player deactivates the moment the Timeline starts when they touch the box collider, but the player never reactivates. I have tried using Player.SetActive(true) in the coroutine and even using an Invoke method with no luck. Any ideas on how to fix this? Please help.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
public class TimelineTrigger : MonoBehaviour
{
// calling items for Unity
public PlayableDirector timeline;
public GameObject Player;
public GameObject CutsceneCollider;
public GameObject CutsceneMC;
// Start is called before the first frame update
void Start()
{
// calls the playable director and turns off the MC for the scene
timeline = timeline.GetComponent<PlayableDirector>();
CutsceneMC.SetActive(false);
}
void Update()
{
Player = GameObject.FindGameObjectWithTag("Player");
}
private void EnableAfterTimeline()
{
Player = GameObject.FindGameObjectWithTag("Player");
Player.SetActive(true);
}
public void OnTriggerEnter2D (Collider2D col)
{
if (col.CompareTag("Player"))
{
// plays the cutscene and starts the timer
timeline.Play();
Player.SetActive(false);
Invoke("EnableAfterTimeline", 18);
CutsceneMC.SetActive(true);
StartCoroutine(FinishCut());
}
IEnumerator FinishCut()
{
// once the cutscene is over using the duration, turns off the collider and the MC.
yield return new WaitForSeconds(17);
CutsceneMC.SetActive(false);
CutsceneCollider.SetActive(false);
}
}
}
The issue here is that coroutines in Unity can't be run on inactive GameObjects, so FinishCut never gets executed.
This can be worked around by having a separate MonoBehaviour in the scene to which the responsibility of running a coroutine can be off-loaded. This even makes it possible to start static coroutines from static methods.
using System.Collections;
using UnityEngine;
[AddComponentMenu("")] // Hide in the Add Component menu to avoid cluttering it
public class CoroutineHandler : MonoBehaviour
{
private static MonoBehaviour monoBehaviour;
private static MonoBehaviour MonoBehaviour
{
get
{
var gameObject = new GameObject("CoroutineHandler");
gameObject.hideFlags = HideFlags.HideAndDontSave; // hide in the hierarchy
DontDestroyOnLoad(gameObject); // have the object persist from one scene to the next
monoBehaviour = gameObject.AddComponent<CoroutineHandler>();
return monoBehaviour;
}
}
public static new Coroutine StartCoroutine(IEnumerator coroutine)
{
return MonoBehaviour.StartCoroutine(coroutine);
}
}
Then you just need to tweak your code a little bit to use this CoroutineHandler to run the coroutine instead of your inactive GameObject.
public void OnTriggerEnter2D (Collider2D col)
{
if (col.CompareTag("Player"))
{
// plays the cutscene and starts the timer
timeline.Play();
Player.SetActive(false);
Invoke("EnableAfterTimeline", 18);
CutsceneMC.SetActive(true);
CoroutineHandler.StartCoroutine(FinishCut()); // <- Changed
}
IEnumerator FinishCut()
{
// once the cutscene is over using the duration, turns off the collider and the MC.
yield return new WaitForSeconds(17);
CutsceneMC.SetActive(false);
CutsceneCollider.SetActive(false);
}
}
If you have only one Player instance and it's accessible from the start, you'd better set it once in the Start method.
void Start()
{
// calls the playable director and turns off the MC for the scene
timeline = timeline.GetComponent<PlayableDirector>();
CutsceneMC.SetActive(false);
Player = GameObject.FindGameObjectWithTag("Player");
}
void Update()
{
}
private void EnableAfterTimeline()
{
Player.SetActive(true);
}

Can't access variable from another script

Assets\Scripts\Wood.cs(32,9): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
Well I'm trying to take the bool hasTorch and put it in the script Wood.cs to know if the player has a torch or not.
(I'm new so it's probably easy to fix, I just don't know :c)
Script 1 (Chest.cs):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Chest : MonoBehaviour
{
public Sprite openChest;
public GameObject chest1;
public GameObject chestBox;
public GameObject torch;
public bool hasTorch = false;
public GameObject darkness;
public GameObject chatBox;
private void OnTriggerEnter2D(Collider2D other)
{
chest1.GetComponent<SpriteRenderer>().sprite = openChest;
torch.SetActive(true);
chatBox.SetActive(true);
darkness.SetActive(false);
chestBox.SetActive(false);
hasTorch = true;
}
public void Close()
{
chatBox.SetActive(false);
}
}
Script 1 (Wood.cs):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Wood : MonoBehaviour
{
public GameObject chestScript;
public Chest script;
public GameObject chatBox;
private void OnTriggerEnter2D(Collider2D other)
{
if (script.hasTorch == true)
{
chatBox.SetActive(true);
}
if (script.hasTorch == true)
{
chatBox.SetActive(true);
}
}
public void Close()
{
chatBox.SetActive(false);
}
void Start(){
chestScript.GetComponentInChildren<Chest>().hasTorch;
}
}
This line does not do anything (not a valid statement, as the error suggests):
chestScript.GetComponentInChildren<Chest>().hasTorch;
you could Log it or set it to true/false like this (a valid assignment):
chestScript.GetComponentInChildren<Chest>().hasTorch = false;
You have created a variable of type Chest but have not told Unity which Chest instance you want to access. Imagine you had a couple of GameObjects, all with this script attached, each with a different value for hasTorch. Unity wouldn't know which instance you have in mind, that is why you have to specifically assign the value.
All you have to do is to add this line into the Start() method:
script = someKindOfaGameObject.GetComponent<Chest>();
From now on you should be able to access all the public variables in the Chest script using script.variable syntax.

{Unity} effect other objects after collision

I am creating a game with unity and I have a question.
I have 5 game objects + player. And they always rotate when the game has started. I want that if the player collides with the object that is tagged snowflake, the other 4 objects pause the rotation.
Have a static event on your player script, when player collide invoke that event. On other scripts subscribe to that event.
For example in your PlayerScript should be something like
public class PlayerScript : MonoBehaviour {
public static UnityAction OnPlayerCollidedWithSnowFlakes;
private void OnCollisionEnter(Collision other) {
if (other.gameObject.tag.Equals("snowflake")) {
OnPlayerCollidedWithSnowFlakes?.Invoke();
}
}
}
And your RotatingObjectScript should be something like
public class RotatingObjectScript : MonoBehaviour {
private void Awake() {
PlayerScript.OnPlayerCollidedWithSnowFlakes += CollidedWithSnowflakeEventHandler;
}
private void OnDestroy() {
PlayerScript.OnPlayerCollidedWithSnowFlakes -= CollidedWithSnowflakeEventHandler;
}
private void CollidedWithSnowflakeEventHandler() {
.
.
// Stop rotating
.
.
}
}

is there a way to find if an object in an array has been destroyed? [duplicate]

I'm creating a game and i want to show a panel when the player is dead
I've tried different approaches but none seems to do what I want
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DeadOrAlive : MonoBehaviour
{
public GameObject Player;
public GameObject deadPanel;
void Update()
{
if (!GameObject.FindWithTag("Player"))
{
deadPanel.SetActive(true);
}
}
}
To check if a object has been destroyed, you should use MonoBehavior's OnDestroy like so:
// Attach this script to the player object
public class DeadOrAlive : MonoBehaviour
{
public GameObject deadPanel;
void OnDestroy()
{
deadPanel.SetActive(true);
}
}
You can also instead of destroying the player object, set it to active/inactive, but to check if the player is dead or alive this way, you will need a separate object which checks the active state:
//Attach this to a object which isn't a child of the player, maybe a dummy object called "PlayerMonitor" which is always active
public class DeadOrAlive : MonoBehaviour
{
public GameObject deadPanel;
void Update()
{
if (!GameObject.FindWithTag("Player"))
{
deadPanel.SetActive(true);
}
}
}
Haven't used unity in a while and forgot how weird it could get.
Thanks to #VincentBree this is how I did it
void Update()
{
if (!Player.activeSelf)
{
deadPanel.SetActive(true);
}
}

How could i fix an error (cs0120) in unity?

In unity, I'm trying to make a press of a button increase the speed of the player. However, each time I run it. It gives me:
Error CS0120: An object reference is required for the non-static
field, method, or property 'PlayerController.speed'
I've already tried changing order of the code, so what could I do?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Upgrader1 : MonoBehaviour
{
void Start()
{
GameObject Player = GameObject.Find("Player");
PlayerController PlayerController = Player.GetComponent<PlayerController>();
}
public void Upgrade1()
{
PlayerController.speed++;
}
}
public class Upgrader1 : MonoBehaviour
{
PlayerController PlayerController; //It should be member variable
void Start()
{
GameObject Player = GameObject.Find("Player");
PlayerController = Player.GetComponent<PlayerController>();
}
public void Upgrade1()
{
PlayerController.speed++;
}
}
it's always a good thing to use proper naming conventions.
PlayerController _PlayerController;
void Start() {
GameObject Player = GameObject.Find("Player");
_PlayerController = Player.GetComponent<PlayerController>();
}
public void UpgradeSpeed() // I changed the name according to its functionality
{
_PlayerController.speed++;
}
With this, you won't put PlayerController class reference again by mistake.

Categories