Using variables from another script int Unity 5 - c#

I need to use some variables defined in a script but when I call them their values are 0. I don't know what I am doing wrong.
Example:
Script1.cs
public int cont;
public void Method() { cont++; }
void Update() { Method(); }
Script2.cs
public Script1 usingScript1;
void MethodX()
{
usingScript1.GetComponent<Script1>();
Debug.Log(usingScript1.cont);
}
void Update() { MethodX(); }
This script should be showing the "cont" variable increasing since it's being called from Update(), but that's not happening. When I call it, it's 0 and don't increase.
Also, I refer the object which contains Script1.cs in the Ispector. It must be a simple thing that I'm missing. I even tried calling Method().

Just to add to what everyone mentioned, have you tried initializing "cont" ?
This
public int cont;
becomes
public int cont = 0;
Also try initializing it in the Start() function if this doesn't work.

The function called Method() is never called anywhere in this code. Since it's the only thing that modifies the value of the variable called cont, if it is never called, cont will never change from its default value of zero.
EDIT: Whoops!
Okay, the actual problem here is that you need to change
usingScript1.GetComponent<Script1>();
to
usingScript1 = GetComponent<Script1>();
The latter line of code sets the variable usingScript1 so that you can use it in your code. The former simply calls a function without doing anything with the information it returns.
EDIT: GetComponent() will only work is the two scripts are attatched to the same gameobject. Otherwise, you can use FindObjectOfType().

I managed to solve it and never thought about it. As simple as it. Instad of creating an object, I just made the variables static and call 'em using the class.
Script1.cs
public static cont;
Script2.cs
Script1.cont;
And it works.

Related

SelectedIndex returns -1 in void/static void function

I have a problem with the combobox.SelectedIndex function. The problem is that in void and static void it just returns a -1. Now before anyone comes and says if there is anything in it at all, yes it is, I've debugged the code and found that it only returns a -1 in static void and void , now I'm curious as to why it doesn't work, actually a very simple code.
void writecombo()
{
int CURRENT_LOG = combo.SelectedIndex; //< -1
Globals.LG[CURRENT_LOG] += "Hello!" + Environment.NewLine; //Crash, because it is -1
...
}
Where it works:
private void textbox1_KeyDown(object sender, KeyEventArgs e)
{
if (GetAsyncKeyState(Keys.Enter) < 0)
{
int CURRENT_LOG = combo.SelectedIndex; // Not Null
Globals.LG[CURRENT_LOG] += "Hello!" + Environment.NewLine;
...
}
}
I would be happy to get help and also if someone could explain to me why this is the case :)
EDIT: The problem only comes when I want to access this void from a static void, I wanted to use it to access the objects in form1 in a static. (var from = new Form1)
MRE
void vs static void isn't exactly your problem. It's a static member trying to access the non-static members of its class. That barrier cannot be crossed.
When a member is static, there's only one instance of it, and it's attached to the class; it can only access members of the class that are also marked with the static keyword.
Members that are not marked static can access all the members of the class, including its static members. Each object you create from the class using new essentially gets its own copy of the non-static members.
In your code sample, you're trying to access a non-static member from a static member, and the runtime is telling you that can't be done.
First of all, thanks to everyone tried to help me. It seems like accessing/calling an static function, to access with that the Form1 contents is a complicated and hard thing to do.
So, i found another way, instead trying to call a function, i am going to use a timer to check a global boolean value, if it is true, it should execute the code, very simple, it's not good, but at least a way to deal with it.
Still, i am opend for answers if anyone found a good and easy way to access the contents of a form with a static function in it.

Why does my if statement appear to be running twice on first run, even though it shouldn't?

I am currently making a game similar to Flappy Bird, and I have an if statement nested inside another if statement. When the first if statement becomes false, the other if statement still runs, but it only runs once. It should not be running when the first if statement returns false.
void Update()
{
if(!passed) {
if(Player.position.x >= gameObject.GetComponent<Transform>().position.x) {
Debug.Log("done");
passed = true;
}
}
}
As you can see when it first starts, the passed boolean becomes true which means it shouldn't run again after completion. However when I pass the obstacle for the first time in-game, it prints out "done" twice. This only occurs for the first obstacle.
In another script I have this:
private void OnTriggerEnter2D(Collider2D collision){
GameObject.Find("ObstacleTop").GetComponent<Obstacles>().passed = false;
}
And btw passed is set to false at the start:
public bool passed = false;
The script is probably attached to two game objects, so it shows the log output twice.
You can see which instance the log is for by calling GetInstanceID() in the Debug statement.
if (!passed) {
if (Player.position.x >= gameObject.GetComponent < Transform > ().position.x) {
Debug.Log(gameObject.GetInstanceID() + " done");
passed = true;
}
}
If you want to execute the code for the first object that ever executes Update and fulfills the condition, then make the passed variable static.
public static bool passed;
void Update()
{
if(!passed &&
Player.position.x >= gameObject.GetComponent<Transform>().position.x) {
Debug.Log("done");
passed = true;
}
}
If you make the variable static, it will exist once for this class instead of once per instance (i.e., per object).
You can also combine the two if-statements. Since C# uses short circuit evaluation, the second part of the condition (after the &&) will not be evaluated, if the first part evaluates to false.
Since the flag you use to indicate whether it passed or not is not in the same scope as its accompanying if statement, your logic will now depend on the second nested if statement instead.
If you want to only go through this once regardless of what happens in the body, you should do something like this instead:
void Update()
{
if(!passed) {
if(Player.position.x >= gameObject.GetComponent<Transform>().position.x) {
Debug.Log("done");
}
passed = true;
}
}
This marks the block as passed as long as it has entered there at least once.

C# Delegate value does not fall within the expected range error

this is a question programming C# within Unity game engine, but it might be C# delegate expert without Unity experience could know what I'm doing wrong? (I did post on Unity forum already).
I am trying to pass an arbitrary function to be called inside a fixed function, which itself is called using delegate keyword through the AddListener function of InputField.onEndEdit event. I am new to delegates, but as I understand, I need to create a new delegate to do this, and I'm getting bit tangled up, having read a few delegate articles still stuck. Currently, code compiles but get ArgumentException error. Unfortunately, with full stack trace on in Unity Editor, this is all the stack trace I get:
ArgumentException: Value does not fall within the expected range.
CharacterController3D..ctor () (at Assets/Entities/DungeonCell/Priest/CharacterController3D.cs:95)
Where the script name is CharacterController3D.cs. Line 95 constructor in this class, generating this error is:
Del marySuccess = question.MarySuccess;
End Objective: When player inputs an answer to an arbitrary question posed when player triggers it in game, the ProcessAnswer function will call a customised function processing correct answer to each question, ie each question will have different function dealing with a correct answer response. Likewise, the ProcessAnswer function will call different custom function for that question if player gives wrong answer and so on.
Below is the ProcessAnswer function, with arbitrary delegate passed to it delegate1, which in following code block runs when correct answer is given:
private void ProcessAnswer (InputField input, string answer, float clockStart, Del delegate1)
{
if (String.Equals(answer, input.text.Trim(), StringComparison.OrdinalIgnoreCase)) // trim trailing spaces, accept any case in letters typed
{
countdownTimer.enabled = false; // stops timer
float timePoints = Mathf.Round(2000/(clockStart - countdownTimer.TimeStoppedTenthsSecond()));
delegate1();
}
else ....
Above function is called in same script by:
string answer = "grace";
clockStart = 90f;
inputField.onEndEdit.AddListener(delegate { ProcessAnswer(inputField, answer, clockStart, marySuccess); });
where marySuccess is the delegate parameter in this case, defined by:
private delegate void Del();
Del marySuccess = question.MarySuccess;
Still in this same script, question here is declared as a static instance of a separate component script on same object. I understood have to make it static for the delegate to reference it, didn't work as non-static anyway:
private static Questions question;
and initialised in the Awake method, all in same script:
question = this.GetComponent<Questions>();
EDIT
As comments, apology for missing the MarySuccess() method code itself, which has same signature as the delegate declaration (no parameters, returns void):
public void MarySuccess()
{
string phrase1 = "a";
string phrase2 = "b";
string phrase3 = "c";
string phrase4 = "d";
thoughtText.color = new Color(0.55f, 0f, 0.03f); // now matches (141,0,8) colour of input text, was Color.red;
thoughtText.fontSize = 22;
StartCoroutine(player.FillThoughtBox(phrase1, 3, phrase2, 3, phrase3, 5, phrase4));
playerInputPanel.SetActive(false);
player.Invoke("MaryHailed", 10f);
Invoke("HideThoughtPanel", 22f);
}
// use Invoke() with desired delay, so that player can start moving and have more time to read the words before it disappears
private void HideThoughtPanel()
{
thoughtButtonPanel.SetActive(false);
}
EDIT2
I checked even with public void MarySuccess () {} empty, still gives same exception error.
Any suggestions very grateful, thanks!
I fixed this long time ago now, but in case anyone else reads, the problem was using private scope for the delegate function. From above question, code I had was:
private delegate void Del();
Del marySuccess = question.MarySuccess;
which generated the error in 2nd line. It should be:
public delegate void Del();
because MarySuccess() method is public method, the delegate signature needs to match it, and also be public. Indeed, since this was calling the method in another class, the method called would have to be public to work, and therefore the delegate also needs to be public, otherwise the 'value' of marySuccess here does not 'fall within the expected range' ie a public delegate 'value'. I had thought that since Del() only used in this class, it could be private, but not appreciating that Del() is used as a data type, as well as a variable. It's a confusing error message I feel, since I feel that the delegate type is being assigned a reference not a value, but very welcome if someone more experienced can correct any errors in detail of this analysis..
I got the very same exception in a very similar case. In my case it turned out that the expression question.MarySuccess (fetching a delegate) raises this particularly unexpected error if question is null. That's the difference between
Del x = question.MarySuccess;
and
Del x = () => question.MarySuccess();
The second version will work even if question is null, and raise a NullReferenceException only later and only if x is actually called.

Issue with ++ operator

I'm attempting to add 1 to the variable levelname everytime the LevelChange function is called. However, everytime its called it resets the value to 1 like its originally set in the beginning of the code. I'm used to c++ and very confused. This code is a bit sloppy because ive tried a ton of ways to solve this. Any help would be appreciated.
Theres a bracket missing because for some reason i cant get this line to go in the code block.
public class NextLevel : MonoBehaviour {
int levelname = 1;
int newlevelname;
string levelnameS;
void LevelChange()
{
levelname++;
newlevelname = levelname;
string levelnameS = newlevelname.ToString(); //Converts newlevelname which is an int value to a string
Debug.Log(levelnameS); //prints to the console
SceneManager.LoadScene(levelnameS); //changes scene based on the level name. In this case its a number because thats what the levels are named.
Debug.Log(levelname);
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Return))
{
LevelChange(); //calls the level change function
}
}
}
levelname is a instance property. Each instance of class NextLevel has own value of this. So if you every time create new instance of NextLevel and call Update count always start from 1.
You can switch levelname to static property or always use one instance of class NextLevel.
use public static int levelname = 1;
instead of int levelname=1

Where do I instantiate a C# form class so it's properties are available to other classes?

I'm a beginner with C# and I think there is something fundamental about instantiation and passing references that I just do not get.
I am trying to get the default Program class to instantiate 2 other classes, a form called frmGameUI and a class called LocHandler. If this was working correctly the LocHandler would then check the current location and assign the text properties of frmGameUI. For some reason the method to set the properties in LocHandler can not see or get my reference to frmGameUI that I instantiated in Program. What am I doing wrong?
static class Program
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainUI());
GameUI frmGameUI = new GameUI();
frmGameUI.Show();
LocationHandler LocHandler = new LocationHandler();
LocHandler.InitializeRoom();
}
And here is the LocHandler class:
class LocationHandler
{
private string currentRoom = "LivingRoom";
public void InitializeRoom()
{
if (currentRoom == "LivingRoom")
{
frmGameUI.btnLocation1.Text = "Bedroom";
frmGameUI.btnLocation2.Text = "Kitchen";
frmGameUI.btnLocation3.Text = "Patio";
}
}
}
in LocHandler, VS is telling me that frmGameUI does not exist in this context. I'm sure there is something fundamental and simple I just don't grasp here. Any help is appreciated!
Yes, you're definitely missing some fundamental concepts. In C# variables aren't global. They have scope, see: http://msdn.microsoft.com/en-us/library/aa691132(v=vs.71).aspx. In your case, the scope of GameUI frmGameUI = new GameUI(); is local to the the method that you declared it in. So, nobody outside of that method can see that variable. That is to say, they can't see the variable by that name. That's NOT to say that you can't pass that variable to another method. So, if you need the LocationHandler class to deal with that variable, then perhaps you should pass it to the InitializeRoom method. Like this:
LocHandler.InitializeRoom(frmGameUI);
Note that your method signature would change to:
public void InitializeRoom(GameUI gameui)
and then your code in that method would refer to the gameui variable.
///<snip>
gameui.btnLocation1.Text = "Bedroom";
gameui.btnLocation2.Text = "Kitchen";
gameui.btnLocation3.Text = "Patio";
Make sense?
Execution of the Main method will stop on this line, while the main form is showing.
Application.Run(new MainUI());
So what you probably want to do is move the code to create LocationHandler above this line, and pass it in to GameUI. (and also replace MainUI with GameUI)
Create different class with initialized instances and keep them there as public's

Categories