Unity基础(15)-Application与SceneMan
Application类与SceneManager类
-
在较早Unity版本之前,Application类负责:应用程序运行时数据,获取并加载场景(异步,同步),随着移动端兴起,后期版本中只负责获取跟应用程序运行时数据,而场景相关的被SceneManager替代。这也是与其他移动平台结合的改变。
移动端
- Application静态属性:
dataPath属性 : 数据文件路径
public static string dataPath{ get; }
Application.dataPath
返回程序的数据文件所在文件夹的路径(只读).返回路径为相对路径,不同游戏平台的数据文件保存路径不同,Editor中就是项目的Assets文件夹的路径,通过这个路径可以访问项目中任何文件夹中的资源,但是在移动端
它是完全没用。
Application.persistentDataPath
此属性返回一个持久化数据存储目录的路径,可以在此路径下存储一些持久化的数据文件。这个路径可读、可写,但是只能在程序运行时才能读写操作,不能提前将数据放入这个路径。在IOS上是应用程序的沙盒,可以被iCloud自动备份,可以通过同步推送一类的助手直接取出文件;在Android上的位置是根据Project Setting里设置的Write Access路径,可以设置是程序沙盒还是sdcard,注意:如果在Android设置保存在沙盒中,那么就必须root以后才能用电脑取出文件,因此建议写入sdcard里。一般情况下,建议将获得的文件保存在这个路径下,例如可以从StreamingAsset中读取的二进制文件或者从AssetBundle读取的文件写入PersistentDatapath。
Application.streamingAassetsPath
此属性用于返回流数据的缓存目录,返回路径为相对路径,适合设置一些外部数据文件的路径.在PC/MAC中可实现对文件的“增删改查”等操作,但在移动端是一个只读路径。
Application.temporaryCachePath
此属性返回一个临时数据的缓存目录,跟Application.persistentDataPath类似,但是在IOS上不能被自动备份
以上各路径中的资源加载方式都可以用WWW类加载,但要注意各个平台路径需要加的访问名称,例如Android平台的路径前要加"jar:file://",其他平台使用"file://"。以下是各路径在各平台中的具体位置信息:
- Android平台
Application.dataPath : /data/app/xxx.xxx.xxx.apk
Application.streamingAssetsPath : jar:file:///data/app/xxx.xxx.xxx.apk/!/assets
Application.persistentDataPath : /data/data/xxx.xxx.xxx/files
Application.temporaryCachePath : /data/data/xxx.xxx.xxx/cache
- IOS平台
Application.dataPath : Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data
Application.streamingAssetsPath : Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data/Raw
Application.persistentDataPath : Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documents
Application.temporaryCachePath : Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Library/Caches
- Windows Web Player
Application.dataPath : file:///D:/MyGame/WebPlayer (即导包后保存的文件夹,html文件所在文件夹)
Application.streamingAssetsPath :
Application.persistentDataPath :
Application.temporaryCachePath :
#if UNITY_EDITOR
string filepath = Application.dataPath +"/StreamingAssets"+"/version.txt";
#elif UNITY_IPHONE
string filepath = Application.dataPath +"/Raw"+"/my.xml";
#elif UNITY_ANDROID
string filepath = "jar:file://" + Application.dataPath + "!/assets/"+"/version.txt";
#endif
StreamingAssets在各个平台上的文本支持读取方式
string path = System.IO.Path.Combine(Application.streamingAssetsPath,"version.txt");
## Editor:
1::System.IO.File.ReadAllText (path);
2:path = "file://"+path;或者 path = "file:/"+path;或者 path = "file:\\"+path或者 path = "file:\\\\"+path;在win7上都可以 在mac上path = "file:/"+path不可以外,别的都可以
然后WWW www = new WWW (path);
## Android:
1:WWW www = new WWW (path);
## iphone:
1:System.IO.File.ReadAllText (path);
2:path = "file://"+path;System.IO.File.ReadAllText (path);
还有一点就是在读取streamingAssets目录下的文本文件时android平台必须要用www来读取哦,因为android平台是被压缩在apk中,
所以不能直接用CSharp去读,ios可以直接用System.IO.File.ReadAllText(filePath)
-
loadedLevel属性 :
SceneManager.GetActiveScene().buildIndex
返回当前场景的索引值
SceneManager.GetActiveScene().name
返回当前场景的名字
SceneManager.sceneCountInBuildSettings
游戏中可被加载的场景数量
Application.platform 当前游戏的运行平台,返回值为枚举类型
Application.isPlaying 当前游戏是否正在运行
Application.isEditor 游戏是否处于Unity编辑模式 -
Application类静态方法:
旧方法
Application.CaptureScreenshot方法 : 截屏
目前改为了:ScreenCapture.CaptureScreenshot
public static void CaptureScreenshot(string filename);
参数filename 截屏文件名称 superSize放大系数,默认为0,即不放大
public static void CaptureScreenshot(string filename, int superSize);
此方法截取当前游戏画面并保存为PNG格式,文件默认保存在根目录下,若有重名文件则替换.
public void CameraGame()
{
Debug.Log(Application.dataPath);
string fileName = Application.dataPath +"/Images/" + Time.time+ ".png";
ScreenCapture.CaptureScreenshot(fileName);
}
public void CameraGame()
{
Debug.Log(Application.dataPath);
StartCoroutine(GetScreenCamera());
}
IEnumerator GetScreenCamera()
{
yield return new WaitForEndOfFrame();
Texture2D t = new Texture2D(100, 100, TextureFormat.RGB24, false);
t.ReadPixels(new Rect(0, 0, 100, 100), 0, 0);
// 保存图片
t.Apply();
byte[] imgB = t.EncodeToPNG();
System.IO.File.WriteAllBytes(Application.dataPath + "/Images/" + Time.time + ".png", imgB);
}
- RegisterLogCallback方法 :注册委托
方法1:Application.RegisterLogCallback
static function RegisterLogCallback (handler : Application.LogCallback) : void
在一个日志信息上注册一个委托来被调用,这个函数和RegisterLogCallback唯
方法2:Application.RegisterLogCallbackThreaded
static function RegisterLogCallbackThreaded (handler : Application.LogCallback) : void
在一个日志信息上注册一个委托来被调用,这个函数和RegisterLogCallback唯一不同的是,这个函数将从不同的线程被调用,注意:你只有你知道你在做什么时才能使用这个函数,否则使用Application.RegisterLogCallback。
两个方法在使用的时候,都需要传递一个委托
public delegate void LogCallback (string condition, string stackTrace, LogType type);
第一个参数为日志描述信息,第二个参数为日志产生的栈数据,第三个参数为日志的类型
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class LogMessage : MonoBehaviour {
string message="";
public Text text;
void Start () {
//在一个日志信息上注册一个委托来被调用
Application.logMessageReceivedThreaded +=MyLogCallback;
}
void Update () {
text.text = message;
}
/// <summary>
/// log callback check
/// </summary>
/// <param name="condition">日志描述信息log内容.</param>
/// <param name="stackTrace">log产生的栈数据追踪</param>
/// <param name="type">log的类型.</param>
void MyLogCallback (string condition, string stackTrace, LogType type){
switch(type){
case LogType.Assert:
message += " receive an assert log"+",condition="+condition+",stackTrace="+stackTrace;
break;
case LogType.Error:
message += " receive an Error log"+",condition="+condition+",stackTrace="+stackTrace;
break;
case LogType.Exception:
message += " receive an Exception log"+",condition="+condition+",stackTrace="+stackTrace;
break;
case LogType.Log:
message += " receive an Log log"+",condition="+condition+",stackTrace="+stackTrace;
break;
case LogType.Warning:
message += " receive an Warning log"+",condition="+condition+",stackTrace="+stackTrace;
break;
}
}
void OnGUI(){
if(GUI.Button(new Rect(10,20,200,40),"assert")){
Debug.LogAssertion ("assertion");
}else if(GUI.Button(new Rect(10,80,200,40),"error")){
Debug.LogError ("error");
}else if(GUI.Button(new Rect(10,140,200,40),"exception")){
Debug.LogException (new System.NullReferenceException());
}else if(GUI.Button(new Rect(10,200,200,40),"log")){
Debug.Log ("log");
}else if(GUI.Button(new Rect(10,260,200,40),"warning")){
Debug.LogWarning ("waring");
}
}
}
Application相关事件函数
OnApplicationPause(bool pause) 如果应用程序暂停,则为True,否则为False
OnApplicationFocus(bool focus) 如果应用程序失去焦点
OnApplicationQuit() 程序退出事件
`强制暂停时`,先 `OnApplicationPause`,后 `OnApplicationFocus`;
`重新“启动”手机时`,先`OnApplicationFocus`,后 `OnApplicationPause`;
`启用键盘按Home`不会调用OnApplicationFocus,而是调用OnApplicationPause;
`安卓上启用手机键盘`,会调用OnApplicationFocus](false)事件。
private void OnApplicationPause(bool pause)
{
Debug.Log("停止程序" + pause);
}
private void OnApplicationFocus(bool focus)
{
Debug.Log("程序失去焦点" + focus);
}
// 当前应用双击Home,然后Kill(IOS 有回调,android 没回调)
private void OnApplicationQuit()
{
QuitGame();
}
public void QuitGame()
{
Debug.Log("Quit");
// 在编辑器或者web播放器中退出被忽略
// Application.Quit();
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#elif UNITY_IPHONE
Application.Quit();
#elif UNITY_ANDROID
Application.Quit();
#else
Application.Quit();
#endif
}
SceneManager
通常游戏的主场景包含的资源较多,这会导致加载场景的时间较长。
为了避免这个问题,可以首先加载Loading场景,然后再通过Loading场景来加载主场景。
因为Loading场景包含的资源较少,所以加载速度快。
在加载主场景的时候一般会在Loading界面中显示一个进度条来告知玩家当前加载的进度。
在Unity中可以通过调用SceneManager.LoadSceneAsync(旧版本:Application.LoadLevelAsync)函数来异步加载游戏场景,
通过查询AsyncOperation.progress的值来得到场景加载的进度。
通过Unity提供的Coroutine机制,我们可以方便的在每一帧结束后调用SetLoadingPercentage函数来更新界面中显示的进度条的数值。
SceneManager.LoadSceneAsync()
此方法用于按照关卡名字在后台异步加载关卡到当前场景中,此方法只是将新关卡加载到当前场景,当前场景的原有内容不会被销毁.
AsynvOperation colve = public static AsynvOperation LoadLevelAdditiveAsync(int index);
colve.isDone 是否加载完成
colve.progress 加载进度
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System;
public class Loading : MonoBehaviour {
public Slider loadingSlider;
public Text loadingText;
public AsyncOperation op;
public float targetValue;
void Start () {
loadingSlider.value = 0.0f;
// 判断当前场景的名字是Loading
if (SceneManager.GetActiveScene().name == "Loading")
{
// 加载下一个场景
StartCoroutine(AsyncLoading());
}
}
private IEnumerator AsyncLoading()
{
op = SceneManager.LoadSceneAsync(3);
// 阻止当加载完成自动切换
op.allowSceneActivation = false;
//
yield return op;
}
void Update () {
Debug.Log(op.progress);
targetValue = op.progress;
if (op.progress >= 0.9f)
{
//operation.progress的值最大为0.9
targetValue = 1.0f;
}
if (targetValue != loadingSlider.value)
{
//插值运算
loadingSlider.value = Mathf.Lerp(loadingSlider.value, targetValue, Time.deltaTime * 1);
if (Mathf.Abs(loadingSlider.value - targetValue) < 0.01f)
{
loadingSlider.value = targetValue;
}
}
loadingText.text = ((int)(loadingSlider.value * 100)).ToString() + "%";
if ((int)(loadingSlider.value * 100) == 100)
{
//允许异步加载完毕后自动切换场景
op.allowSceneActivation = true;
}
}
}
第二种方式:进度条加载
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class LoadScene : MonoBehaviour {
public Slider sl;
public Text t;
void Start () {
sl.value = 0;
StartCoroutine(LoadingScene());
}
private IEnumerator LoadingScene(int scene)
{
AsyncOperation op = SceneManager.LoadSceneAsync(3);
while (!op.isDone)
{
t.text = op.progress * 100 + "%";
sl.value = op.progress * 100 ;
yield return new WaitForEndOfFrame();
}
}
private IEnumerator LoadingScene()
{
int displayProgress = 0;
int toProgress = 0;
AsyncOperation op = SceneManager.LoadSceneAsync(3);
op.allowSceneActivation = false;
while (op.progress < 0.9f)
{
toProgress = (int)op.progress * 100;
while (displayProgress < toProgress)
{
++displayProgress;
t.text = displayProgress + "%";
sl.value = displayProgress * 0.01f;
yield return new WaitForEndOfFrame();
}
}
toProgress = 100;
while (displayProgress < toProgress)
{
++displayProgress;
t.text = displayProgress + "%";
sl.value = displayProgress * 0.01f;
yield return new WaitForEndOfFrame();
}
op.allowSceneActivation = true;
}