Min*_*wzy 17 c# unity-game-engine virtual-reality
如何将得分值从一个场景传递到另一个场景?
我尝试过以下方法:
场景一:
void Start () {
score = 0;
updateScoreView ();
StartCoroutine (DelayLoadlevel(20));
}
public void updateScoreView(){
score_text.text = "The Score: "+ score;
}
public void AddNewScore(int NewscoreValue){
score = score + NewscoreValue;
updateScoreView ();
}
IEnumerator DelayLoadlevel(float seconds){
yield return new WaitForSeconds(10);
secondsLeft = seconds;
loadingStart = true;
do {
yield return new WaitForSeconds(1);
} while(--secondsLeft >0);
// here I should store my last score before move to level two
PlayerPrefs.SetInt ("player_score", score);
Application.LoadLevel (2);
}
Run Code Online (Sandbox Code Playgroud)
场景二:
public Text score_text;
private int old_score;
// Use this for initialization
void Start () {
old_score = PlayerPrefs.GetInt ("player_score");
score_text.text = "new score" + old_score.ToString ();
}
Run Code Online (Sandbox Code Playgroud)
但屏幕上没有显示任何内容,也没有错误.
这是传递数据的正确方法吗?
我正在使用Unity 5免费版,为Gear VR开发游戏(意味着游戏将在Android设备上运行).
有什么建议吗?
Pro*_*mer 50
有3种方法可以做到这一点,但解决方案取决于您希望在场景之间传递的数据类型.加载新场景时甚至标记为时,组件/脚本和游戏对象都会被销毁static
.
1.使用static
关键字.
使用此方法如果变量传递到下一个场景是不是一个组成部分,并没有继承MonoBehaviour
,而不是一个游戏物体,然后把这些变量是static
.
内置基本数据类型,如int
,bool
,string
,float
,double
.所有这些变量都可以变成一个static
变量.
该内置基本数据类型的实施例可以被标记为静态:
static int counter = 0;
static bool enableAudio = 0;
static float timer = 100;
Run Code Online (Sandbox Code Playgroud)
这些应该没有问题.
可以标记为静态的对象示例:
public class MyTestScriptNoMonoBehaviour
{
}
Run Code Online (Sandbox Code Playgroud)
然后
static MyTestScriptNoMonoBehaviour testScriptNoMono;
void Start()
{
testScriptNoMono = new MyTestScriptNoMonoBehaviour();
}
Run Code Online (Sandbox Code Playgroud)
请注意,该类不继承自MonoBehaviour
.这应该工作.
无法标记为静态的对象示例:
凡是从继承Object
,Component
或GameObject
将无法正常工作.
1A.任何继承自的东西MonoBehaviour
public class MyTestScript : MonoBehaviour
{
}
Run Code Online (Sandbox Code Playgroud)
然后
static MyTestScript testScript;
void Start()
{
testScript = gameObject.AddComponent<MyTestScript>();
}
Run Code Online (Sandbox Code Playgroud)
这将不工作,因为它从继承MonoBehaviour
.
1B.所有GameObject
:
static GameObject obj;
void Start()
{
obj = new GameObject("My Object");
}
Run Code Online (Sandbox Code Playgroud)
这不会起作用,因为它是a GameObject
并且GameObject
继承自Object
.
Object
即使用static
关键字声明它们,Unity也会永远销毁它.
有关解决方法,请参阅#2.
2.使用该DontDestroyOnLoad
功能.
如果要保留或传递给下一个场景的数据继承Object
,Component
或者是a ,则只需要使用它GameObject
.这解决了1A和1B中描述的问题.
当场景卸载时,您可以使用它来使这个GameObject不被破坏:
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
Run Code Online (Sandbox Code Playgroud)
您甚至可以将它与1A和1B中的static
关键字解决问题一起使用:
public class MyTestScript : MonoBehaviour
{
}
Run Code Online (Sandbox Code Playgroud)
然后
static MyTestScript testScript;
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
void Start()
{
testScript = gameObject.AddComponent<MyTestScript>();
}
Run Code Online (Sandbox Code Playgroud)
testScript
现在,当加载新场景时,将保留该变量.
3.保存到本地存储,然后在下一个场景中加载.
当这是游戏关闭并重新打开时必须保留的游戏数据时,应使用此方法.这样的例子是玩家高分,游戏设置如音乐量,对象位置,操纵杆简档数据等.
Thare是两种保存方式:
3APlayerPrefs
.使用API.
如果只有几个变量可以保存,请使用.让我们说球员得分:
int playerScore = 80;
Run Code Online (Sandbox Code Playgroud)
我们想要保存playerScore:
将分数保存在OnDisable
函数中
void OnDisable()
{
PlayerPrefs.SetInt("score", playerScore);
}
Run Code Online (Sandbox Code Playgroud)
将其加载到OnEnable
函数中
void OnEnable()
{
playerScore = PlayerPrefs.GetInt("score");
}
Run Code Online (Sandbox Code Playgroud)
图3B .Serialize数据以JSON,XML或binaray形式然后保存使用C#文件API之一,如File.WriteAllBytes
和File.ReadAllBytes
保存和加载文件.
如果要保存许多变量,请使用此方法.
一般情况下,您需要创建一个不继承的类MonoBehaviour
.您应该使用此类来保存游戏数据,以便可以轻松地序列化或反序列化.
要保存的数据示例:
[Serializable]
public class PlayerInfo
{
public List<int> ID = new List<int>();
public List<int> Amounts = new List<int>();
public int life = 0;
public float highScore = 0;
}
Run Code Online (Sandbox Code Playgroud)
抢DataSaver
类,这是一个包装上File.WriteAllBytes
,并File.ReadAllBytes
使得从保存的数据更容易这个职位.
创建新实例:
PlayerInfo saveData = new PlayerInfo();
saveData.life = 99;
saveData.highScore = 40;
Run Code Online (Sandbox Code Playgroud)
将PlayerInfo中的数据保存到名为"players"的文件中:
DataSaver.saveData(saveData, "players");
Run Code Online (Sandbox Code Playgroud)
从名为"players"的文件加载数据:
PlayerInfo loadedData = DataSaver.loadData<PlayerInfo>("players");
Run Code Online (Sandbox Code Playgroud)
der*_*ugo 37
还有一种方法:
ScriptableObject
ScriptableObject
s 基本上是数据容器,但也可以实现自己的逻辑。他们“生活”在Assets
类似的预制件中。它们不能用于永久存储数据,但它们会在一个会话期间存储数据,因此它们可用于在场景之间共享数据和引用……而且——我也经常需要——在场景和AnimatorController
!
首先你需要一个类似于MonoBehaviour
s的脚本。一个简单的例子ScriptableObject
可能看起来像
// fileName is the default name when creating a new Instance
// menuName is where to find it in the context menu of Create
[CreateAssetMenu(fileName = "Data", menuName = "Examples/ExamoleScriptableObject")]
public class ExampleScriptableObject : ScriptableObject
{
public string someStringValue = "";
public CustomDataClass someCustomData = null;
public Transform someTransformReference = null;
// Could also implement some methods to set/read data,
// do stuff with the data like parsing between types, fileIO etc
// Especially ScriptableObjects also implement OnEnable and Awake
// so you could still fill them with permanent data via FileIO at the beginning of your app and store the data via FileIO in OnDestroy !!
}
// If you want the data to be stored permanently in the editor
// and e.g. set it via the Inspector
// your types need to be Serializable!
//
// I intentionally used a non-serializable class here to show that also
// non Serializable types can be passed between scenes
public class CustomDataClass
{
public int example;
public Vector3 custom;
public Dictionary<int, byte[]> data;
}
Run Code Online (Sandbox Code Playgroud)
您可以ScriptableObject
通过脚本创建任一实例
var scriptableObject = ScriptableObject.CreateInstance<ExampleScriptableObject>();
Run Code Online (Sandbox Code Playgroud)
或者为了让事情更容易使用[CreateAssetMenu]
上面的例子中所示。
由于这个创建的ScriptabeObject
实例存在于Assets
它没有绑定到场景中,因此可以在任何地方引用!
当您想在两个场景之间共享数据时,或者在场景之间共享数据时,AnimatorController
您需要做的就是ScriptableObject
在两者中引用此实例。
我经常使用例如一个组件来填充数据
public class ExampleWriter : MonoBehaviour
{
// Here you drag in the ScriptableObject instance via the Inspector in Unity
[SerializeField] private ExampleScriptableObject example;
public void StoreData(string someString, int someInt, Vector3 someVector, List<byte[]> someDatas)
{
example.someStringValue = someString;
example.someCustomData = new CustomDataClass
{
example = someInt;
custom = someVector;
data = new Dictionary<int, byte[]>();
};
for(var i = 0; i < someDatas.Count; i++)
{
example.someCustomData.data.Add(i, someDatas[i]);
}
example.someTransformReference = transform;
}
}
Run Code Online (Sandbox Code Playgroud)
因此,在您将所需的数据写入并存储到此ExampleScriptableObject
实例后,任何场景中的每个其他类AnimatorController
或其他ScriptableObject
s 都可以以相同的方式读取这些数据:
public class ExmpleConsumer : MonoBehaviour
{
// Here you drag in the same ScriptableObject instance via the Inspector in Unity
[SerializeField] private ExampleScriptableObject example;
public void ExampleLog()
{
Debug.Log($"string: {example.someString}", this);
Debug.Log($"int: {example.someCustomData.example}", this);
Debug.Log($"vector: {example.someCustomData.custom}", this);
Debug.Log($"data: There are {example.someCustomData.data.Count} entries in data.", this);
Debug.Log($"The data writer {example.someTransformReference.name} is at position {example.someTransformReference.position}", this);
}
}
Run Code Online (Sandbox Code Playgroud)
如前所述,aScriptableObject
本身的变化仅在 Unity 编辑器中真正持久。
在构建中,它们仅在同一会话期间保持不变。
因此,我经常将会话持久性与某些 FileIO(如本答案的第 3b 节中所述)结合起来,以便在会话开始时(或在需要时)从硬盘加载和反序列化值,并将它们序列化并存储到文件中一次在会话结束 ( OnApplicationQuit
) 或需要时。
(这当然不适用于参考。)
Isj*_*Isj 10
除了playerPrefs之外,另一种脏方法是在级别加载期间通过调用DontDestroyOnLoad来保留对象.
DontDestroyOnLoad (transform.gameObject);
Run Code Online (Sandbox Code Playgroud)
附加到游戏对象的任何脚本都将存活,脚本中的变量也将存活.DontDestroyOnLoad函数通常用于保留整个GameObject,包括附加到它的组件,以及它在层次结构中具有的任何子对象.
您可以创建一个空的GameObject,并只放置包含您想要保留的变量的脚本.
我使用一种称为无状态场景的函数方法。
using UnityEngine;
public class MySceneBehaviour: MonoBehaviour {
private static MySceneParams loadSceneRegister = null;
public MySceneParams sceneParams;
public static void loadMyScene(MySceneParams sceneParams, System.Action<MySceneOutcome> callback) {
MySceneBehaviour.loadSceneRegister = sceneParams;
sceneParams.callback = callback;
UnityEngine.SceneManagement.SceneManager.LoadScene("MyScene");
}
public void Awake() {
if (loadSceneRegister != null) sceneParams = loadSceneRegister;
loadSceneRegister = null; // the register has served its purpose, clear the state
}
public void endScene (MySceneOutcome outcome) {
if (sceneParams.callback != null) sceneParams.callback(outcome);
sceneParams.callback = null; // Protect against double calling;
}
}
[System.Serializable]
public class MySceneParams {
public System.Action<MySceneOutcome> callback;
// + inputs of the scene
}
public class MySceneOutcome {
// + outputs of the scene
}
Run Code Online (Sandbox Code Playgroud)
您可以将全局状态保留在调用者的范围内,因此可以最小化场景输入和输出状态(使测试变得容易)。要使用它,您可以使用匿名函数:-
MyBigGameServices services ...
MyBigGameState bigState ...
Splash.loadScene(bigState.player.name, () => {
FirstLevel.loadScene(bigState.player, (firstLevelResult) => {
// do something else
services.savePlayer(firstLevelResult);
})
)}
Run Code Online (Sandbox Code Playgroud)
更多信息请访问https://corepox.net/devlog/unity-pattern:-stateless-scenes
归档时间: |
|
查看次数: |
30414 次 |
最近记录: |