[英]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
时要解决的两个问题
When the scene is changed you get another instance -> you'll have to make sure there exists only one single instance.当场景改变时,你会得到另一个实例 -> 你必须确保只存在一个实例。
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.