Cannot make button non-interactable through seperate script - c#

I'm trying to make a button interactable after a certain scene (playing level) has been loaded. It's a button in a menu scene that represent the loaded scene itself (level selectable after playing it).
The problem is this: If the users passes a certain level, say level 1, level 2 gets loaded, and a static method gets called:
public static void AllowTut2()
{
Tut2Allowed = true; //public static bool initialised in this script
tutorial2.interactable = true; //tutorial2 is a button in the "menu scene"
}
To make it clear where the variables come from, this is part of the same script:
public class LevelSelectScript : MonoBehaviour {
public Button tutorial2;
public static bool Tut2Allowed = false;
//...some other variables
void Start ()
{
tutorial2 = tutorial2.GetComponent<Button>();
tutorial2.enabled = false; //more later on
///... some other code
}
}
Now the problem is this error: An object reference is required to access non-static member `LevelSelectScript.tutorial2' (refers to method AllowTut2).
It seems that I cannot change tutorial2.interactable trough the given static method (called in another script).
It basically says the button tutorial2 is non-static, therefore cannot use this in a static method.
Now if I make the button static, i.e. change
public Button tutorial2;
to
public static Button tutorial2;
then I have no way to assign the button object in the scene to this variable in the attached script.
Does someone perhaps know a solution to this problem?
Thanks in advance!

if you want to use static varaibles and also use inspector for assigning you can use singleton , here is where you can learn it

Related

Change variable when button is pressed

I'm creating a unity project where when the user presses a certain button a stat modifier will increase, how would I get this to work using C#? this is the current code but I feel like this is entirely in the wrong direction
public class logicBook
{
public void Equip(Character c)
{
c.logic.AddModifier(10);
}
public int logic;
logic = 0;
}
I'm pretty new to C# and Unity so help would be really apricated!
I believe by button you meant key so if you want to implement that you need first to have your class inherit from Monobehaviour so that you can use your script as a component of a gameobject.
then you should have an Update function (it is a function that gets called every frame) and rihgt there you can check the input
public class logicBook : MonoBehaviour{
public void Equip(Character c){
// do some cool stuff here
}
void Update(){
if(Input.GetKeyDown(/* Key that triggers this */){
Equip(/* Argument here */);
}
}
If you want to have a button in game that triggers this function create a canvas UI in your scene and create a button object as a child of your canvas and then add the function to the button onClick component.

How to set a GameObject active on one scene form a button click function on second scene that is loaded additive C#, Unity

I'm new to coding and Unity, I'm working on a simple click style game to learn the basics of both. I've created several scenes: MainMenu, UI, 1st level and 2nd level. After pressing 'Start' in main menu i'm loading UI and 1st level additively.
In UI layer I have a shop UI and other bits that I never want to unload. On the 1st and 2nd level i have the bits that i want to have only on those scenes.
So, what I'm trying to do is when i purchase an item or upgrade for the 1st level i want a GameObject (sprite) to be set as active.
What I've tried to do is to call a function in one script that is attached to GameObject in 1st level from script that is attached to a purchase button in UI scene, but from what I was able to understand from messing with it will set that game object active if it's assigned in the UI scene - so the whole thing is basicly pointless and i can do it much easier.
Code in script attached to GameObject in 1st level scene
public class Work_Button : MonoBehaviour
{
public GameObject hubert12;
public void Huberd()
{
hubert12.SetActive(true);
}
}
Code in script attached to GameObject in UI scene
public class Shop : MonoBehaviour
{
public GameObject buyHubertOnebutton;
public GameObject test;
public void UnlockHubert1()
{
if (Global_Cash.CashCount >= 20)
{
Global_Cash.CashCount -= 20;
buyHubertOnebutton.GetComponent<UnityEngine.UI.Button>().interactable = false;
Work_Button sn = test.GetComponent<Work_Button>();
sn.Huberd();
}
}
}
If you have any remarks anout how i've spit scenes or anything else they will be more than welcome!
Thanks!
There's something you need to be aware of, and that is that you can't reference an object from one scene, in another. You CAN reference the same Prefab though, but that's a slightly different issue.
One way I find effective is to do something like this:
public class Work_Button : MonoBehaviour
{
public GameObject hubert12;
public void Awake ( )
{
Shop.Register ( this );
}
public void Huberd ( )
{
hubert12.SetActive ( true );
}
}
Then you can have a Shop manager that has instance and static components.
public class Shop : MonoBehaviour
{
// Static variables
private static Work_Button _workButton;
// Instance variables
public GameObject buyHubertOnebutton;
public static void Register ( Work_Button workButton )
{
_workButton = workButton;
}
public void UnlockHubert1 ( )
{
if ( Global_Cash.CashCount >= 20 )
{
Global_Cash.CashCount -= 20;
buyHubertOnebutton.GetComponent<UnityEngine.UI.Button> ( ).interactable = false;
if ( _workButton != null )
_workButton.Huberd ( );
}
}
}
This works by having your button register with the shop. And because we're using the static variable here, we don't need to "find" the Shop object. The instance method UnlockHubert1 will check to make sure there is a button registered.
This represents just one of many ways to accomplish this. It's also the most basic of basic implementations. But as of right now I'm fond of this method. Extending this, you could store the registered items in a Dictionary collection, and you could do some cleanup/deregister when a button is destroyed (i.e. OnDestroy ).
The assumption here is that there is only one Work_Button in the scene, otherwise you'll need a way to differentiate them (i.e. a Dictionary with am identifier as the key).

Unity: Singleton DontDestoryOnLoad script false reference

So I have this manager in my start scene with DontdesoryOnload, that managers all the UIs, etc. It follows singleton pattern, so if I go to scene 2 and come back to my start-scene, the first manager will remain the same, and the manager in the newly opened start-scene will figure that there's already a manager, and destroy itself.
From here let's call the Manager remains alive Manager-Singleton and the manager that is destroyed as planned Manager-Dead.
The problem I'm having is that the references in my Manager-Singleton seem to false-reference.
When Manager-Dead is destroyed as planned, if I access a public GameObject under my Manager-Singleton, it will show me an error. Where if I click on those References fields in Inspector, it will lead me to the correct Gameobject which not not destoryed at all.
MissingReferenceException: The object of type 'GameObject' has been destroyed, but you are still trying to access it.
However, if I avoid Manager-Dead from being destroyed, (So there will be two managers in one scene), the code worked just fine.
I know you might be thinking, if there are two managers in the scene, there might be a UI overlap so that I might be clicking on ManagerDead's Button, and accessing its References. So after I got back to the Start scene, I manually disable the ManagerDead. And it turns out ManagerSingleton is changing ManagerDead's UI !
I really couldn't figure out where it went wrong. Any suggestions would be appreciated.
Following is some of my codes in case they might be useful:
[RequireComponent(typeof(UIManager))]
[RequireComponent(typeof(DataManager))]
[RequireComponent(typeof(StateManager))]
public class Managers : MonoBehaviour {
private static UIManager _UIManager;
public static UIManager UI
{
get { return _UIManager; }
}
private static DataManager _DataManager;
public static DataManager Data
{
get { return _DataManager; }
}
private static StateManager _StateManager;
public static StateManager State
{
get { return _StateManager; }
}
public string debugString = "";
void Awake(){
//Only one dataControl obj is allowed to exist and pass along.
if (GameObject.FindObjectsOfType<Managers> ().Length > 1) {
Destroy (gameObject);
} else {
DontDestroyOnLoad (gameObject);
}
_UIManager = GetComponent<UIManager> (); //!!!!! This is a Singleton class.
_DataManager = GetComponent<DataManager> ();
_StateManager = GetComponent<StateManager> ();
}
}
Problem solved, the Component referencing part is what's causing the trouble, Since _UIManager etc is static, that means when component referencing is called in Awake function of Manager-Dead, it will refer those reference to the GameObjects Under it even after it's destroyed.
This results in the static _UIManager from Manager-Singleton will be referred to the Destroyed Gameobjects under Manager-Dead.

how to make a c# script run at scene start in unity

I am doing a school project. I need to check the destroyed objects in my scene as soon as the scene starts. problem is I don't know how to make it load or where to attach the c# script.
public static class DestroyedObject {
static List<GameObject> objs = new List<GameObject>();
public static void Add(GameObject obj)
{
if(!objs.Contains(obj))
objs.Add(obj);
}
}
If you want it to run when you start the scene you need to attach it to a GameObject. Create empty and attach it as a component.
The code that you want to run on start should be in the:
void Awake
{
//Your code here
}
or
void Start
{
//Your code here
}
functions.
Start is called as soon as the class is instantiated and Awake is called when the scene is started. Depends where you want it in the call stack, but in your case i think it will do essentially the same thing.
I think what you're looking for is a way to "save" what objects have been deleted : you simply have to make your class inherit from MonoBehaviour and call DontDestroyOnLoad() so your object containing the script will exist between the scenes.
public static class DestroyedObject : MonoBehaviour
{
public static DestroyedObject Instance;
private static List<GameObject> objs = new List<GameObject>();
private void Awake()
{
if (!Instance)
{
Instance = this;
}
else
{
DestroyImmediate(gameObject);
}
DontDestroyOnLoad(gameObject);
}
public static void Add(GameObject obj)
{
if(!objs.Contains(obj))
objs.Add(obj);
}
public static List<GameObject> GetDestroyedObjects()
{
return objs;
}
}
Then you simply access your script using DestroyedObject.Instance.Add() or DestroyedObject.Instance.GetDestroyedObjects() (some people don't like this kind of design pattern but it has proven to be very effective when using Unity).
Also as #Sergey asked, why creating objects (on scene loading) in order to delete them afterward : you could do the revers operation (only instantiate the needed ones).
Hope this helps,
Can you describe what you are trying to achieve in total? Because it looks like your way is not the best way to do it ;).
If all you want to know is how to execute a script at scene start: create a script that inherits from MonoBehaviour (no need for static class), attach it to a gameobject in your scene, and thats it!
If you want to execute code as soon as the scene starts (and the gameobject is loaded), put your code in Awake() or Start(). You can read about the execution order of those functions here: https://docs.unity3d.com/Manual/ExecutionOrder.html
Making a script static means it will be active in all scenes and even before any scene is loaded.
Additionally, i would not recommend the use of static classes unless you really need them.

Accessing information between scenes in Unity

I have a class in Unity that a list of toggle switches that get turned on and off in a separate scene from the rest of my game. What I'm wanting is to have the user select one button and then have a corresponding action happen in my main game when they go back to that scene. However, I'm having issue sending information between scenes.
At the moment my toggle class looks like this:
private bool action1 = false;
public bool Action1
{
get { return action1;}
}
void OnGUI()
{
action1 = GUI.Toggle(new Rect(10, 10, 100, 30), action1, "test");
}
void Update()
{
if(Input.GetButton("Jump"))
{
Application.LoadLevel("Main");
}
}
Then in a class held in my Main scene, I have the following code:
private ActionClass actionIsOn = new ActionClass();
void Start()
{
if(actionIsOn.Action1 == true)
{
Debug.Log("action is on");
}
else
{
Debug.Log("nothing happening");
}
}
However, when I test this, nothing happens.
Have I set this up correctly? Is there a better way to pass this information from one scene to another?
Option #1:
Use a static class to hold global info that's relevant to multiple scenes.
public static class GlobalData
{
public static bool SomeBooleanFlag;
}
This way in your first scene you can set GlobalData.SomeBooleanFlag to some value, and in your second scene you can check for it.
Option #2:
You can use Object.DontDestroyOnLoad to ensure that an object in your scene doesn't get destroyed when a new scene is loading. This way you can aggregate all of the info that you want to pass to the other scene in a single object (or use multiple objects, and keep them all alive), and make sure it stays alive even after the scene has changed.
http://docs.unity3d.com/Documentation/ScriptReference/Object.DontDestroyOnLoad.html

Categories

Resources