- Home /
How do I get a U.I. image to remember if it is active or Not Active Across Scene Changes Using Arduino
I have part of my interface on a slide in animated panel on a canvas that lights up a indicator light (U.I. button) Now if I set it for open the indicator light switches switches to active and the other indicator switches to un active via a manager C# script.
Now how do I retain that data across scene changes?
I tried putting the Don't destroy on load on my manager script but weird things happen. For one it does not carry the data across scene changes, secondly if I remove the Don't destroy on load stuff to put my script back to normal then my indicators don't respond to the make active and not active portion of the IEnumerator part of the script.
How can I fix this?
Here is a portion of my script that has the Autodoors set active and un active functions.
NOTE: I placed some images in the comments below of my inspector and the U.I. Panel that has the indicator lights on it that I am wanting to remember their settings when I leave that main scene and go to other scene and then return to the main scene.
//Auto Door Left
public void GoAutoDoorLeft(){
StartCoroutine(AutoDoorL());
//Star Indicator Light On Coroutine
StartCoroutine(AutoDoorLindicatorOn());
}
//Indicator L On Initiator
IEnumerator AutoDoorLindicatorOn(){
yield return new WaitForSeconds (2.0f); // wait time
//initiate Indicator light On
AutoDoorOpenLightOnLeft.SetActive(!AutoDoorOpenLightOnLeft.active);
AutoDoorCloseLightOnLeft.SetActive(!AutoDoorCloseLightOnLeft.active);
GetComponent<AudioSource>().PlayOneShot(DTMFtone01);
}
IEnumerator AutoDoorL(){
yield return new WaitForSeconds (0.5f); // wait time
anim.enabled = true;
//play the Slidein animation
anim.Play("AutoDoorsIndicatorsSlideInAni");
GetComponent<AudioSource>().PlayOneShot(AutoDoorSlideInFX);
}
//Auto Door Screen Slide Out
public void AutoDoorSlideOut(){
StartCoroutine(AutoDoorOut());
}
IEnumerator AutoDoorOut(){
yield return new WaitForSeconds (3.0f); // wait time
anim.enabled = true;
//play the SlideOut animation
GetComponent<AudioSource>().PlayOneShot(AutoDoorSlideOutFX);
anim.Play("AutoDoorIndicatorsClosed");
}
$$anonymous$$aybe you've lost the reference to the targets, are they destroyed or also carried to the next scene?
I'm not really good with this, but my main scene has a canvas with an animated panel that slides in when called and indicators change on it, what I need is for when I come back to that scene the indicators be in the same setting as when I left that scene, this does not happen and I am at a total loos as to how to make that happen. I keep hearing about singletons but all I find in the way of any tutorial all has to do with the On GUI stuff and NOT what I need here.
There are different ways of saving data across scenes. PlayerPrefs, static variables (i usually don't recommend those), your own file or the DontDestroyOnLoad approach. You could make an object that holds the neccessary information and just pass them back to the UI when the scene is loaded again. You could actually do that with the UI elements itself but that may mess up the whole setup of your scene, as you've already experienced. If the required information are just a few values and of simple types, you can also use the player prefs as a kind of cache. But I personally don't use the PPs for such things unless you also need it across ga$$anonymous$$g "sessions".
Thanks Suddoha, What I could really use is a more detailed in depth explanation of how to do this exactly if you would be so kind ;) ?
This is how I have my Auto Doors slide in screen (Panel) set up in the inspector. Controlled by that portion of the script I posted above.
Answer by Suddoha · Sep 15, 2015 at 11:14 AM
I'm not sure which other logic is coupled with those indicators, you have to make sure the logic applies correctly according to the restored state.
This is just a simple example, using a dictionary to store per-session states and preferences without spamming PlayerPrefs with junk. If you need to retain the data across several starts of the application, you may want to adjust this a little bit.
It's actually just a dictionary wrapped in another class which handles some situations and avoid ugly casts inside your script, this will already do it (unless you save, e.g. a boolean and try to read the value as int or something, of course that's not gonna work). Perhaps you should add some exception handling. You might also want to add more methods like remove entries and so on.
static class StateDictionary
{
private static Dictionary<string, object> myStates = new Dictionary<string, object>();
public static bool GetState<T>(string key, out T state)
{
state = default(T);
object restoredState = null;
if(myStates.TryGetValue(key, out restoredState))
{
state = (T)restoredState;
return true;
}
return false;
}
public static void AddOrReplaceState(string key, object value)
{
if (myStates.ContainsKey(key))
{
myStates[key] = value;
Debug.Log("state replaced");
}
else
{
myStates.Add(key, value);
Debug.Log("state added");
}
}
}
So, how to use that? I'm not entirely sure how scene loading is handled in your game (trigger, UI, time [...]), but here's an example:
In your scene, you should now have an object that is addressed whenever you want to load a scene. This will use the following script. Possible setup: Imagine you've got a button in order to load the next scene, so add the LoadScene method to the onClick event in the inspector or associate it with the existing logic in your project.
public class SceneLoader : MonoBehaviour {
public delegate void OnExitSceneEventHandler();
public event OnExitSceneEventHandler onExitScene;
public void LoadScene(int index)
{
if (onExitScene != null)
onExitScene();
Application.LoadLevel(index);
}
}
And finally, some test object:
public class Example : MonoBehaviour
{
// the object you want to save states from
public GameObject myGO;
// a script that handles loading the next scene
public SceneLoader sceneLoader;
// just a test key
private string testKey = "rendererActivated";
void Awake()
{
// subscribe to the event which the scene loader raises
// before it loads the next level
sceneLoader.onExitScene += SaveState;
// store the tmporary state here, maybe there is none so
// we don't want to apply it directly
bool tmp;
if(StateDictionary.GetState<bool>(testKey, out tmp))
myGO.SetActive(tmp); // we found a state, let's apply it
}
// method that will be called by the event as soon as it's raised
// so put every save-state logic into it
private void SaveState()
{
// just saving the active state (boolean) for a testing purpose
StateDictionary.AddOrReplaceState(testKey, myGO.activeSelf);
}
}
Answer by KnightRiderGuy · Sep 15, 2015 at 01:03 PM
Thanks Suddoha, I'll see if I can do a test scene and see how your solution works, but just to be clear on how those indicator lights are activated I'll post my entire script, it should be at the top of the script the information you were wondering about.
"I'm not sure which other logic is coupled with those indicators"
using UnityEngine;
using System.Collections;
public class ThreeDOverviewManagerScript : MonoBehaviour {
//refrence for the Auto Doors Indicator panel in the hierarchy
public GameObject AutoDoorPanel;
public GameObject AutoDoorOpenLightOnLeft;
public GameObject AutoDoorOpenLightOnRight;
public GameObject AutoDoorCloseLightOnLeft;
public GameObject AutoDoorCloseLightOnRight;
//animator reference
private Animator anim;
//variable for checking if the game is paused
//private bool isPaused = false;
public AudioClip Scanner;
public AudioClip TurboWarning;
public AudioClip TurboBoost;
public AudioClip AutoDoorSlideInFX;
public AudioClip AutoDoorSlideOutFX;
public AudioClip DTMFtone01;
public AudioClip DTMFtone02;
void Start () {
//unpause the game on start
//Time.timeScale = 1;
//get the animator component
anim = AutoDoorPanel.GetComponent<Animator>();
//disable it on start to stop it from playing the default animation
//anim.enabled = false;
}
void Update () {
if (Input.GetButtonDown ("Fire1")) {
//clicked elsewhere on screen
Debug.Log ("Clicked Screen");
}
}
//Plays Auto Door Screen Slidein Sound FX
public void AutoDoorSlideInSoundFX()
{
GetComponent<AudioSource>().PlayOneShot(AutoDoorSlideInFX);
}
//Plays Auto Door Screen SlideOu Sound FX
public void AutoDoorSlideOutSoundFX()
{
GetComponent<AudioSource>().PlayOneShot(AutoDoorSlideOutFX);
}
public void TurboBoostSound()
{
GetComponent<AudioSource>().clip = TurboBoost;
GetComponent<AudioSource>().PlayOneShot(TurboBoost);
if(GetComponent<AudioSource>().isPlaying)
{
GetComponent<AudioSource>().Stop();
}
else
{
GetComponent<AudioSource>().Play();
}
}
public void TurboWarningSound()
{
GetComponent<AudioSource>().clip = TurboWarning;
GetComponent<AudioSource>().PlayOneShot(TurboWarning);
if(GetComponent<AudioSource>().isPlaying)
{
GetComponent<AudioSource>().Stop();
}
/*else
{
audio.Play();
}*/
}
public void ScannerSound()
{
StartCoroutine(LoadS1("ScannerAdjustScreen"));
GetComponent<AudioSource>().clip = Scanner;
GetComponent<AudioSource>().loop = true;
if(GetComponent<AudioSource>().isPlaying)
{
GetComponent<AudioSource>().Stop();
}
else
{
GetComponent<AudioSource>().Play();
}
}
IEnumerator LoadS1(string ScannerAdjustLev){
yield return new WaitForSeconds(3.5f); // wait time
Application.LoadLevel(ScannerAdjustLev);
}
public void GoSurveillance(){
StartCoroutine(LoadT1("SurveillanceModeScreen"));
}
IEnumerator LoadT1(string level01){
yield return new WaitForSeconds(0.5f); // wait time
Application.LoadLevel(level01);
}
public void GoMusicPlayer(){
StartCoroutine(LoadT2("KITT_MusicPlayer"));
}
IEnumerator LoadT2(string level03){
yield return new WaitForSeconds(0.5f); // wait time
Application.LoadLevel(level03);
}
public void GoHomeScreen(){
StartCoroutine(LoadT3("KnightSpinningLogo_NoKITTintro"));
}
IEnumerator LoadT3(string level03){
yield return new WaitForSeconds(0.5f); // wait time
Application.LoadLevel(level03);
}
public void GoAutoDWH(){
StartCoroutine(LoadT4("AutoWindowSDoorsHatchLightsController"));
}
IEnumerator LoadT4(string level04){
yield return new WaitForSeconds(0.5f); // wait time
Application.LoadLevel(level04);
}
public void GoAirVac(){
StartCoroutine(LoadT5("OxygenSupplyScreen"));
}
IEnumerator LoadT5(string level05){
yield return new WaitForSeconds(0.5f); // wait time
Application.LoadLevel(level05);
}
public void GoSystemGuidance(){
StartCoroutine(LoadT6("SystemGuidanceScreen"));
}
IEnumerator LoadT6(string level06){
yield return new WaitForSeconds(0.5f); // wait time
Application.LoadLevel(level06);
}
public void GoComLinkClock(){
StartCoroutine(LoadT7("KnightRiderComLinkClock"));
}
IEnumerator LoadT7(string level07){
yield return new WaitForSeconds(0.5f); // wait time
Application.LoadLevel(level07);
}
public void GoAnalyzer(){
StartCoroutine(Analyzer01("Analyzer"));
}
IEnumerator Analyzer01(string analyzer){
yield return new WaitForSeconds (0.5f); // wait time
Application.LoadLevel (analyzer);
}
public void GoVoiceBox(){
StartCoroutine(VoiceBox01("VBscene"));
}
IEnumerator VoiceBox01(string VoiceBox){
yield return new WaitForSeconds (0.5f); // wait time
Application.LoadLevel (VoiceBox);
}
public void GoTemperature(){
StartCoroutine(Temperature01("InteriorTemperatureScreen"));
}
IEnumerator Temperature01(string Temperature){
yield return new WaitForSeconds (0.5f); // wait time
Application.LoadLevel (Temperature);
}
public void GoLaser(){
StartCoroutine(Laser01("LaserChargeScreen"));
}
IEnumerator Laser01(string Laser){
yield return new WaitForSeconds (0.5f); // wait time
Application.LoadLevel (Laser);
}
public void GoMicroJam(){
StartCoroutine(MicroJam01("MicroJamScene"));
}
IEnumerator MicroJam01(string MicroJam){
yield return new WaitForSeconds (0.5f); // wait time
Application.LoadLevel (MicroJam);
}
public void GoAnharmonicSynth(){
StartCoroutine(LoadAnSynth("AnharmonicSynthesizerScene"));
}
IEnumerator LoadAnSynth(string level03){
yield return new WaitForSeconds(0.5f); // wait time
Application.LoadLevel(level03);
}
//Spare Button
public void GoMultipleWebCams(){
StartCoroutine(LoadWebCams("MultipleWebCameras"));
}
IEnumerator LoadWebCams(string MultiWebCams){
yield return new WaitForSeconds(0.5f); // wait time
Application.LoadLevel(MultiWebCams);
}
//End Spare button
//Slide Show Button
public void GoSlideShow(){
StartCoroutine(LoadSlideShow("SlideShow"));
}
IEnumerator LoadSlideShow(string Slideshow){
yield return new WaitForSeconds(0.5f); // wait time
Application.LoadLevel(Slideshow);
}
//End Slide Show button
//Alpha Circuit Button
public void GoAlphaCircuit(){
StartCoroutine(LoadAlphaCircuit("KITTsAlphaCircuitScan"));
}
IEnumerator LoadAlphaCircuit(string Alpha){
yield return new WaitForSeconds(0.5f); // wait time
Application.LoadLevel(Alpha);
}
//End Alpha Circuit button
//Auto Door Left
public void GoAutoDoorLeft(){
StartCoroutine(AutoDoorL());
//Star Indicator Light On Coroutine
StartCoroutine(AutoDoorLindicatorOn());
}
//Indicator L On Initiator
IEnumerator AutoDoorLindicatorOn(){
yield return new WaitForSeconds (2.0f); // wait time
//initiate Indicator light On
AutoDoorOpenLightOnLeft.SetActive(!AutoDoorOpenLightOnLeft.active);
AutoDoorCloseLightOnLeft.SetActive(!AutoDoorCloseLightOnLeft.active);
GetComponent<AudioSource>().PlayOneShot(DTMFtone01);
}
IEnumerator AutoDoorL(){
yield return new WaitForSeconds (0.5f); // wait time
anim.enabled = true;
//play the Slidein animation
anim.Play("AutoDoorsIndicatorsSlideInAni");
GetComponent<AudioSource>().PlayOneShot(AutoDoorSlideInFX);
}
//Auto Door Screen Slide Out
public void AutoDoorSlideOut(){
StartCoroutine(AutoDoorOut());
}
IEnumerator AutoDoorOut(){
yield return new WaitForSeconds (3.0f); // wait time
anim.enabled = true;
//play the SlideOut animation
GetComponent<AudioSource>().PlayOneShot(AutoDoorSlideOutFX);
anim.Play("AutoDoorIndicatorsClosed");
}
//////////////////////////////////////////////////
//Auto Door Right
public void GoAutoDoorRight(){
StartCoroutine(AutoDoorR());
//Star Indicator Light On Coroutine
StartCoroutine(AutoDoorRindicatorOn());
}
//Indicator R On Initiator
IEnumerator AutoDoorRindicatorOn(){
yield return new WaitForSeconds (2.0f); // wait time
//initiate Indicator light On
AutoDoorOpenLightOnRight.SetActive(!AutoDoorOpenLightOnRight.active);
AutoDoorCloseLightOnRight.SetActive(!AutoDoorCloseLightOnRight.active);
GetComponent<AudioSource>().PlayOneShot(DTMFtone02);
}
IEnumerator AutoDoorR(){
yield return new WaitForSeconds (0.5f); // wait time
anim.enabled = true;
//play the Slidein animation
anim.Play("AutoDoorsIndicatorsSlideInAni");
GetComponent<AudioSource>().PlayOneShot(AutoDoorSlideInFX);
}
//Auto Door Screen Slide Out
public void AutoDoorSlideOutR(){
StartCoroutine(AutoDoorOutR());
}
IEnumerator AutoDoorOutR(){
yield return new WaitForSeconds (3.0f); // wait time
anim.enabled = true;
//play the SlideOut animation
GetComponent<AudioSource>().PlayOneShot(AutoDoorSlideOutFX);
anim.Play("AutoDoorIndicatorsClosed");
}
}
I'm wondering if perhaps I'm approaching this in the wrong way? Perhaps what I really need is for Unity to read back the status on the door if closed or open via something like this method only not done through sockets but through the I.O. port?
Alternate methode of reading the status of the door back from the Arduino
I'm not sure why you start with sockets and I/O from an Arduino now. The topic is about remembering states when the scene has been changed and the way I've suggested works perfectly. What issues do occur now?
Well it goes like this ;) I was thinking the other day that because this is going inside of the car that if the car door was open then Arduino would already have a light on status but Unity would have no clue so if the software in the dash was started up and the door was open it would be out of sync. So I thought that somehow being able to read the light states back from the Arduino would be more reliable because then it could update the U.I. indicator like in the you tube demo, only I would need it not through sockets but just through the com port. You have to remember the context of what I need this to function for. ;)
Oh plus I have not yet had a chance to test out your method as I was busy and I was a little unsure how to integrate it into what I already have.
Your answer
Follow this Question
Related Questions
setActive on object in separate scene 2 Answers
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
How to set the position of an object in another scene? 1 Answer