Switch between canvas

How would I go about switching between multiple canvas?
Up until now I have just enabled and disabled the “canvas” component, but this means I can still interact with the buttons. I ran into this problem when I closed a canvas after opening it, and then jumped. This disabled the players movement scripts (like it should do when I open a canvas) and tried to do what the buttons were supposed to do.

  • So my question is, how would I go about switching between multiple canvas, without having to define every single canvas?

I have a bunch of canvases I toggle on and off.

Short answer, the main thing is to get the UnityEngine.CanvasGroup’s and set the .alpha .interactable and .blocksRaycasts properties, as desired.

Long answer; Here’s an Abstract class the individual controller scripts for each canvas implement, it may be of use. It also fades them in & out. Client code must implement PostMenuClose() which can be custom code called when the manu/panel is closed. Take from it what you like :slight_smile:

using UnityEngine;
using System.Collections;

public abstract class AbstractFadePanel : MonoBehaviour
{

	protected UnityEngine.UI.Text[] textEls;
	protected CanvasGroup RootCanvasGroup;
	public abstract bool MenuOpen { get; protected set; }
	public abstract void PostMenuClose ();

	UnityEngine.UI.Image[] imageEls;

	bool firstTime = true;

	const float FADE_TIME = 0.2f;

	void Awake ()
	{
		RootCanvasGroup = gameObject.GetComponentsInChildren<UnityEngine.CanvasGroup> () [0];
		if (RootCanvasGroup == null)
			RootCanvasGroup = gameObject.GetComponent<UnityEngine.CanvasGroup> ();

		textEls = gameObject.GetComponentsInChildren<UnityEngine.UI.Text> (includeInactive: true);
		imageEls = gameObject.GetComponentsInChildren<UnityEngine.UI.Image> (includeInactive: true);
	}


	/// <summary>
	/// Toggles the visibility of the entire panel
	/// </summary>
	/// <param name="turnOn">If set to <c>true</c> turn on.</param>
	public void ToggleVisibility (bool turnOn)
	{
		// Until used, the menus may exist in the editor in a crippled state
		if (firstTime) {
			RootCanvasGroup.alpha = 1;
			RootCanvasGroup.interactable = true;
		}

		RootCanvasGroup.interactable = turnOn;

		// Remove focus from the menu so arrow keys don't also move through widgets
		//  after it's been hidden.
		UnityEngine.EventSystems.EventSystem.current.SetSelectedGameObject (null);

		// Fade out constituent els
		float targetAlpha = turnOn ? 1f : 0f;

		foreach (var t in textEls)
			t.CrossFadeAlpha (targetAlpha, FADE_TIME, false);

		foreach (var i in imageEls)
			i.CrossFadeAlpha (targetAlpha, FADE_TIME, false);

		if (turnOn)
			StartCoroutine (ForceInteractableRedraw ());
	}
		

	/// <summary>
	/// Closes the menu
	/// </summary>
	protected void closeMenu ()
	{
		if (!UI.UIRegistry.GetClickLock ())
			return;

		RootCanvasGroup.interactable = false;
		RootCanvasGroup.blocksRaycasts = false;
		MenuOpen = false;
		ToggleVisibility (turnOn: false);
		PostMenuClose ();
	}


	/// <summary>
	/// Opens the menu
	/// </summary>
	protected void openMenu ()
	{
		RootCanvasGroup.interactable = true;
		RootCanvasGroup.blocksRaycasts = true;
		MenuOpen = true;
		ToggleVisibility (turnOn: true);
	}


	/// <summary>
	/// For some reason toggling Interactable does not ensure the objects will
	/// redraw correctly to reflect the new state.  This forces it.
	/// Note Canvas.ForceUpdateCanvases() sounds like it should address this, but couldn't
	/// get it working in a quick test.
	/// </summary>
	/// <returns>The interactable redraw.</returns>
	IEnumerator ForceInteractableRedraw ()
	{
		yield return new WaitForSeconds (0.04f);
		RootCanvasGroup.interactable = false;
		RootCanvasGroup.interactable = true;
	}
}