Forum rules - please read before posting.

Saving game from a Main Menu in its own Scene

I followed the tutorials on how to make a Main menu. I simplified it, so basically there is only a single Main Menu on a separate scene (it will have an animated specific background, so a transparent menu is not an option). There is also no Pause menu. Clicking the pause button will make an autosave and bring you to this Main Menu.

I set the saving system to Screenshot with text.
However, there is a problem. When I want to do a proper save from the Main Menu, it saves the Main Menu scene, including the screenshot of that scene, instead of the game level with its screenshot. The autosave works fine, as the pause button triggers it while the game is still in the specific level for creating the save properly.

I noticed that within the SaveList settings, I can create an ActionList when click, but I struggle to find a solution to make use of it.
Several ideas came to mind:

  1. Copy the Autosave data, including the screenshot, into the appropriate save slot because that is what I basically need. However, I found elsewhere on this forum that copying saves is supposed to be very complicated and risky.
  2. Load autosave, save to the slot, and return to MainMenu Scene. Unfortunately, in the Action list, I cannot follow with any other action after Save: Save or Load: Load Game.
  3. Create a floating menu without its own scene. But i have an animated fullscreen background image for the Main Menu. When changing the resolution, the image gets distorted as the menu adapts to it. I would like it to behave like a standard scene background (ortho size set to fit).

Any suggestions, please?

Comments

  • A few notes / suggestions:

    1. Copying the Autosave is feasible, but - unless I'm misunderstanding - would need the game to be saved before each time you open the Menu, regardless of whether or not the user ultimately chooses to.
    2. ActionLists will cease at the moment a file is loaded. However, you can use the Events Editor (available in the top toolbar) to run an ActionList once a file has been loaded (via the Save: Load: After event).
    3. If your Menu relies on Unity UI, altering the Canvas Scaler's UI Scale Mode can affect how it adjusts (or doesn't) based on the resolution and aspect ratio. If you only wanted the background to be affected in this way, it could be on a separate Menu that appears at the same time as your Main menu.
    4. Rather than swiching to your dedicated "Menu" scene, you can also add it on top of your regular scene with the Scene: Add or remove Action. You'd need to ensure that the background is positioned closer to the camera than any object in your gameplay scene(s), but it should then appear as if the gameplay scene has been closed.
  • edited April 7

    I think the best, safest, and most elegant solution would be 1). Right now, the game is saved the moment you click the Menu button in the in-game inventory before the scene switches to the Menu scene, so there should be no problem.

    2) Seems overly complicated, plus I'm a bit weary about the scenes switching back and forth.
    3) I am using AC Menu.
    4) Wouldn't the screenshot still be made from the Main menu scene background?

    I also encountered a little problem with the screenshots. I am using crunch compression, which requires all graphics resolutions to be divisible by 4. But I get an error, and game crashes every time I try to make a save game with a screenshot:

    Texture '' has dimensions (2341 x 1080) which are not multiples of 4. Compress will not work.
    UnityEngine.StackTraceUtility:ExtractStackTrace ()
    AC.SaveFileHandler_SystemFile:LoadScreenshot (string) (at Assets/AdventureCreator/Scripts/Save system/FileHandling/SaveFileHandler_SystemFile.cs:293)

    It did not do this before for some reason (or maybe I had a game resolution set to something divisible by 4). But the game should be playable under various resolutions anyway. Can I somehow exclude the screenshots from the compression, or force a screenshot resolution, or is there a better way to deal with it?

  • I think the best, safest, and most elegant solution would be 1)

    I need to look into providing a Copy function of sorts.

    I am using AC Menu.

    You'd need to switch - but I recommend doing so anyway as Unity UI menus offer more styling flexibility, with AC menus generally better for rapid-prototyping.

    Wouldn't the screenshot still be made from the Main menu scene background?

    Having an override/replacement ability of sorts wouldn't be too difficult, but would be done as the last step of implementation.

  • edited April 8

    A little update on the Texture '' has dimensions (...) which are not multiples of 4. Compress will not work. UnityEngine.StackTraceUtility:ExtractStackTrace ()

    This happens when I try to implement 4. The MainMenu scene has a different resolution than the level scene (in fact, all scenes have different resolutions). Not sure if it has something to do with it. This change then corrupts the whole saving system. When I want to change back from Scene: Add or Remove to Scene: Switch, the problem persists, and I cannot even get to the Main Menu without the game crashing with this error message. To get it working again, I have to delete the project and use a backup version.

  • edited April 23

    Do you mean that you are changing the resolution manually, i.e. with Screen.SetResolution? I do not recommend this on a per-scene basis. Or by "resolution" are you referring to the background dimensions?

    AC should automatically scale the saved texture to the nearest multiple of 4.

    If a screenshot is somehow being saved/loaded incorrectly, no need to restore a backup of the project - you can delete the offending save file from the Save-game File Manager.

    I would advise disabling save-screenshots for the moment, however, until the wider issue of saving in the intended scene is handled - as it only compounds the issue.

    The folllowing script will copy the Autosave when clicking a SavesList element - be sure to uncheck Save when click on? in the element's properties to avoid conflict:

    using UnityEngine;
    using System.Collections.Generic;
    using AC;
    
    public class CopyAutosave : MonoBehaviour
    {
    
        public int fromID, toID;
        private SaveFile saveToCopyTo;
    
        void OnEnable () { EventManager.OnMenuElementClick += OnMenuElementClick; }
        void OnDisable () { EventManager.OnMenuElementClick -= OnMenuElementClick; }
    
        void OnMenuElementClick (Menu _menu, MenuElement _element, int _slot, int buttonPressed)
        {
            if (_element == null || !(_element is MenuSavesList)) return;
            MenuSavesList savesList = _element as MenuSavesList;
            if (savesList.saveListType != AC_SaveListType.Save) return;
    
            SaveFile saveFile = savesList.GetSaveFile (_slot);
            if (saveFile != null)
            {   
                CopySaveFile (0, saveFile.saveID);
            }
            else
            {
                CopySaveFile (GetNewSaveID (), saveFile.saveID);
            }
        }
    
    
        public void CopySaveFile (int fromID, int toID)
        {
            saveToCopyTo = null;
            int profileID = Options.GetActiveProfileID ();
    
            SaveFile saveToCopy = SaveSystem.SaveFileHandler.GetSaveFile (fromID, profileID);
            if (saveToCopy == null) return;
    
            string newLabel = SaveSystem.SaveFileHandler.GetDefaultSaveLabel (toID);
    
            saveToCopyTo = new SaveFile (toID, profileID, newLabel, string.Empty, saveToCopy.screenShot, string.Empty, 0);
    
            SaveSystem.SaveFileHandler.Load (saveToCopy, true, OnLoadSaveToCopy);
        }
    
    
        private void OnLoadSaveToCopy (SaveFile saveToCopy, string data)
        {
            saveToCopyTo.screenShot = Decompress (saveToCopyTo.screenShot);
            SaveSystem.SaveFileHandler.SaveScreenshot (saveToCopyTo);
            SaveSystem.SaveFileHandler.Save (saveToCopyTo, data, OnAttemptCopy);
        }
    
    
        private void OnAttemptCopy (bool isSuccessful)
        {
            if (!isSuccessful)
            {
                ACDebug.LogWarning ("Save file " + saveToCopyTo.saveID + " could not be created.");
            }
            saveToCopyTo = null;
            KickStarter.saveSystem.GatherSaveFiles ();
        }
    
    
        private Texture2D Decompress (Texture2D source)
        {
            if (source == null) return null;
    
            RenderTexture renderTex = RenderTexture.GetTemporary(
                        source.width,
                        source.height,
                        0,
                        RenderTextureFormat.Default,
                        RenderTextureReadWrite.Linear);
    
            Graphics.Blit(source, renderTex);
            RenderTexture previous = RenderTexture.active;
            RenderTexture.active = renderTex;
            Texture2D readableText = new Texture2D(source.width, source.height);
            readableText.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0);
            readableText.Apply();
            RenderTexture.active = previous;
            RenderTexture.ReleaseTemporary (renderTex);
            return readableText;
        }
    
    
        private int GetNewSaveID ()
        {
            if (KickStarter.saveSystem.foundSaveFiles != null && KickStarter.saveSystem.foundSaveFiles.Count > 0)
            {
                int expectedID = -1;
    
                List<SaveFile> foundSaveFilesOrdered = new List<SaveFile>();
                foreach (SaveFile foundSaveFile in KickStarter.saveSystem.foundSaveFiles)
                {
                    foundSaveFilesOrdered.Add (new SaveFile (foundSaveFile));
                }
                foundSaveFilesOrdered.Sort (delegate (SaveFile a, SaveFile b) {return a.saveID.CompareTo (b.saveID);});
    
                for (int i=0; i<foundSaveFilesOrdered.Count; i++)
                {
                    if (expectedID != -1 && expectedID != foundSaveFilesOrdered[i].saveID)
                    {
                        return expectedID;
                    }
    
                    expectedID = foundSaveFilesOrdered[i].saveID + 1;
                }
    
                // Saves present, but no gap
                return foundSaveFilesOrdered [foundSaveFilesOrdered.Count-1].saveID+1;
            }
            return 1;
        }
    
    }
    
  • Should i attach this script to something? I assume that probably not, since it seems to be running on its own, unfortunately also giving me this this error:

    CopyAutosave.cs(95,56): error CS0246: The type or namespace name 'List<>' could not be found (are you missing a using directive or an assembly reference?)

  • The script needs to be attached to an object, yes, and then have its CopySaveFile function called. I've amended it to remove the error.

    However, with the latest AC release I've added the ability to assign a RenderTexture to the Settings Manager that is used to override save-screenshots. This'll be the better approach - you could now use a full-screen Menu that obscures the gameplay, and then use a separate camera that only renders the gameplay scene and passes its output to a dedicated RenderTexture - no need to go about copying saves this way.

  • edited April 23

    I plan to have an animated background in the Main Menu - either using a video or animating some object to hover over it. So, I am unsure if this can be achieved within a menu without using a scene. I think copying the Save File would be a better/simpler option unless I am missing something?

    I am having a little trouble with the script tho. I have 20 save slots (including 0 = Autosave). I need to copy from ID 0 to an ID that is not given but is variable based on a specific slot I chose to click on. Now with settings from 0 to 0, I can click only on Autosave. When I click on a different slot, I get an error.
    I guess a solution would be to attach it to every Slot element individually, but I don't know how.

    Also, the copied screenshot of a new save is darker (if I keep clicking to overwrite autosave, it gets darker and darker till black).

    I am also using the parameters and global variable of a specific slot ID so it remembers the position of the slot that was clicked on (like in the default Save when click on?, following parts of the Custom Save Labels Tutorial). I am not sure if this is retained in the CopyAutosave script or if I can set it elsewhere somehow.

  • Copying save files isn't the simplest option, in my opinion.

    You can still have animations using the alternative technique - either embedded within the Menu UI itself, or by spawning in an animated background prefab at the same time.

  • edited April 24

    Even if I wanted to use an NPC? I will have some just objects hovering around in the background, thought it would have been easier to make them NPCs (perhaps even using skeletal animation) with prescribed paths to move around the background, rather then putting a video there.

  • An NPC can be part of the prefab that gets spawned in.

    The associated Action logic would need to come from ActionList assets, but if all the Paths / NPC objects are a part of the prefab, and the movement doesn't involve pathfinding, they should work just fine.

  • Ok, thank you for the advice. I will try to upgrade the UI Menu so it does not require its own scene.

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.