1

I have a strange issue with a game that I'm making. For some reason, whenever I change to another scene from my menu, the menu can be seen in the background and its buttons are active. So a player could tap on a space where a menu button was (while not actually being on the menu screen) and get an unintended response. It only happens on this one scene; all other scenes work correctly. Here's the script with the problem.

    using UnityEngine;
    using System.Collections;



public class Menu : MonoBehaviour 
{
    //public Texture2D background;
    public GUITexture backgroundCopy;
    public GUITexture background;
    float bgPos, bgCopyPos;
    public GUISkin buttonSkin;
    public GUISkin recordSkin;
    public GUIText guiRecordLabel;
    public GUIText guiTime;
    public GUIText guiComplete;
    public GUIText guiTurns;
    public GUIText guiLosses;
    public GUIText guiQuits;

    Records records = new Records();

    //public static Menu instance = null;
    private bool onMenuScreen;              //this prevents the menu buttons from being pressed when I'm not on the menu. weird issue.

    void Awake()
    {
        //ScreenFader.fadeToBlack = false;
        //create a singleton so that there's only one instance of a menu at any time.
        //if (instance != null)
        //    DestroyObject(this);    //destroys the new instance
        //else
        //    instance = this;

        //menu needs to persist for the duration of the game because I want the music to keep playing across multiple screens. -THIS IS NO LONGER THE CASE
        //DontDestroyOnLoad(this);

        //load records
        records.LoadRecords();

    }
    // Use this for initialization
    void Start () 
    {
        bgPos = 0;                  //initial x Position of the background
        bgCopyPos = -Screen.width;  //this is placed before the original background.
        onMenuScreen = true;        //I SHOULDN'T NEED THIS

    }





    // Update is called once per frame
    void Update () 
    {
        if (!onMenuScreen)  //I need to do this check because the menu persists and remains on screen.
        {
            guiRecordLabel.enabled = false;
            guiTime.enabled = false;
            guiComplete.enabled = false;     //I shouldn't need any of this
            guiTurns.enabled = false;
            guiLosses.enabled = false;
            guiQuits.enabled = false;
        }
        else
        {
            guiRecordLabel.enabled = true;
            guiTime.enabled = true;
            guiComplete.enabled = true;
            guiTurns.enabled = true;
            guiLosses.enabled = true;
            guiQuits.enabled = true;
        }

        //show records
        guiRecordLabel.material.color = Color.red;
        guiTime.text = "Total Time: " + records.TotalTime;
        guiComplete.text = "Completion: " + records.CompletionRate + "%";
        guiTurns.text = "Turn Total: " + records.TurnTotal;
        guiLosses.text = "Total Losses: " + records.LossCount;
        guiQuits.text = "Rage Quits: " + records.RageCount;



        //scroll the background. TODO: provide different backgrounds
        bgPos = (bgPos > Screen.width) ? -Screen.width + 2 : bgPos += 1;
        bgCopyPos = (bgCopyPos > Screen.width) ? -Screen.width + 2 : bgCopyPos += 1;

        background.pixelInset = new Rect(bgPos, background.transform.position.y, Screen.width, Screen.height);
        backgroundCopy.pixelInset = new Rect(bgCopyPos, background.transform.position.y, Screen.width, Screen.height);


    }

    void OnGUI()
    {


        //buttons
        GUI.skin = buttonSkin;
        if (onMenuScreen && GUI.Button(new Rect(60 * Title.scale.x, 400 * Title.scale.y, 130 * Title.scale.x, 33 * Title.scale.y), "Level Select"))
        {           
            Application.LoadLevel("LevelSelectScreen");
            onMenuScreen = false;
        }

        if (onMenuScreen && GUI.Button(new Rect(300 * Title.scale.x, 400 * Title.scale.y, 130 * Title.scale.x, 33 * Title.scale.y), "Help & Options"))
        {         
            Application.LoadLevel("HelpScreen");
            onMenuScreen = false;
        }

        if (onMenuScreen && GUI.Button(new Rect(540 * Title.scale.x, 400 * Title.scale.y, 130 * Title.scale.x, 33 * Title.scale.y), "Back to Title"))
        {
            //DestroyObject(this);    //Kill the menu whenever I return to title screen.         
            Application.LoadLevel("TitleScreen");
            onMenuScreen = false;
        }
    }
}

I thought the issue might have been the second script that I have on the scene, but I disabled it and I have the same problem. Here's the other script.

   /* This script is used to allow music to persist between screens. It uses a singleton to prevent more than once instance
 * from being created. This script must be placed in MenuScreen scene. */

using UnityEngine;
using System.Collections;
using System.IO;
using System;

public class MusicPlayer : MonoBehaviour 
{

    public static MusicPlayer instance = null;
    AudioClip track;        //copy of the music currently playing.
    public AudioClip[] musicTracks;
    AudioSource source;
    private bool musicPlaying;
    private short trackNumber;

    void Awake()
    {
        //create a singleton so that there's only one instance of a music track at any time.
        if (instance != null)
            DestroyObject(this);    //destroys the new instance
        else
            instance = this;


        DontDestroyOnLoad(this);
    }
    // Use this for initialization
    void Start () 
    {
        source = GetComponent<AudioSource>();
        LoadTrackFile();
    }

    public string TrackName
    {
        get { return musicTracks[trackNumber].name; }
    }

    public short TrackNumber
    {
        get { return trackNumber; }
        set { trackNumber = value; }
    }

    public bool MusicPlaying
    {
        get { return musicPlaying; }
        set { musicPlaying = value; }
    }

    /* Create/update a file to save track number. */
    public void UpdateTrackFile()
    {
        string directory = Application.persistentDataPath + "/Tile Crusher/Data/";
        string fileName = "trackfile.savefile";

        //initialize track number if file doesn't exist.
        if (!File.Exists(directory + fileName))
        {
            trackNumber = 0;
        }

        FileStream fs = new FileStream(directory + fileName, FileMode.OpenOrCreate);
        StreamWriter writer = new StreamWriter(fs);

        //write track number to file
        writer.WriteLine(trackNumber);

        writer.Close();
        fs.Close();
    }

    void LoadTrackFile()
    {

        //start searching and reading files
        string directory = Application.persistentDataPath + "/Tile Crusher/Data/";
        string fileName = "trackfile.savefile";


        //locate the file.  If it doesn't exist, it will be created.
        if (!File.Exists(directory + fileName))
        {
            UpdateTrackFile();
        }

        //read data. The file is read in a specific order.
        FileStream fs = new FileStream(directory + fileName, FileMode.Open);
        StreamReader fileRead = new StreamReader(fs);

        //load track number
        string track = fileRead.ReadLine();
        trackNumber = Int16.Parse(track);

        //done   
        fileRead.Close();
        fs.Close();


    }

    // Update is called once per frame
    void Update () 
    {

        if (!musicPlaying && trackNumber >= 0)
        {
            //play music
            source.clip = musicTracks[trackNumber];
            source.Play();
            musicPlaying = true;
        }
        else if (trackNumber < 0)
            source.Stop();


}

What's bugging me is that this issue is occurring only on this one scene. All my other scenes work fine. I used a workaround, but I don't think I need to do such a thing for this one scene. Can anyone help with this?

King
  • 45
  • 6

1 Answers1

0

I would refactor the Menu class so that you can disable it a a whole when no needed for two reasons:

  1. The code on Update is needed only when you are actually in the menu scene
  2. OnGui is pretty expensive as it is called several times per frame

You can make an empty game object MenuManager or even better SceneManager kind of persistent using Object.DontDestroyOnLoad. So enabling and disabling the Menu object can be done in this class.

Maybe Unity singleton manager classes can give you some inspiration. I use this approach to keep the hierarchy small and clean. All my scenes contain a game object _ApplicationStartup from a prefab which contains the initial bootstrap code and some enhancements for development. When your project is growing and has a couple of scenes, I highly recommend to have your scenes designed in a way that you can testing scenes directly. When you are working on scene Level-5, it's totally annoying if you have to switch back to main scene for testing.

Community
  • 1
  • 1
Kay
  • 12,918
  • 4
  • 55
  • 77
  • Yeah, I know about OnGUI's performance issues. I was in the process of moving away from it when I asked my question. Who knows, maybe it will fix the issue I'm having. – King May 20 '13 at 14:25
  • I used to work with Unity's built-in GUI system, but then switched to NGUI - one of my best decisions. Maybe they will do something similar, the NGUI guy is now working at Unity. – Kay May 20 '13 at 15:29
  • So after eliminating OnGUI and switching to GUITextures, there's been some improvement. The buttons are no longer active in the background when switching screens. So it seems OnGUI was responsible for part of the problem. I'm still not sure of the cause of the issue, though. I think I'll make the SceneManager script as suggested. – King May 20 '13 at 18:35