【发布时间】:2020-10-19 21:52:38
【问题描述】:
或者也许使变量静态并在编辑器中获取对它们的引用。 该脚本位于我的游戏场景中。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class SceneFader : MonoBehaviour
{
#region FIELDS
public GameObject fadeOutUIGameobjectImage;
public float fadeSpeed = 0.8f;
public bool loaded = false;
private static Image fadeOutUIImage;
private void Start()
{
}
public enum FadeDirection
{
In, //Alpha = 1
Out // Alpha = 0
}
#endregion
#region FADE
public static IEnumerator Fade(FadeDirection fadeDirection)
{
fadeOutUIGameobjectImage.SetActive(true);
float alpha = (fadeDirection == FadeDirection.Out) ? 1 : 0;
float fadeEndValue = (fadeDirection == FadeDirection.Out) ? 0 : 1;
if (fadeDirection == FadeDirection.Out)
{
while (alpha >= fadeEndValue)
{
SetColorImage(ref alpha, fadeDirection);
yield return null;
}
fadeOutUIGameobjectImage.SetActive(false);
}
else
{
fadeOutUIGameobjectImage.SetActive(true);
while (alpha <= fadeEndValue)
{
SetColorImage(ref alpha, fadeDirection);
yield return null;
}
}
}
#endregion
#region HELPERS
public static IEnumerator FadeAndLoadSceneNewGame(FadeDirection fadeDirection, string sceneToLoad)
{
yield return Fade(fadeDirection);
loaded = false;
SceneManager.LoadScene(sceneToLoad);
}
public static IEnumerator FadeAndLoadSceneLoadGame(FadeDirection fadeDirection, string sceneToLoad)
{
yield return Fade(fadeDirection);
loaded = true;
SceneManager.LoadScene(sceneToLoad);
var saveLoad = GameObject.Find("Save System").GetComponent<SaveLoad>();
saveLoad.Load();
}
private static void SetColorImage(ref float alpha, FadeDirection fadeDirection)
{
if(fadeOutUIImage == null)
{
fadeOutUIImage = fadeOutUIGameobjectImage.GetComponent<Image>();
}
fadeOutUIImage.color = new Color(fadeOutUIImage.color.r, fadeOutUIImage.color.g, fadeOutUIImage.color.b, alpha);
alpha += Time.deltaTime * (1.0f / fadeSpeed) * ((fadeDirection == FadeDirection.Out) ? -1 : 1);
}
#endregion
}
现在,tope 中的变量是公共的,但不是静态的,所以我不能在脚本的其余部分中使用它们,如果我将它们设为静态,我无法在编辑器中引用它们我尝试在当它们是静态的但它们为空时开始。
这个脚本位于我的主菜单场景中,我认为将游戏场景中的两个方法设为 public static 会更容易从主菜单场景中调用它们:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEditor;
using Cinemachine;
using UnityStandardAssets.Characters.ThirdPerson;
public class MenuController : MonoBehaviour
{
#region Default Values
[Header("Default Menu Values")]
[SerializeField] private float defaultVolume;
[SerializeField] private int defaultSen;
[SerializeField] private bool defaultInvertY;
[Header("Levels To Load")]
public string _newGameButtonLevel;
private string levelToLoad;
public GameObject player;
private int menuNumber;
#endregion
#region Menu Dialogs
[Header("Main Menu Components")]
[SerializeField] private GameObject menuDefaultCanvas;
[SerializeField] private GameObject GeneralSettingsCanvas;
[SerializeField] private GameObject graphicsMenu;
[SerializeField] private GameObject soundMenu;
[SerializeField] private GameObject controlsMenu;
[SerializeField] private GameObject confirmationMenu;
[Space(10)]
[Header("Menu Popout Dialogs")]
[SerializeField] private GameObject noSaveDialog;
[SerializeField] private GameObject newGameDialog;
[SerializeField] private GameObject loadGameDialog;
#endregion
#region Slider Linking
[Header("Menu Sliders")]
[SerializeField] private Text controllerSenText;
[SerializeField] private Slider controllerSenSlider;
public float controlSenFloat = 2f;
[Space(10)]
[SerializeField] private Text volumeText;
[SerializeField] private Slider volumeSlider;
[Space(10)]
[SerializeField] private Toggle invertYToggle;
#endregion
#region Initialisation - Button Selection & Menu Order
private void Start()
{
menuNumber = 1;
}
#endregion
//MAIN SECTION
public IEnumerator ConfirmationBox()
{
confirmationMenu.SetActive(true);
yield return new WaitForSeconds(2);
confirmationMenu.SetActive(false);
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (menuNumber == 2 || menuNumber == 7 || menuNumber == 8)
{
GoBackToMainMenu();
ClickSound();
}
else if (menuNumber == 3 || menuNumber == 4 || menuNumber == 5)
{
GoBackToOptionsMenu();
ClickSound();
}
else if (menuNumber == 6) //CONTROLS MENU
{
ClickSound();
}
}
}
private void ClickSound()
{
GetComponent<AudioSource>().Play();
}
#region Menu Mouse Clicks
public void MouseClick(string buttonType)
{
if (buttonType == "Controls")
{
controlsMenu.SetActive(true);
menuNumber = 6;
}
if (buttonType == "Graphics")
{
GeneralSettingsCanvas.SetActive(false);
graphicsMenu.SetActive(true);
menuNumber = 3;
}
if (buttonType == "Sound")
{
GeneralSettingsCanvas.SetActive(false);
soundMenu.SetActive(true);
menuNumber = 4;
}
if (buttonType == "Exit")
{
Debug.Log("YES QUIT!");
Application.Quit();
}
if (buttonType == "Options")
{
menuDefaultCanvas.SetActive(false);
GeneralSettingsCanvas.SetActive(true);
menuNumber = 2;
}
if (buttonType == "LoadGame")
{
menuDefaultCanvas.SetActive(false);
loadGameDialog.SetActive(true);
menuNumber = 8;
}
if (buttonType == "NewGame")
{
menuDefaultCanvas.SetActive(false);
newGameDialog.SetActive(true);
menuNumber = 7;
}
}
#endregion
public void VolumeSlider(float volume)
{
AudioListener.volume = volume;
volumeText.text = volume.ToString("0.0");
}
public void VolumeApply()
{
PlayerPrefs.SetFloat("masterVolume", AudioListener.volume);
Debug.Log(PlayerPrefs.GetFloat("masterVolume"));
StartCoroutine(ConfirmationBox());
}
public void ControllerSen()
{
controllerSenText.text = controllerSenSlider.value.ToString("0");
controlSenFloat = controllerSenSlider.value;
}
#region ResetButton
public void ResetButton(string GraphicsMenu)
{
if (GraphicsMenu == "Audio")
{
AudioListener.volume = defaultVolume;
volumeSlider.value = defaultVolume;
volumeText.text = defaultVolume.ToString("0.0");
VolumeApply();
}
if (GraphicsMenu == "Graphics")
{
controllerSenText.text = defaultSen.ToString("0");
controllerSenSlider.value = defaultSen;
controlSenFloat = defaultSen;
invertYToggle.isOn = false;
}
}
#endregion
#region Dialog Options - This is where we load what has been saved in player prefs!
public void ClickNewGameDialog(string ButtonType)
{
if (ButtonType == "Yes")
{
newGameDialog.SetActive(false);
StartCoroutine(SceneFader.FadeAndLoadSceneNewGame(SceneFader.FadeDirection.In, _newGameButtonLevel));
}
if (ButtonType == "No")
{
GoBackToMainMenu();
}
}
public void ClickLoadGameDialog(string ButtonType)
{
if (ButtonType == "Yes")
{
newGameDialog.SetActive(false);
StartCoroutine(SceneFader.FadeAndLoadSceneLoadGame(SceneFader.FadeDirection.In, _newGameButtonLevel));
}
if (ButtonType == "No")
{
GoBackToMainMenu();
}
}
#endregion
#region Back to Menus
public void GoBackToOptionsMenu()
{
GeneralSettingsCanvas.SetActive(true);
graphicsMenu.SetActive(false);
soundMenu.SetActive(false);
VolumeApply();
menuNumber = 2;
}
public void GoBackToMainMenu()
{
menuDefaultCanvas.SetActive(true);
newGameDialog.SetActive(false);
loadGameDialog.SetActive(false);
noSaveDialog.SetActive(false);
GeneralSettingsCanvas.SetActive(false);
graphicsMenu.SetActive(false);
soundMenu.SetActive(false);
menuNumber = 1;
}
public void ClickQuitOptions()
{
GoBackToMainMenu();
}
public void ClickNoSaveDialog()
{
GoBackToMainMenu();
}
#endregion
}
在这个脚本中我有两个事件:
我从主菜单中的 OnClick 按钮调用它们的 ClickNewGameDialog 和 ClickLoadGameDialog。
我创建了这个脚本并将它添加到游戏场景中的一个空游戏对象中:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
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;
}
}
但是当我尝试在游戏场景中使用它时:
if(NewGame.GameStarted != true)
GameStarted 始终为 true 绝不为 false,因此即使玩家单击了“加载游戏”按钮,它也始终在盯着新游戏。
【问题讨论】:
-
那你为什么要创建
static方法来访问实例变量呢? -
@UnholySheep 因为这个方法在我的游戏场景中,我想从我的主菜单场景中访问这些方法,我从新游戏按钮和加载游戏按钮调用这两个方法。
-
这并不能解释为什么您将它们设为静态,您可以轻松访问您的类的实例,方法是让这些按钮具有对它的引用,或者在运行时获取它(通过 @ 987654327@电话)
-
@UnholySheep 用我的主菜单场景中的脚本和两个按钮事件更新了我的问题,你能告诉我如何引用游戏场景中的方法吗?我希望能够在游戏场景中的任何脚本中知道玩家是否单击了“新游戏”按钮或“加载游戏”按钮。而且我不确定在主菜单脚本中仅使用公共静态布尔值是否是个好主意。
-
您可能希望有一个管理器类,它要么是
static class,要么附加到标有Object.DontDestroyOnLoad的对象上:docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html。将static字段放入MonoBehaviour派生类将无法很好地配合 Unity 在场景更改期间处理此类类的方式