Forum rules - please read before posting.

How to show a menu from code?

edited May 2017 in Technical Q&A

I want to specify a menu to turn on a menu with code, is there any reference on how to do that ? Edit: solved i ran a cut scene from code instead. 

Comments

  • edited May 2017
    AC.Menu myMenu = AC.PlayerMenus.GetMenuWithName ("MyMenuTitle");
    myMenu.TurnOn ();
  • Nice!..  I like the easy access to everything.
  • Hey Chris, I'm new here and I'd like to say thanks for the Adventure Creator! It's a really amazing tool!

    I have a problem in my code: the "TurnOn" method is not activating the Menu during the game. The code is below, as well as images. The idea is to make the Menu activate whenever an objective has its state changed.

    public class QuestHUDInGame : MonoBehaviour
    {
        private void Awake() { EventManager.OnObjectiveUpdate += OnObjectiveUpdate; }
    
        //AC: An event triggered when a Objective's state is changed
        private void OnObjectiveUpdate(Objective objective, ObjectiveState state)
        {
            //Get the Menu elements
            AC.Menu objectiveMenu = KickStarter.menuManager.GetMenuWithName("ObjectiveInGame");
            AC.MenuLabel titleMenu = objectiveMenu.GetElementWithName("QuestTitle") as MenuLabel;
            AC.MenuLabel stateMenu = objectiveMenu.GetElementWithName("QuestState") as MenuLabel;
    
            //Change the HUD information
            titleMenu.label  = objective.GetTitle();
            stateMenu.label = state.GetLabel();
    
            //Refreshing the Menu
            objectiveMenu.TurnOn();
            KickStarter.playerMenus.RebuildMenus (KickStarter.menuManager);
        }
    
    }
    
  • edited February 2022

    Welcome to the community, @davimedio01.

    There are two GetMenuWithName functions in AC - one inside MenuManager, and another inside PlayerMenus. You'll want to call the latter, not the former, to affect Menus at runtime:

    AC.Menu objectiveMenu = PlayerMenus.GetMenuWithName("ObjectiveInGame");
    

    Bear in mind that your Menu must have an Appear type set to Manual for it to be turned on via script. Otherwise, you'll need to unlock the menu instead:

    objectiveMenu.IsLocked = false;
    

    You'll also want to unregister your event hook inside an OnDisable function, so that the event isn't registering multiple times upon re-enabling the script. Use this instead of your current Awake function:

    private void OnEnable() { EventManager.OnObjectiveUpdate += OnObjectiveUpdate; }
    private void OnDisable() { EventManager.OnObjectiveUpdate -= OnObjectiveUpdate; }
    
  • Thank you so much! I read the rules right now, so sorry about the beggining lmao.
    You tool is really really nice! The code above works much fine, really thank you again!

  • Sorry to hijack an old thread.
    I want to take a screenshot with any menus (except "DisplayStand", UnityUI) showing so I'm trying to

    • Check if "DisplayStand" is on
    • Backup all menus with PreScreenshotBackup
    • Turn back on "DisplayStand" if it was open
    • Take the screenshot
    • Turn back on any menus that were on with PostScreenshotBackup

    Everything works fine, but "DisplayStand" is not showing in the screenshot if it was visible.

    Here's the code snippet I'm using:

                bool displayMenuOn = PlayerMenus.GetMenuWithName("DisplayStand").IsVisible();
                Debug.Log("DisplaymenuOn: " + displayMenuOn);
    
                KickStarter.playerMenus.PreScreenshotBackup();
    
                if (displayMenuOn)
                {
                    Menu myMenu = PlayerMenus.GetMenuWithName("DisplayStand");
                    myMenu.isLocked = false;
                    myMenu.TurnOn();
                }
    
                yield return new WaitForEndOfFrame();
                Texture2D screenshot = GetScreenshotTexture();
                Debug.Log("Took screenshot succesfully.");
    
                KickStarter.playerMenus.PostScreenshotBackup();
    

    "DisplayStand" has Manual appear type.
    AC 1.81.2, Unity 2022.3.3 5f1

  • You'd need to run this in a coroutine, and then wait until the next frame, after calling PreScreenshotBackup, for it to take effect.

    Alternatively - and this is also optional in AC's save-screenshot settings - you can rely on a seprate Camera, parented to the MainCamera, that outputs to a Render Texture that you read instead.

    Being a separate Camera, you can place your UI objects (except "DisplayStand") on a separate layer that isn't visible to it.

  • edited October 2024

    Thanks a lot for this. I couldn't get the coroutine working so I have a child-Camera to the main camera that outputs to render texture, using this for save-screenshots as well. This works to a point, but now I cannot get any UI to show up in the screenshot!? Also the UI prefabs that have the layer "UI" don't show even if UI is checked in the camera culling mask.

    Please see below for inspectors of

    • Screenshotcam
    • UI prefab that needs to be in the screenshot
    • AC Settings manager

    https://imgur.com/1Jiep8K

    Here is my screenshot code mostly taken from the SaveSystem AC script.

    namespace AC
    {
        public class CameraScreenShot : MonoBehaviour
        {
            bool displayMenuOn;
            public Camera screenShotCam;
    
            protected virtual Texture2D GetScreenshotTexture()
            {
                if (KickStarter.mainCamera)
                {
                    Rect screenRect = KickStarter.mainCamera.GetPlayableScreenArea(false);
                    Texture2D screenshotTexture = null;
    
                    RenderTexture screenshotRenderTexture = KickStarter.settingsManager.screenshotRenderTexture;
                    if (screenshotRenderTexture)
                    {
                        var old_rt = RenderTexture.active;
                        screenshotTexture = new Texture2D(screenshotRenderTexture.width, screenshotRenderTexture.height, TextureFormat.RGB24, false);
    
                        RenderTexture.active = screenshotRenderTexture;
                        screenshotTexture.ReadPixels(new Rect(0, 0, screenshotRenderTexture.width, screenshotRenderTexture.height), 0, 0);
                        RenderTexture.active = old_rt;
                    }
                    else
                    {
                        screenshotTexture = new Texture2D((int)screenRect.width, (int)screenRect.height);
                        screenshotTexture.ReadPixels(screenRect, 0, 0);
                    }
    
                    if (KickStarter.settingsManager.linearColorTextures)
                    {
                        for (int y = 0; y < screenshotTexture.height; y++)
                        {
                            for (int x = 0; x < screenshotTexture.width; x++)
                            {
                                Color color = screenshotTexture.GetPixel(x, y);
                                screenshotTexture.SetPixel(x, y, color.linear);
                            }
                        }
                    }
    
    
                    screenshotTexture.Apply();
                    return screenshotTexture;
                }
                ACDebug.LogWarning("Cannot take screenshot - no main Camera found!");
                return null;
            }
    
            /** The width of save-game screenshot textures */
            public virtual int ScreenshotWidth
            {
                get
                {
                    if (KickStarter.mainCamera)
                    {
                        int width = (int)(KickStarter.mainCamera.GetPlayableScreenArea(false).width * KickStarter.settingsManager.screenshotResolutionFactor);
                        return Mathf.Min(width, Screen.width);
                    }
                    else
                    {
                        int width = (int)(Screen.width * KickStarter.settingsManager.screenshotResolutionFactor);
                        return Mathf.Min(width, Screen.width);
                    }
                }
            }
    
            /** The height of save-game screenshot textures */
            public virtual int ScreenshotHeight
            {
                get
                {
                    if (KickStarter.mainCamera)
                    {
                        int height = (int)(KickStarter.mainCamera.GetPlayableScreenArea(false).height * KickStarter.settingsManager.screenshotResolutionFactor);
                        return Mathf.Min(height, Screen.height);
                    }
                    else
                    {
                        int height = (int)(Screen.height * KickStarter.settingsManager.screenshotResolutionFactor);
                        return Mathf.Min(height, Screen.height);
                    }
                }
            }
    
    
            public void CreateTexture()
            {
                StartCoroutine(CreateTextureCo());
            }
    
            private System.Collections.IEnumerator CreateTextureCo()
            {
                yield return new WaitForEndOfFrame();
    
                Texture2D screenshot = GetScreenshotTexture();
                Debug.Log("Took screenshot succesfully.");
    
                int categoryID = 1; // Set this to the photo category's ID number
                InvCollection playerInvCollection = KickStarter.runtimeInventory.PlayerInvCollection;
                foreach (InvItem item in KickStarter.inventoryManager.items)
                {
                    if (playerInvCollection.Contains(item.id) || item.binID != categoryID) continue;
                    InvInstance newItemInstance = new InvInstance(item);
                    InvInstance addedInstance = playerInvCollection.Add(newItemInstance);
                    addedInstance.Tex = screenshot;
                    byte[] bytes = screenshot.EncodeToJPG();
                    string dataString = Convert.ToBase64String(bytes);
                    // string dataString = System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length);
                    // item.GetProperty("PhotoID").TextValue = dataString;
                    addedInstance.GetProperty("PhotoID").TextValue = dataString;
                    PlayerMenus.ResetInventoryBoxes();
                    break;
                }
            }
        }
    }
    

    I thought it could have something with the "ScreenSpace Overlay" in the UI Canvas, but when changing to ScreenSpace Camera" I couldn't drag the main camera into Render Camera".

  • I thought it could have something with the "ScreenSpace Overlay" in the UI Canvas, but when changing to ScreenSpace Camera" I couldn't drag the main camera into Render Camera".

    What's your AC version? This should happen automatically.

    If not, you can attach a simple custom script to handle this - but try assigning it manually at runtime first. Also make sure that the screenshot camera's field of view matches that of the MainCamera.

  • AC 1.81.2, Unity 2022.3.3 5f1

    Thanks. Unfortunately it doesn't work. What I did, all in runtime:

    • copied the settings from MainCamera to child-ScreenshotCam (FOV, Clipping Planes, viewportRect etc.)
    • Changed the "DisplayStand" UI from Overlay to Screenspace-Camera and assigned the MainCamera (the main camera was assigned automatically at runtime)

    On another note, optimally I'd like the screenshotCam to have a higher FOV to get more into the picture. With the same FOV at the main camera, the sides of the screen is not included in the picture. I suppose this can be changed in the screenshot script somehow.....

  • Sounds like all's set up correctly.

    Check the depth the UI objects have from the camera - if you can share screenshots of the Cameras, the UI objects, and how things appear in the Scene window (at an angle), I'll see if I can spot what's wrong.

  • Here are some screenshots:

    https://imgur.com/a/mbF8Ro2

    The main camera is automatically assigned, but the plane distance is set to 100 so the UI is hidden behind scene items far outside. When I set the Plane Distance close to the camera, i.e. 0.15, the UI is visible in the Main Camera, but not in the ScreenShot camera so it doesn't appear in the screenshot.

    The viewport rect for the Main Camera seems to change slightly to different numbers, sometimes changing X and W, sometimes changing Y and H) each time I hit run. I suppose this has to do with the Fixed Aspect ratio, but since it changes each time I was a bit confused.

    I do want to keep the ScreenShotCam viewport rect to default (x:0, y:0, w:1,h:1) and FOV to 90 (Main camera: 65) for normal screenshots though as this gives better coverage of the visible screen.

  • If the Plane Distance field won't show until a camera is assigned, drop the prefab into the scene, assign a Camera to show it, lower it to 0.15, apply the change to the prefab and remove from the scene.

    Is the whole UI prefab on the "Visible in screenshots" layer?

  • Thanks. Ok, this sets the Plane Distance so that one is good. The canvas still doesn't show in the Screeshot Cam though. All the child objects as well in the UI prefab are on the "Visible in screenshots" layer.

    What I tried:

    • Small script that changes the Canvas' WorldCamera to to the ScreenshotCam onEnable and back to MainCamera onDisable -> The canvas was put way out in space and not visible
    • Changed Canvas to ScreenSpace Overlay, Added a BasicCamera script to Screenshot cam and did an actionlist to switch to ScreenshotCam right before taking screenshot and back to FirstPersonPlayerCam after taking the screenshot -> this just gives me a black screen for the screenshot
  • Small script that changes the Canvas' WorldCamera to to the ScreenshotCam onEnable and back to MainCamera onDisable -> The canvas was put way out in space and not visible

    Where was it put, exactly? As both cameras have the same position, I'm not sure why switching would make such a difference.

    Though, as we're dealing purely with Unity concepts, I'm not sure if AC is directly involved with causing the issue.

    What's your CopyCameraClearFlags component doing?

  • It was put in the root of the UI object

    public class SetScreenshotCam : MonoBehaviour
    {
        Canvas myCanvas;
        public Camera screenShotCam;
        public Camera mainCam;
        void OnEnable()
        {
            myCanvas = GetComponent<Canvas>();
           myCanvas.worldCamera = screenShotCam;
        }
        void OnDisable()
        {
            myCanvas = GetComponent<Canvas>();
            myCanvas.worldCamera = mainCam;
        }
    }
    

    Both MainCam and ScreenshotCam have the same position but with the above script the UI is placed outside where other Screenspace-overlay objects are placed, e.g. JoystickUI.

    I don't have a CopyCameraClearFlags component on the ScreenshotCam, only the Camera component. I did add it to see what happens but no change.

    I cannot for my life get the UI to show up in the screenshotcam, so I'm giving up on this.

    I went back to trying to turn back on this menu through a coroutine after PreScreenshotBackup and if displayMenuOn=true:

            IEnumerator turnOnDisplayStand()
            {
                if (displayMenuOn)
                {
                    Menu myMenu = PlayerMenus.GetMenuWithName("DisplayStand");
                    myMenu.isLocked = false;
                    myMenu.TurnOn();
                }
                yield return null;
            }
    

    but nothing happens. Please don't spend time on this Unity thing, but if you spot the error immediately please let me know.

  • Code should work - so long as the Menu's "Appear type" is set to "Manual", otherwise it'll be bound by the Appear type's rule.

    Unless it's part of a wider coroutine, the snippet above doesn't need to be in one, mind.

  • Thanks. I finally got this to work by changing the code to:

                if (displayMenuOn)
                {
                    PlayerMenus.GetMenuWithName("DisplayStand").RuntimeCanvas.gameObject.SetActive(true);
                }
    
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.