- Home /
Call Method of a Gameobj. Component from other script works, but it does not change variables
Hey Guys,
so I have this very strange problem here which I cannot understand.
There are 3 Scripts:
MainGame : MonoBehaviour - put on a gameobject on the scene, this exists first
Brain - gets created by MainGame.
Gui - gets created by Brain.
When I call a a function from Gui to change a value of MainGame, it doesn't change the variable, but it does run the Debug.Log in the method!
There is only one comment, when I uncomment, the variable readyToGui becomes true, else it stays false all the time.
Here are the scripts:
MainGame.cs
using UnityEngine;
using System.Collections;
public class MainGame : MonoBehaviour {
private Brain brain;
public bool readyToGui;
void Start()
{
Debug.Log ("MainGame.Start()");
this.brain = new Brain();
readyToGui = false;
}
public Brain getBrain() { Debug.Log ("MainGame.getBrain();"); return brain; }
public void setReadyToGui() { Debug.Log("set this.readyToGui to true"); this.readyToGui = true; }
public void saySomething() { Debug.Log("MainGame says something"); }
void OnGUI()
{
Debug.Log (this.readyToGui);
//this.brain.getGui().initialize();
if(readyToGui) {
brain.getGui().OnGui(); }
}
}
Brain.cs
using UnityEngine;
using System.Collections;
public class Brain {
private Gui gui;
public Brain()
{
this.gui = new Gui(this);
}
public Gui getGui() { return this.gui; }
}
Gui.cs
using UnityEngine;
using System.Collections;
public class Gui {
private Brain brain;
public Gui (Brain brain)
{
this.brain = brain;
initialize();
}
public void initialize()
{
GameObject _main_game = GameObject.Find("_main_game");
MainGame mainGame = _main_game.GetComponent<MainGame>();
mainGame.saySomething();
mainGame.setReadyToGui();
}
public void OnGui()
{
showHelp();
}
private void showHelp()
{
GUI.Box(new Rect(10, 10, 100, 100), "helpbox");
}
}
And here is the output, when I live it like it is (with the comment):
MainGame.start() UnityEngine.Debug:Log(Object) (1)
MainGame says something UnityEngine.Debug:Log(Object) (1)
set this.readyToGui to true UnityEngine.Debug:Log(Object) (1)
False UnityEngine.Debug:Log(Object) (187)
This is driving me crazy, I so much hope someone of you can help me.
Not sure if it matters, but have you tried splitting the setReadyToGui() method out into multiple lines? That was the only thing that looks strange to me. But I've been wrong before, C# might support this.
Otherwise I can't see what's happening.
that has nothing to do with it. whitespace is there for readability, not for any functionality/performance. more might add an infinitesimally small amount of time to compile, but that's about it.
the code works as written - there's either a misunderstanding about the order of execution with the constructors or the fact that the OP sets the variable back to false
and is then surprised by it being, err, false
;)
I did only set it to false
once, when the _main_game GameObject is built. I mean, Start() is only called once right?
yes, Start()
is only called once but you set your bool to false
AFTER the constructors for Brain()
& Gui()
are executed so setting it to true
in setReadyToGui()
happens BEFORE you set it to false
.
Answer by Skippy_123 · Jun 29, 2014 at 03:02 PM
(This Answer is for more then just the above sourcecode from my first post. This is about the code seen in the first following picture. For just the answer for the first post, read the post below, from gjf)
I actually found the problem. I did not initialize everything properly. The Solution and the problem are in 2 picutres I made to see it better, I hope I can help someone somewhen with this.
the finally working sourcecode is the following:
MainGame.cs
using UnityEngine;
using System.Collections;
public class MainGame : MonoBehaviour {
private Brain brain;
void Start() {
Debug.Log ("MainGame.Start()");
this.brain = new Brain();
}
public Brain getBrain() { Debug.Log ("MainGame.getBrain();"); return this.brain; }
public void saySomething() { Debug.Log("MainGame says something"); }
void OnGUI() {
if(this.brain.initialized) {
brain.getGui().OnGui(); }
}
}
Brain.cs
using UnityEngine;
using System.Collections;
public class Brain {
private Gui gui;
public bool initialized;
public Brain() {
this.gui = new Gui(this);
this.initialized = false;
if(this.gui.initialized)
this.initialized = true;
}
public void saySomething() { Debug.Log("Brain says something"); }
public Gui getGui() { return this.gui; }
}
Gui.cs
using UnityEngine;
using System.Collections;
public class Gui {
private Brain brain;
public bool initialized;
public Gui (Brain brain) {
this.brain = brain;
this.initialized = false;
initialize();
}
public void initialize() {
this.initialized = true;
}
public void accessBrain() {
GameObject _main_game = GameObject.Find("_main_game");
MainGame mainGame = _main_game.GetComponent<MainGame>();
mainGame.getBrain().saySomething();
}
public void OnGui() {
showHelp();
accessBrain();
}
private void showHelp() {
GUI.Box(new Rect(10, 10, 100, 100), "helpbox");
}
}
your code still has potential problems. it's possible (although unlikely in this case) that the line
if(this.gui.initialized)
will throw a null exception. it's good practise to check whether the object is null before accessing any of its members.
i.e. the code should look more like:
if (this.gui != null)
{
if (this.gui.initialized)
... rest of code here
}
you should do something similar with these lines:
$$anonymous$$ainGame mainGame = _main_game.GetComponent<$$anonymous$$ainGame>();
mainGame.getBrain().saySomething();
Yes, you're right, this is of course not the perfect code yet. I already got into those problems in my real code (this stuff here was of course just a break down of my real code because it is to long). I had to deal with exactley what you said, because there were so many "branches"/situations, so I had to put different kind of checks for initialized objects everywhere.
So always remember, write good, exception handling and much situation covering initialization codes!
I will probably put all initialization processes in the update routine, checking for everybody all the time till they are ready, and then change a fullInit bool somewhere.
Thanks for the comment!
Answer by gjf · Jun 29, 2014 at 11:58 AM
the scripts do exactly what you've told them to do - maybe you're confused by the order of execution.
add the following into MainGame.cs
before you set readyToGui
to false
and you'll see that it was set to true
.
Debug.Log(string.Format("Setting readyToGui to false, was {0}", (readyToGui ? "true" : "false")));
try removing line 13 in your original script (`readyToGui = false;`)
Thanks for the answer. For the code I used for this question at start, this was the solution. While waiting for answers, I had more problems which had to deal with proper initialization (order) which I already solved.
Your answer

Follow this Question
Related Questions
Initialising List array for use in a custom Editor 1 Answer
How to make sure custom init methods are called? 1 Answer
OnEnable not called after all Awake and not all OnDisable before OnDestroy? 1 Answer
initialize with object name 1 Answer
Order of GameObject.FindGameObjectsWithTag(string tag) 3 Answers