简体   繁体   English

如何检查主菜单后是否开始游戏?

[英]How can I check if game is started after the main menu?

When running the game by default the main menu scene is loaded first at index 0. so when loading a game or making a new game any loaded scene index that is not 0 meaning the game started or loaded.默认情况下运行游戏时,主菜单场景首先在索引 0 处加载。因此,在加载游戏或制作新游戏时,任何加载的场景索引不为 0 表示游戏已启动或已加载。

I want to use this script as a manager script to detect when a new game started or game loaded anything that is not the main menu so I can activate stuff or start stuff from other scripts.我想将此脚本用作管理器脚本,以检测新游戏何时开始或游戏何时加载非主菜单的任何内容,以便我可以激活内容或从其他脚本启动内容。

The first problem is the gameobject empty gameobject the script is attached to should be on DontDestroyOnLoad?第一个问题是脚本附加到的游戏对象空游戏对象应该在 DontDestroyOnLoad 上吗?

And how can I use it from other scripts?以及如何从其他脚本中使用它?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class NewGame : MonoBehaviour
{
    public static bool GameStarted = false; 

    private Scene currentScene;

    // Start is called before the first frame update
    void Start()
    {
        currentScene = SceneManager.GetActiveScene();
    }

    // Update is called once per frame
    void Update()
    {
        if(currentScene.buildIndex != 0 && GameStarted == false)
        {
            GameStarted = true;
        }
    }
}

And example of a script I want to use it:我想使用它的脚本示例:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ScaleRotate : MonoBehaviour
{
    public GameObject objectToScale;
    public Vector3 minScale;
    public Vector3 maxScale;
    public float duration;
    public float rotationAngle = 180.0f;
    public DimLights dimLights;

    private bool scaling = true;
    private bool isInProcess = false;

    private void Start()
    {
        StartCoroutine(dimLights.DimLightsOverTime(2, duration));
        StartCoroutine(ScaleOverSeconds(maxScale, new Vector3(0,rotationAngle,0), duration));
    }

    public IEnumerator ScaleOverSeconds(Vector3 scaleTo, Vector3 rotateTo, float seconds)
    {
        isInProcess = true;
        float elapsedTime = 0;
        Vector3 startingScale = objectToScale.transform.localScale;
        Vector3 startingRotation = objectToScale.transform.localEulerAngles;
        //If you want, you can change axis of rotation or angle or everything you want. But what I do - I rotate by Y-axis for 180 degrees

        while (elapsedTime < seconds)
        {
            objectToScale.transform.localScale = Vector3.Lerp(startingScale, scaleTo, (elapsedTime / seconds));
            objectToScale.transform.localEulerAngles = Vector3.Lerp(startingRotation, rotateTo, (elapsedTime / seconds));

            elapsedTime += Time.deltaTime;
            //You can use yield return null instead of yield return new WaitForEndOfFrame() - this will do the same, but it's easier to write
            yield return null;
        }
        objectToScale.transform.localScale = scaleTo;
        objectToScale.transform.localEulerAngles = rotateTo;
        isInProcess = false;
    }

    private void Update()
    {
        if(NewGame.GameStarted == true)
        {

        }

        if (Input.GetKeyDown(KeyCode.S))
        {
            //Check if object is not changing it's scale right now
            if (!isInProcess)
            {
                //Use if(scaling) instead of if(scaling == true) - this means the same, but it's more readable
                if (scaling)
                {
                    Vector3 rotateTo = objectToScale.transform.localEulerAngles + new Vector3(0, rotationAngle, 0);
                    StartCoroutine(dimLights.DimLightsOverTime(0, duration));
                    StartCoroutine(ScaleOverSeconds(minScale, rotateTo, duration));
                    //Remove scaling = false (we will paste it later)
                }
                //Add there else operator
                else
                {
                    //If you want to change rotation to counterclockwise, change '+' to '-'
                    Vector3 rotateTo = objectToScale.transform.localEulerAngles + new Vector3(0, rotationAngle, 0);
                    StartCoroutine(dimLights.DimLightsOverTime(2, duration));
                    StartCoroutine(ScaleOverSeconds(maxScale, rotateTo, duration));
                }
                //Change scaling value. If you want, you can move this line into ScaleOverSeconds coroutine
                scaling = !scaling;
            }
        }
    }
}

For example I want that the two lines in the Start() will be executed only when a new game is started after the main menu not when running the application.例如,我希望 Start() 中的两行仅在主菜单后启动新游戏时才执行,而不是在运行应用程序时执行。

I added in the Update()我在 Update() 中添加了

if(NewGame.GameStarted == true)
            {
    
            }

But I'm still not sure how to use the NewGame and if this is a logic way to check for a new game start?但我仍然不确定如何使用 NewGame 以及这是否是检查新游戏开始的逻辑方式?

Two issues to solve when using DontDestroyOnLoad使用DontDestroyOnLoad时要解决的两个问题

  1. When the scene is changed you get another instance -> you'll have to make sure there exists only one single instance.当场景改变时,你会得到另一个实例 -> 你必须确保只存在一个实例。

  2. The Start is not called anymore for the already started instance.不再为已启动的实例调用Start

The solution for 1 is called Singleton pattern and you can do it like 1 的解决方案称为Singleton模式,您可以这样做

public class NewGame : MonoBehaviour
{
    // Here you store the actual instance
    private static NewGame _instance;

    // Public read-only access property
    public static NewGame Instance 
    {
        get
        {
            // if already set simply return directly
            if(_instance) return _instance;

            // Otherwise try to find it in the scene
            _instance = FindObjectOfType<NewGame>();
            if(_instance) return _instance;

            // Otherwise create it now
            _instance = new GameObject(nameof(NewGame)).AddComponent<NewGame>();

            return _instance;
        }
    }

    private void Awake()
    {
        if(_instance && _instance != this)
        {
            // There already exist another instance 
            Destroy (this.gameObject);
            return;
        }

        // Otherwise this is the active instance and should not be destroyed
        _instance = this;
        DontDestroyOnLoad(this.gameObject);

        // Todo solution for 2
    }

    ...
}

For the second thing you can use SceneManager.sceneLoades like对于第二件事,您可以使用SceneManager.sceneLoades之类的

public class NewGame : MonoBehaviour
{
    // Here you store the actual instance
    private static NewGame _instance;

    // Public read-only access property
    public static NewGame Instance 
    {
        get
        {
            // if already set simply return directly
            if(_instance) return _instance;

            // Otherwise try to find it in the scene
            _instance = FindObjectOfType<NewGame>();
            if(_instance) return _instance;

            // Otherwise create it now
            _instance = new GameObject(nameof(NewGame)).AddComponent<NewGame>();

            return _instance;
        }
    }

    private bool _gameStarted;
    public static bool GameStarted => Instance._gameStarted;

    private void Awake()
    {
        if(_instance && _instance != this)
        {
            // There already exist another instance 
            Destroy (this.gameObject);
            return;
        }

        // Otherwise this is the active instance and should not be destroyed
        _instance = this;
        DontDestroyOnLoad(this.gameObject);

        SceneManager.sceneLoaded += OnSceneLoaded;

        // update it once now 
        _gameStarted = SceneManager.GetActiveScene().buildIndex != 0;
    }

    void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        _gameStarted = scene.buildIndex != 0;
    }
}

So you would in any other script be able to simply access所以你可以在任何其他脚本中简单地访问

if(NewGame.GameStarted)
{
    // => buildIndex != 0
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM