Activate and deactivate an object not work - c#

i try to make a fire place were i need to collect wood and use it on fire place but nothing happen, i have used the debug.log to see if the variable are correct receive the changes and its work perfect but the if i have fireonplace variable = 1 then activate the fireplace object the wood its inserted on the variable but the trigger for activate the fire not happen.
This is my code
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class enablefire : MonoBehaviour {
public GameObject Enable_Disable;
public static int woodonfire = 0;
public void Enable ()
{
Enable_Disable.SetActive (true);
}
public void Disable()
{
Enable_Disable.SetActive (false);
}
// Use this for initialization
void Start ()
{
Enable ();
//Enable_Disable.SetActive (false);
}
void Update()
{
if (woodonfire >= 1)
{
Enable_Disable.SetActive (true);
}
if (woodonfire == 0)
{
Enable_Disable.SetActive (false);
//Enable_Disable.SetActive (false);
}
}
}

change the name of the game object, as a rule the name has to begin with lowercase, try names like enableDisable;
also you already created a method to enable/disable the GameObject why don't you just change this code...
void Update()
{
if (woodonfire >= 1)
{
Enable();
} else if (woodonfire == 0)
{
Disable();
}
}

You have to move the script onto another object.
Since an inactive gameobject has all its components inactive, the script on it will be inactive too and you won't be able to active the object again. It may be a better option to make the particle system in another object which contains the script. ( You will basicly activate and de-activate your child object (fire) ).

Related

How can I destroy a game object forever?

So, I have this potion. When the player in my game comes in contact with the potion, I want to destroy the potion. However, if the player dies, the scene will reload and the potion will still be in the level. If the player collides with the potion, I don't want them to obtain it. They should only be able to collect the potion once.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroyPotionForever : MonoBehaviour
{
public bool potionCollide = false;
// Start is called before the first frame update
void Start()
{
}
void OnTriggerEnter(){
if(potionCollide == false){
Destroy(gameObject);
bool potionCollide = true;
}
}
// Update is called once per frame
void Update()
{
}
}
But...this code doesn't work. Any help is appreciated.
A simple way would be to store whether you had picked up the potion in PlayerPrefs.
Then you could do something like:
void OnTriggerEnter()
{
if(PlayerPrefs.GetInt("GotPotion", 0) == 0)
{
// You didn't get the potion yet, so get it
Destroy(gameObject);
PlayerPrefs.SetInt("GotPotion", 1); // got the potion
}
}
Then wherever you spawn your potion, you could have:
if(PlayerPrefs.GetInt("GotPotion", 0) == 1)
{
// Got the potion already, so don't spawn the potion
}
Or, you if you put the potion in the scene directly, you could do:
void Start()
{
if(PlayerPrefs.GetInt("GotPotion", 0) == 1)
{
// If the potion is already picked up, destroy it
Destroy(gameObject);
}
}
A much better way would be to write your own save system as Antnio Pedro Gonalves Ferreira suggested, but this will get you through the demo phase at least.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroyPotionForever : MonoBehaviour
{
public bool potionCollide = false;
// Start is called before the first frame update
void Start()
{
}
void OnTriggerEnter(){
if(potionCollide == false){
Destroy(gameObject);
potionCollide = true;
}
}
// Update is called once per frame
void Update()
{
}
}
Just using global var. potionCollide . You created local variable instead of using variable global.
Is your potion on the scene before you start the game? Whatever happens during runtime does not permanently change the scene, if you want the potion to disappear forever it cannot be on the hierarchy of the scene before the game runs. When you reload a scene it resets to the state it was before you ran the game.

How to call coroutine from another script? UNITY

This is the script where the touch action, the main game is on it
var addingGoldPerSec = new GameObject();
var buttonInstance = addingGoldPerSec.AddComponent<ItemButton>();
StartCoroutine(buttonInstance.addGoldLoop());
And this is the one where I have the coroutine
public double goldPerSec
{
get
{
if (!PlayerPrefs.HasKey("_goldPerSec"))
{
return 0;
}
string tmpStartGoldPerSec = PlayerPrefs.GetString("_goldPerSec");
return double.Parse(tmpStartGoldPerSec);
}
set
{
PlayerPrefs.SetString("_goldPerSec", value.ToString());
}
}
public void updateUI()
{
priceDisplayer.text = LargeNumber.ToString(currentCostPerSec).ToString();
coinDisplayer.text = "PER SEC\n" + LargeNumber.ToString(goldPerSec).ToString();
levelDisplayer.text = "LEVEL\n" + level + "/150".ToString();
}
public IEnumerator addGoldLoop()
{
while (DataController.Instance.gold <= 1e36)
{
DataController.Instance.gold += goldPerSec;
if (Gameplay.Instance.booster == 1)
{
yield return new WaitForSeconds(0.25f);
}
else if (Gameplay.Instance.booster == 0)
{
yield return new WaitForSeconds(1.0f);
}
}
}
And this is a third Script where I manage the data stored into PlayerPrefs
public void loadItemButton(ItemButton itemButton)
{
itemButton.level = PlayerPrefs.GetInt("_level",1);
PlayerPrefs.GetString("_costPerSec", itemButton.currentCostPerSec.ToString());
PlayerPrefs.GetString("_goldPerSec",itemButton.goldPerSec.ToString());
}
public void saveItemButton(ItemButton itemButton)
{
PlayerPrefs.SetInt("_level", itemButton.level);
PlayerPrefs.SetString("_costPerSec", itemButton.currentCostPerSec.ToString());
PlayerPrefs.SetString("_goldPerSec", itemButton.goldPerSec.ToString());
}
I have the second script which is the coroutine one attached into several gameobjects where exists an Upgrade button, per upgrade increases the coin by second you earn, the main problem here is that the coroutine just stops after I touch the screen, so I made another code into the main script so by that way the coroutine will keep working even after touched the screen, so I made a script where is the GameObject, but it just throws me NullReferenceException, tried a check with TryCatch and throws me that the problem is coming from the GameObject that I have created on the main script, but if is that way I need to attach to the main object where the main script exists, like more than 10 gameobjects where the coroutine exists, I think Singleton is not the way, it deletes me all the information above there by instantiating on Awake, I never thought about making static so I did as you told me and I need to change almost of my code, every text is attached into each gameobjects, to make a non-static member work with a static-member need to delete Monobehaviour but it just makes the game explode, thanks for helping me.
Create two scripts and attach them, for example, at Main Camera. The first script contains your timer with all variables:
using UnityEngine;
using System.Collections;
public class TimerToCall : MonoBehaviour {
//Create your variable
...
//Your function timer
public IEnumerator Counter() {
...
}
}
In the second script, you will call the timer:
public class callingTimer : MonoBehaviour {
void Start() {
//TimerToCall script linked to Main Camera, so
StartCoroutine(Camera.main.GetComponent<TimerToCall>().Counter());
}
}
if you want to have for example the second script not linked to any gameObjet you could use static property:
in first script linked:
void Start()
{
StartCoroutine(CallingTimer.ExampleCoroutine());
}
in second script not linked, you use the static property:
using System.Collections;
using UnityEngine;
public class CallingTimer
{
public static IEnumerator ExampleCoroutine()
{
//Print the time of when the function is first called.
Debug.Log("Started Coroutine at timestamp : " + Time.time);
//yield on a new YieldInstruction that waits for 5 seconds.
yield return new WaitForSeconds(5);
//After we have waited 5 seconds print the time again.
Debug.Log("Finished Coroutine at timestamp : " + Time.time);
}
}

Hierarchy issue Unity

Im making a simple game in Unity 3d, basically you have a backdround object with more gameobjects on top, what you have to do is drag those game objects into some trash cans, as soon as you hit the correct trash can with the correct object said object gets deleted, the idea of the game is that when you put all the objects in the corect cans you win the game
I have the drag and acceptance all made but i cant figure out how to make the script so that when theres no more objects, you win the game.
I've been trying to use Hierarchy on an empty game object thats the parent for the objects that you have to destroy, but i dont know how to actually delete the objects so that the code can register it, any help?
The code for the drag and the code im using for the trash cans:
using UnityEngine;
using UnityEngine.EventSystems;
public class arrastrar : MonoBehaviour, IDragHandler
{
public float z = 0.0f;
public void OnDrag(PointerEventData eventData)
{
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = z;
transform.position = Camera.main.ScreenToWorldPoint(mousePosition);
}
}
And the code inside the trashcans
using System.Collections;
using UnityEngine;
using System.Collections.Generic;
public class botarBasura: MonoBehaviour
{
void OnCollisionEnter(Collision other)
{
if (other.gameObject.name == "cubo")
Destroy(other.gameObject);
} else if (other.gameObject.name == "escombros")
{
other.gameObject.transform.position = new Vector3(-1, 2.5f, -2); //If its not the correct trash can it returns the object to the starting position
}
} else if ( other.gameObject.name == "botellas")
{
other.gameObject.transform.position = new Vector3(0, 2.5f, -2);
}
}
}
You can use a scriptable object to keep track of your object. Objects just need to add and remove themselves to a list in the scriptable object in their OnEnable() and OnDisable() callbacks. When an object removes itself you can have code check to see if there are no more objects left and trigger an event that something in your scene will react to.
(Dragable Object)
public class DragableObject : MonoBehaviour{
//reference to the scriptable object
public DragableObjectSet RuntimeSet;
void OnEnable(){
RuntimeSet.Add(this);
}
void OnDisable(){
RuntimeSet.Remove(this);
//you can put code checking if the runtime set is empty here
//or you can put it in the DragableObjectSet Remove method
}
}
Scriptable object example code
public DragableObjectSet : ScriptableObject
{
public List<DragableObject> RuntimeSet = new List<DragableObject>();
public void Add(DragableObject obj){
RuntimeSet.Add(obj);
}
public void Remove(DragableObject obj){
RuntimeSet.Remove(obj);
if(RuntimeSet.Count() == 0)
//some code here raising an event (if desired)
}
}
This type of object is called a runtime set and is detailed in this talk around the 40 minute mark.
https://www.youtube.com/watch?v=raQ3iHhE_Kk
A solution could possibly be using a singleton:
Create a new empty GameObject and add this code:
using UnityEngine;
public class TrashCounter : MonoBehaviour {
public static TrashCounter instance = null;
public int counter = 0;
void Awake(){ instance = this; }
}
Now, wherever you create an object (or in the Start() method of any object code), you just need to do TrashCounter.instance.counter++ and you will have your trash count.
After that, you just need to update this counter everytime you delete an object by doing TrashCounter.instance.counter-- and after you ask if(TrashCounter.instance.counter == 0) WinGame().
You can get an array of all active & not-yet-destroyed GameObjects with some enabled component with Object.FindObjectsOfType<ComponentType>();. Once you have that, you could then look at the length of that array.
So, you could do something like this in the code that destroys/deactivates the draggable gameobject:
GameObject otherObject = /* get draggable object to possibly destroy */;
if ( /* test to remove otherObject */ )
{
// deactivate the draggable object
otherObject.setActive = false;
// get all other draggable objects
DraggableObject[] remainingDraggableObjects = Object.FindObjectsOfType<DraggableObject>();
if (remainingDraggableObjects.Length == 0)
{
// there are no more active gameobjects with enabled DraggableObject component
// handle win condition here.
}
}
In your specific example, it could look like this:
void OnCollisionEnter(Collision other)
{
if (other.gameObject.name == "cubo")
{
other.gameObject.setActive = false; // better than destroying in most cases
// get all other draggable objects
arrastrar[] remainingObjects = Object.FindObjectsOfType<arrastrar>();
if (remainingObjects.Length == 0)
{
// there are no more active gameobjects with enabled arrastrar component
// handle win condition here.
}
}
// ...

Unity The object of type "GameObject" has been destroyed

I have 2 buttons in my options menu, "return to main menu" and "mute music"
Each of these buttons has a script attached to it, and calls the OnPress() method of the script when it is pressed.
I also have a main Level object/script that handles all the scene loading and stuff.
So the script of the main menu button does FindObjectOfType() in its Start and then calls level.LoadStartScene() in its OnPress().
The script for the mute button does the same thing but calls level.ToggleMuteMusic().
So this worked perfectly before, but then I made the level a singleton with the following code:
public void Awake() {
InitializeSingleton();
}
private void InitializeSingleton() {
if (FindObjectsOfType(GetType()).Length > 1) {
Destroy(gameObject);
} else {
DontDestroyOnLoad(gameObject);
}
}
So now the main menu button works perfectly, but the mute button gives an error; I think this is because in Start() it finds the old level object, and then the one with DontDestroyOnLoad comes in and deletes the old one, but then why does the main menu button work???
Mute Button Code:
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class MuteButton : MonoBehaviour {
[SerializeField] string mutedText = "Unmute Music";
[SerializeField] string unmutedText = "Mute Music";
private Level level;
private TextMeshProUGUI myText;
public void Start() {
level = FindObjectOfType<Level>();
myText = GetComponent<TextMeshProUGUI>();
}
public void OnPress() {
if (level == null) {
Debug.Log("log 1");
}
level.ToggleMuteMusic();
bool muteMusic = level.GetMuteMusic();
if (muteMusic == true) {
myText.SetText(mutedText);
} else if (muteMusic == false) {
myText.SetText(unmutedText);
}
}
}
Menu Button Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MenuButton : MonoBehaviour {
Level level;
public void Start() {
level = FindObjectOfType<Level>();
}
public void OnPress() {
level.LoadStartScene();
}
}
Full Error:
MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
UnityEngine.GameObject.GetComponent[T] () (at C:/buildslave/unity/build/Runtime/Export/Scripting/GameObject.bindings.cs:28)
Level.ToggleMuteMusic () (at Assets/Scripts/Level.cs:74)
MuteButton.OnPress () (at Assets/Scripts/MuteButton.cs:23)
Thanks for your time :)
It can be a bit difficult to determine the exact order that things are executing to cause this issue, but the fact that you're losing a reference in Start() that was handled in Awake() is odd. I've had issues using FindObjectOfType<> in Start() in the past, so maybe changing up how you're handling the singleton would be best.
What I'd recommend is making your Level static so you can reference it easier, since you're already implementing a form of Singleton.
Here's an example of how you could rewrite the top of your Level.cs file:
public static Level instance;
private void Awake()
{
if (instance != null && instance != this)
{
Destroy(this.gameObject);
return;
}
else
{
instance = this;
}
DontDestroyOnLoad(this.gameObject);
}
This causes it to create the Level class once, then destroy all subsequent versions of it (like when you reload the scene it's placed in).
Now, to reference it in your other scripts, you never have to use FindObjectOfType<Level>() again! You can statically reference Level.instance, like so:
//New way to call ToggleMuteMusic()
Level.instance.ToggleMuteMusic();
Hopefully this helps!

animation.Play() doesn't work

I'm pretty sure that
animation.Play("DoorOpen");
Would play the animation "DoorOpen", but when i'm trying to put it in my code, it just giving me an error message:
The Animation attached to this GameObject (null if there is none attached).
using UnityEngine;
using System.Collections;
public class DoorPhysics : MonoBehaviour {
int Open = 0;
// Update is called once per frame
void Update() {
if (Open == 0) {
if (Input.GetKeyDown("e")) {
animation.Play("DoorOpen");
}
}
}
}
You need to show location of gameobjects in unity, they do not know eachother, you have to always use :
GameObject.GetComponent<T>()
GetComponentInParent<T>()
GetComponentInChildren<T>()
best practice is to get object references at Start()
also you should attach IMPORTANT!!! Animation component to the object this script it attached to
public class DoorPhysics : MonoBehaviour {
public Animation animation;
int Open = 0;
void Start()
{
animation=GameObject.GetComponent<Animation>(); //if your have derived type change Animation to good class DoorAnimation for example
}
void Update()
{
if (Open == 0) {
if (Input.GetKeyDown("e")) {
this.animation.Play("DoorOpen");
}
}
}
}
if that code wont work, you will need show me your GameObject hierarchy
And if your just start your trip with it learn MonoBehaviour call order
and life cycles of events

Categories