Can't read updated variable - c#

I need to stop/resume the rotation of a fan when a certain key is pressed, so I wrote this C# code:
public bool rotationFlag = false;
void Update()
{
if(rotationFlag)
{
fan.transform.Rotate(Vector3.up, rotationAngle);
}
}
public void commuteFan()
{
rotationFlag = !rotationFlag;
}
cummuteFan() method is called when I press the button.
the variable starts on false and the fan correctly doesn't ratate, when I hit the button, the method is called, the variable values changes and the starts to rotate, but if I want to stop it, it doesn't work anymore. debug tells me that the value is correctly changed to false in commuteFan() but update() continues to read the old value (true) and the fan doesn't stop.

[SOLVED] I don't know why, but I created a class with only the bool along with getter/setter methods in it and it works know

So you had your variable as public, which means that any other part of the project could easily edit it. In your case you were changing it via the editor.
To avoid this kind of problems in the future try using protection.
public class Test : MonoBehaviour
{
private bool isRotating = false;
public void setIsRotating(bool status)
{
isRotating = status;
}
public bool getIsRotating()
{
return isRotating;
}
}
Coding like this will save you a lot of headaches later on.

Related

Using the same boolean in two different scripts in Unity

I'm a total beginner at Unity and I don't understand how to use a variable in two different scripts.
For example, let's say that I have a script called "player" and another called "logic".
In the player script, I create the boolean "IsAlive", and when I collide with something, I die :
public class PlayerScript : MonoBehaviour
{
public bool IsAlive = True;
}
private void OnCollisionEnter2D(Collision2D collision)
{
IsAlive = False;
}
Now, I want to do something in the "Logic" script and have to check if the player is alive or not before. How do I do that ? I tried something like :
public class LogicScript : MonoBehaviour
{
public PlayerScript PlayerScript_logic;
private bool IsAlive_logic = PlayerScript_logic.IsAlive;
}
so that I could use "IsAlive_logic" which would be the same as "IsAlive".
But that is apparently not how if works.
If somebody could help me, please, I'm so lost.
Simply instead of IsAlive_logic in all places use PlayerScript_logic.IsAlive. Despite the fact that you can't access a non-constant field (PlayerScript_logic) when declaring your other fields - it is bad practice to store (and maintain) the same value in multiple places anyway ;)
Alternatively if you really for some reason want/need to you could have a property
private bool IsAlive_logic => PlayerScript_logic.IsAlive;
// or also
//private bool IsAlive_logic { get => PlayerScript_logic.IsAlive; }
// or also
//private bool IsAlive_logic { get { return PlayerScript_logic.IsAlive; } }
which basically simply returns PlayerScript_logic.IsAlive everytime you access it. In general this adds some tiny overhead though and it would be better to go through the PlayerScript_logic.IsAlive directly...

Unity c#: Code-structure or how to access a method/variable from another class/script?

I have two classes: Menu_Buttons, in which there are definitions for methods executed on clicking different buttons in the menu, and PauseMenu, which defines what happens when the Menu key is pressed during the game.
Menu_Buttons:
public class Menu_Buttons : MonoBehaviour
{
public void Menu_NewGameClick()
{
SceneManager.LoadScene(1);
}
public void Menu_ContinueClick()
{
Debug.Log("This will continue the game from the last save");
}
public void Menu_LoadGameClick()
{
SceneManager.LoadScene(1);
Debug.Log("Another menu will show to choose which save to load");
}
public void Menu_SaveGameClick()
{
SaveItem();
Debug.Log("This will save the game");
}
public void Menu_OptionsClick()
{
Debug.Log("This will show the game options");
}
public void Menu_QuitClick()
{
Application.Quit();
Debug.Log("The Game should quit now");
}
}
PauseMenu:
public class PauseMenu : MonoBehaviour
{
//private bool isPauseMenuOpened = false;
public GameObject pauseMenu;
void Update()
{
if (Input.GetKeyDown(KeyCode.B))
{
if (pauseMenu.activeSelf) { ClosePauseMenu(); }
else { OpenPauseMenu(); }
}
}
public void OpenPauseMenu()
{
pauseMenu.SetActive(true);
Cursor.visible = true;
Cursor.lockState = CursorLockMode.Confined;
//isPauseMenuOpened = true;
Time.timeScale = 0f;
}
public void ClosePauseMenu()
{
pauseMenu.SetActive(false);
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
//isPauseMenuOpened = false;
Time.timeScale = 1f;
}
}
I wanted to add another method called Menu_ResumeClick, which would resume the game from the Pause Menu. Of course, I could just create this method in the PauseMenu script and then everything is fine. It looks like this:
public void Menu_ResumeClick()
{
ClosePauseMenu();
}
But since I would like to keep things organised, I thought it would be better to put this method in the Menu_Buttons script along with all the other similar methods. So I tried this:
public void Menu_ResumeClick()
{
PauseMenu.ClosePauseMenu();
}
And then problems begin... I get an error: an object reference is required for the non-static field method or property. Then if I change any of those classes to static, I get errors saying: cannot declare instance members in a static class. Not to mention that static classes canot inherit from MonoBehaviour. Maybe I would be able to solve those problems somehow, but the thing is I don't want to change the whole code just because I would rather have a method in another class. It's just for keeping things organised, nothing more.
I have to admit that I'm a bit frustrated by how these things work. I can easily put the Menu_ResumeClick() method in the PauseMenu class, but in the future it may be difficult to keep track of things if I have various methods scattered around different scripts. The most reasonable solution is to put every menu button in the Menu_Buttons class and then access them from there, but it poses problems that I described. Actually this is not the first time when I'm having problems with accessing methods or variables from other classes - there always seem to be some difficulties. It seems the best way to write code would be to just have a single class for the whole game because then I would be able to access absolutely anything easily - but again the problem would be with keeping things organised.
So, the question is: can I easily use methods (or variables) from other classes, without changing the whole code for this purpose? In other words can I somehow just call a method from another class like this: className.MethodName(); or set a variable from another class like this: className.varName = 2; without making everything static, etc.?
And a bonus question: If it's not possible, then how should I structure my code? Should I try to squeeze as many things as possible into a single class to be able to access them easily, should I make classes static, whenever it's possible, etc.?
In PauseMenu, you can add a field for the Menu_Buttons, which Unity can serialize, so you can pull the GameObject (what contains the Menu_Buttons) in the inspector, and you can call its public methods (and access its public members) from PauseMenu.
public Menu_Buttons MenuButtons;
// or (I much more like this version, keeping things as encapsulated as possible)
[SerializeField] private Menu_Buttons _menuButtons;
private void Resume() => _menuButtons.Menu_ResumeClick();
Edit based on comments:
Both script can have references to each other. As both logically related, I wouldn't separate them, because with the references, we couple them anyway.
Example:
public class Menu_Buttons : MonoBehaviour
{
[SerializeField] private PauseMenu _pauseMenu;
public void Menu_ResumeClick() => _pauseMenu.ClosePauseMenu();
// ...
}
public class PauseMenu : MonoBehaviour
{
[SerializeField] private Menu_Buttons _menuButtons;
// ...
public void ClosePauseMenu()
{
// ...
}
}

How to run a method in all scenes – Unity?

is there such a way to run a method in all scenes in unity without passing data from one screen to another? What I want to do is assume that I have a method which counts the time like stopwatch. When I open the game it starts counting on main screen like 1,2,3... and when I go another screen it should keep running the method and continue counting 4,5,6... and it should continue like this when I switch to other screens.
I thought that it can be done using a static variable in a script and using the same script in all scenes in a game object. But I wonder if there is an easier approach as I said in above like running one global method in all screens once game is launched.
Here is an example of class, that logs value every second. You can change ShowCurrentValue function to one you need. This will work, regardless of changing scene. You can start and stop it with corresponding fucntions from any place in project.
using UnityEngine;
using System.Threading;
public class Counter
{
public static ulong CurrentValue { get; set; } = 0;
private static Thread cThread = null;
public static void Start()
{
if (cThread == null)
cThread = new Thread(ShowCurrentValue);
cThread.Start();
}
public static void Pause()
{
if (cThread != null)
{
cThread.Abort();
CurrentValue++;
}
cThread = null;
}
private static void ShowCurrentValue()
{
while (true)
{
Debug.Log(CurrentValue);
Thread.Sleep(1000);
CurrentValue++;
}
}
}
You are looking LoadAdditive I believe. Also check the docs once LoadAdditive
SceneManager.LoadScene("YourScene", LoadSceneMode.Additive);

Acessing custom property with AddComponent

In Unity3D I've got a script that adds the variable 'eaten' as a component.
using UnityEngine;
[AddComponentMenu("My game/IsEaten")]
public class IsEaten : MonoBehaviour
{
public bool Eaten;
}
Yay! I can then add another script to access 'Eaten'
using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour
{
private Eaten someScript;
// Use this for initialization
void Start ()
{
someScript = GetComponent<IsEaten>();
bool temp = someScript.Eaten;
print(temp); // false
}
}
Which works fine. What do I have to do to access the variable with dot notation from another script? ie
if (myCube.eaten == true)
{
// do something
}
You know, in Unity one does rarely create the whole script to add a single property to some object. The common approach is to think of scripts as 'components' (which they are, in fact). Let me explain this, a component is a single piece of code that add certain functionality to your GameObject, like ability to animate, or to behave the laws of physics. So, maybe, it would be better to reform your IsEaten class to form a true component, like Pickup (I'm assuming that you need Eaten property for the pickup of some sort) that will have functionality to be eaten by a player, or something.
// You will actually need to attach a collider (and check the 'IsTrigger' checkbox on it) to your GameObject
// Then this method will be called whenewer some game object with a collider (e. g. player, npc's, monsters) will enter the trigger of this object
void OnTriggerEnter(Collider other)
{
// Check whether this object was eaten before and if the actor entering our trigger is actually the player
if (!Eaten && other.tag == "Player")
{
// Make shure that we will not get eaten twice
Eaten = true;
// Apply some effect to the player that has devoured us
other.GetComponent<Player>().AddHp(25);
}
}
Other than that, I'm personally thinking, that getting out of your way to simply enable a little sweeter syntax is not worth the hassle, but, if you provide some insight of what are you actually trying to implement, I may try to help you with it :)
One way to do it might be using Get/Set:
using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour
{
private Eaten someScript;
// start new!
public bool eaten
{
get
{
return someScript.Eaten;
}
set
{
someScript.Eaten = value;
}
}
// end new!
// Use this for initialization
void Start ()
{
someScript = GetComponent<IsEaten>();
bool temp = someScript.Eaten;
print(temp); // false
}
}
Then you can access the Test class property:
Test t = GetComponent<Test>();
t.eaten = true;
ath.

Can't pass data between classes

I am developing a Kinect application based on VS2012 using winform. After I tried several methods, I still couldn't pass value from one class to another class.
Basically I have three class, a public MainWindow(), public partial FaceTrackingViewer(), and public SkeletonFaceTracker(). The last class reside in FaceTrackingViewer() class.
In SkeletonFaceTracker(), I have the following:
public bool lastFaceTrackSucceeded { get; set; }
internal void OnFrameReady(KinectSensor kinectSensor, ColorImageFormat colorImageFormat, byte[] colorImage, DepthImageFormat depthImageFormat, short[] depthImage, Skeleton skeletonOfInterest)
{
// something else
if (this.faceTracker != null)
{
this.lastFaceTrackSucceeded = frame.TrackSuccessful; //where it's set to be true.
//something else
}
}
I also tried to change to first line to:
public bool lastFaceTrackSucceeded;
public bool LastFaceTrackSucceeded
{
get { return lastFaceTrackSucceeded; }
private set { lastFaceTrackSucceeded = value; }
}
I think the two are the same though.
In MainWindow(), I have:
public partial class MainWindow : Window
{
//some other irrelevant code snippets
private FaceTrackingViewer.SkeletonFaceTracker skeletonFaceTracker = new FaceTrackingViewer.SkeletonFaceTracker();
private void button_faceOnly_Click(object sender, RoutedEventArgs e)
{
bool faceTrackSucceeded = skeletonFaceTracker.lastFaceTrackSucceeded;
// if I use the second structure in SkeletonFaceTracker(), it should be:
// bool faceTrackSucceeded = skeletonFaceTracker.LastFaceTrackSucceeded;
if (faceTrackSucceeded == true )
{
//do something
}
}
}
However, the bool faceTrackSucceeded is always false, even if the lastFaceTrackSucceeded or LastFaceTrackSucceeded in SkeletonFaceTracker() is true. I am very confused and don't know where it went wrong.
Please note that all the video processing and face tracking actions occur in FaceTrackingViewer() class. I simply want to pass some parameters and structures to MainWindow().
Thank you
One thing first - I assume you are making the variable lastFaceTrackSucceeded public purely for testing purposes. The two ways of defining the property are functionally the same in your example.
The only other thing I can think of is that you are setting LastFaceTrackSucceeded true on a different instance of SkeletonFaceTracker. You haven't provided enough code for me to be sure about this, but if you have two (or more) instances then it can be easy to get them mixed up.

Categories