目录
16.Unity如何调用android与iOS的 API函数?
1.委托是什么?Event关键字有什么用?
- 委托:用于将方法作为参数传递给其他方法。事件处理程序就是通过委托调用方法。
- 你可以创建一个自定义方法,当特定事件发生后,某个类就可以调用你这个方法。
- 可以将多个方法赋给同一个委托,调用时,依次调用其所有绑定的方法,也可以取消。
- 举例:遇到不同国家的人,以不同的方式打招呼。
-
using System; using System.Collections.Generic; namespace UnityBase { //委托 public delegate void sayhelloDelegate(string name); class Program { static void Main(string[] args) { List<People> pp = new List<People>(); var ma = new People { Name = "马云", Country = "中国", sayFunction = ChineseSay }; ma.Country = "USA"; ma.sayFunction += EnglishSay; pp.Add(ma); pp.Add(new People { Name = "Bill", Country = "USA", sayFunction = EnglishSay }); pp.ForEach(p => Say(p)); } public static void Say(People p) { p.sayFunction(p.Name); } public static void ChineseSay(string name) { Console.WriteLine($"{name},老表,吃了没?"); } public static void EnglishSay(string name) { Console.WriteLine($"hello,{name},how are you ?"); } } public class People { public string Name { get; set; } public string Country { get; set; } public sayhelloDelegate sayFunction { get; set; } } }
事件(Event):在类中声明生成,通过使用同一个类或者其他类中的委托与事件处理程序关联。
-
包含事件的类用于发布事件称为(发布器)类,其他接受该事件的类称为(订阅器)
-
在类内部声明事件,首先必须声明该事件的 委托类型。然后声明事件本身,使用event关键字
using System;
namespace UnityBase
{
// 发布器
public class EventTest {
public delegate void NumDelegate();
public event NumDelegate NumEvent;
protected virtual void OnNumEvent() {
if (NumEvent != null)
{
NumEvent();
}
else {
Console.WriteLine("Event Not !!!");
Console.ReadKey();
}
}
public void SetValue() {
OnNumEvent();
}
}
// 触发
class Program
{
static void Main(string[] args)
{
EventTest e = new EventTest();
e.SetValue();
e.NumEvent += new EventTest.NumDelegate(prinnf);
e.SetValue();
e.SetValue();
}
// 订阅器
public static void prinnf()
{
Console.WriteLine("Event Fire");
Console.ReadKey();
}
}
}
2.Unity协程是如何实现的 (IEnumerator)
- 协程:
- 性能:相比于一般函数,没有更多开销
- 好处:分部做一个比较耗时的东西,如需大量计算,将计算放到一个随时间进行的协程来处理,分散计算压力。
- 坏处:本质是迭代器,且是基于unity生命周期的,大量开启协程会产生GC。
- 执行:协程不是线程,不是异步执行的。在主线程中执行,是一个分部执行,遇到条件(yield return)会挂起,直到满足条件才会被唤醒继续执行后面的代码。unity每帧都会处理对象上的协程。
- 结束:StopCoroutine(string methordName); StopAllCoroutines(); 暂停当前脚本下所有协程。或者设置对象active=false,即使再次激活,也不能继续执行。但enable=false 不能停止协程。。
- 中断:WaitForSeconds() 等待数秒,受Time.timeScale影响,当time.timeScale=0时,yield return new WaitForSecond(1)不会被满足。 WaitForFixedUpdat:等待一个固定帧。。。。 StartCoroutine等待一个协程暂停,WWW等待一个加载完成。
- 执行顺序:开始协程—>执行协程—>遇到中断指令中断协程—>返回上层函数继续执行上层函数的下一行代码—>中断指令结束,继续执行中断指令之后的代码—>协程结束。
- 在一个主线程里,同时最多只能有一个处于运行状态的协程。协程不是并行的,同一时刻,一个脚本实例中可以有多个暂停的协程,但只有一个运行的协程。
- 和线程的区别:线程是利用多核达到真正的并行计算,缺点是有大量的锁,切换,等待的问题。而协程是非抢占式,需要手动释放使用权来切换到其他协程,因此,同一时间只有一个协程拥有运行权,相当于单线程的能力。 协程是C#线程的替代品,是unity不使用线程的解决方案。使用协程不用考虑锁的问题。多个协程可以同时进行,会根据启动顺序来更新。
- 注意点:IEnumerator类型的方法不能带ref和out型参数,但可以被传递引用。函数Update和FiexdUpdate中不能使用yield语句,否则会报错,但是可以启动协程。
3.摄像机有几种模式,成像原理分别是什么?
- Projection:Prespective 透视;Orthographic 正交。
4.Canvas 有几种模式,如何配置?
- canvas的RenderMode共有三种模式:Screen Space-OverLay,Screen Space-Camrea,World Space;
- Screen Sp模块管理ace-OverLay:Canvas 覆盖屏幕,且永远覆盖在其它元素的上层,也就是说 UI 会遮挡场景中的其它元素。显示优先级由 Sort Order 确定
- Screen Space-Camrea:和 Overlay 模式相仿,Canvas覆盖整个屏幕空间画布也是填满整个屏幕空间。不同之处在于,Canvas 被放置于指定摄像机的前方。这种模式下面 UI 并不一定能渲染在 3d 元素之上。
- Word Spcae:此种模式下,Canvas 与场景中其它3D元素没有区别。
- 同时显示多个摄像机:更改相机的Viewport Path,上面的相机Depth要大。
5.UGUI如何打包图集?
- 开启:Edit--Project Setting-Editor-Sprite Packer-Mode
- Disable:不可用
- Enable For Builds:打包发布时启用
- Always Enable:一直启用,在开发和打包阶段都启用,方便开发人员在开发阶段查看图集信息,推荐使用
- 操作:Type是Sprite,设置Packing Tag的名字,unity会自动将这些图按照tag打包到图集中去。
- 查看:window-sprite packer
- 注意:打包的图片不要放到Rescore下。
- 加载:动态加载,需要自己写代码。Atlas和AutoSetTextureUISprite包含usingEditor,需放在Editor下,否则报错。
- https://blog.csdn.net/weixin_41843959/article/details/80411529
6.UGUI如何实现UI物体淡入淡出?
- 单个:控制组件alpha透明度
- 整体:使用CanvasGroup组件,把组件放到界面根节点。CanvasGroup是管理整个界面下的所有UI元素,改变这个组件透明属性,地下所有ui元素该属性都会变
- 使用DoTween插件。
7.Hash表的原理是什么, 如何实现?
- Hash table:根据关键码值(Key value)而直接进行访问的数据结构。通过关键码值映射到表中一个位置来访问记录,以加快查找速度,这个映射函数叫哈希函数,存放记录的数组叫哈希表,得出的值叫哈希值。
- 优点:不论哈希表数据有多少,增加,删除,改写数据复杂度平均都是O(1),效率非常高。
- 原理:每个数据都对应一个固定位置,查找特定数据时,直接查看这个数据对应的位置是否存在数据。
- 实现:首先:分配一片空间用来存储数据,比如空的数组。然后:有数据存进来时,按照特定规则得出数据在数组中位置,将数据存进这个位置。
- 问题1:冲突:两个数据通过哈希函数计算出的哈希值有可能相等。‘
- 解决1:开放定址法,链定址法。 开放定址法:将冲突数据再重新计算一个空位置,将其存进去。
- 问题2:哈希表满了,如何扩容?
- 解决2:当插入数据时,所有位置都满了,就再分配一个大于原先空间的一片空间,把原来空间中的值重新哈希到新空间中
8.链表如何实现?
- 链表是用任意的存储单元来存储线性表中的数据元素。再存储数据元素时,除了存储数据本身信息外,还要存储与他相邻的数据元素的存储地址信息。
- https://www.cnblogs.com/tonybinlj/archive/2012/06/08/1500291.html
9.Unity节点缓存池如何实现?
- 缓存池:unity在创建物体后(申请内存),删除,内存没有立刻释放,只是将引用取消掉。对象使用完毕,我们不直接销毁对象,而是将它重新放入缓存池,以备下次使用
- 优点:减少内存消耗,优化运行时效率,防止内存泄漏。
- 创建:存放不同类型的游戏对象(GameObject),使用字典来创建缓存池(Dictionary),缓存池判断游戏物体是什么类型使用枚举。
using System.Collections.Generic; using UnityEngine; public class PoolManager : MonoBehaviour { //单例 static PoolManager _poolManager = null; public static PoolManager poolManager { get { if (_poolManager == null) { _poolManager = new PoolManager(); } return _poolManager; } } //缓存表 Dictionary<string, List<GameObject>> _list = new Dictionary<string, List<GameObject>>(); void Awake() { _poolManager = this; } //创建一个新的缓存池 public void CreateNewObjList(string key, GameObject obj, int defCount = 5) { List<GameObject> list = new List<GameObject>(); for (int i = 0; i < defCount; i++) { GameObject go = CreateOneObj(key, obj); list.Add(go); } _list.Add(key, list); } //创建单个对象 private GameObject CreateOneObj(string key, GameObject obj) { GameObject go = Instantiate(obj) as GameObject; go.transform.SetParent(this.transform); go.transform.localScale = Vector3.one; go.transform.localPosition = Vector3.zero; go.name = key + "_缓存对象"; return go; } //从缓存池取对象 public GameObject GetObject(string key, GameObject obj) { //key不存在 if (!_list.ContainsKey(key)) { CreateNewObjList(key, obj); } GameObject item = null; //缓存池有可用对象 if (_list[key].Count > 0) { item = _list[key][0]; _list[key].RemoveAt(0); } else { item = CreateOneObj(key, obj); } //回收的对象都会设置为false item.gameObject.SetActive(true); item.transform.localPosition = Vector3.zero; item.transform.localScale = Vector3.one; return item; } //回收对象 public void RecoverObj(GameObject obj) { string key = GetKeyByObjName(obj); Debug.Log("回收的Key:" + key); if (!_list.ContainsKey(key)) { Debug.LogError("不存在回收的Key->" + key); return; } obj.SetActive(false); obj.transform.SetParent(this.transform); _list[key].Add(obj); } //根据key清空对应缓存值 public void ClearListByKey(string key) { if (!_list.ContainsKey(key)) { Debug.LogError("不存在key->" + key); return; } _list[key].Clear(); for (int i = 0; i < transform.childCount; i++) { GameObject go = transform.GetChild(i).gameObject; string goKey = GetKeyByObjName(go); if (goKey == key) { Destroy(go); } } } //清空所有缓存池 public void ClearAllPoolList() { _list.Clear(); for (int i = 0; i < transform.childCount; i++) { GameObject go = transform.GetChild(i).gameObject; Destroy(go); } } //获取obj的key private string GetKeyByObjName(GameObject obj) { string str = obj.name; int idx = str.IndexOf("_"); string key = str.Substring(0, idx); return key; } }
使用
//----------------------------//
// 使用
public GameObject obj1, obj2;
private void Start()
{
PoolManager.poolManager.CreateNewObjList("key1", obj1);
PoolManager.poolManager.CreateNewObjList("key2", obj1);
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
GameObject go = PoolManager.poolManager.GetObject("obj1", obj1);
go.transform.SetParent(this.transform);
go.transform.localScale = Vector3.one;
go.transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
go.transform.localPosition = new Vector3(go.transform.localPosition.x, go.transform.localPosition.y, 0);
}
}
10.Unity如何实现单例模式?
public class GameManager : MonoBehaviour {
//单例
private static GameManager instance = null;
public static GameManager GetInstance {
get {
if (instance == null) {
instance = new GameManager();
}
return instance;
}
}
}
11.MenuItem 什么意思?
- 允许自己添加菜单到主菜单和检视面板(仅静态函数能使用menuitem属性)
- 使用方法:
[MenuItem(string itemName, bool isValidateFunction, int priority)]
- itemName:菜单名称路径,isValidateFunction:true则点击菜单就会调用;priority:菜单显示顺序
-
第一个参数为路径名称,可添加快捷键(空格后加如下符合设置):
- _w:(单一快捷键w);#w(shift+w);%w(ctrl+w); &w(Alt +w)
[MenuItem("GameObject/xxxxxxxxxx #w")]
- 为组件添加:
[MenuItem("CONTEXT/组件名/显示方法名")]
12.AB包;.manifest有什么作用?
- AssetBundle定义和作用:
- AssetBundle是一个压缩包含模型,贴图,预制体,声音,甚至是整个场景,可以在游戏运行时加载。
- AssetBundle自身保存依赖关系;(AB包后缀为 manifest的文件可被文本形式打开)
- 压缩可以使用LZ4和LZMA压缩算法,减少包大小,更快进行网络传输。
- 把一些可以下载的内存放进AssetBundle里,减少安装包的大小。
- 使用流程:
- 基本设置:指定资源的AssetBundle属性,选择资源,(xxxa/xxx):xxxa会生成目录,名字为xxx。
- 打包:使用编辑扩展器--build所有以及设置好要打包的assetbundle资料。脚本要放到Editor文件夹下,否则报错
-
using System.IO; using UnityEditor; using UnityEngine; public class CreateAssetBundles : MonoBehaviour { [MenuItem("AssetBundles/Build AssetBundles")] //特性 static void BuildAssetBundle() { string dir = "AssetBundles"; //相对路径 if (!Directory.Exists(dir)) //判断是否存在 { Directory.CreateDirectory(dir); } BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64); } }
打包完成,会在AssetBundle下生成manifest文件。
-
加载:4种加载方式。
-
从文件中加载 AssetBundle.LoadFromFile 。
using System.Collections; using UnityEngine; public class LoadFromFileExample : MonoBehaviour { private IEnumerator Start() { //这里需要注意的是,如果你想加载的资源有依赖的资源 如贴图等资源,则必须先加载依赖资源后加载你所想加载的资源。 //即A依赖B 则必须先加载B到内存中,然后再加载A 并实例化---这里注意依赖项一般可以不用实例化只需要在内存中即可。 AssetBundle abShare = AssetBundle.LoadFromFile("AssetBundles/materials/mapmaterials"); AssetBundle ab = AssetBundle.LoadFromFile("AssetBundles/scene/map_001"); //这里需要注意的是 单独加载和加载所有压缩包内的对象处理方式 //加载单独的 GameObject panelPrefab = ab.LoadAsset<GameObject>("Plane"); //注意名字不能写错了 Instantiate(panelPrefab);//实例化资源 加载所有 //Object[] panelPrefab = ab.LoadAllAssets(); //foreach (var obj in panelPrefab) //{ // Instantiate(obj);//实例化资源 //} yield return null; } }
-
从内存中加载 AssetBundle.LoadFromMemoryAsync(注意是异步,去掉Asyns既是同步方法)
using System.Collections; using System.IO; using UnityEngine; public class LoadFromFileExample : MonoBehaviour { private IEnumerator Start() { //这里需要注意的是,如果你想加载的资源有依赖的资源 如贴图等资源,则必须先加载依赖资源后加载你所想加载的资源。 //即A依赖B 则必须先加载B到内存中,然后再加载A 并实例化---这里注意依赖项一般可以不用实例化只需要在内存中即可。 AssetBundle abShare = AssetBundle.LoadFromFile("AssetBundles/materials/mapmaterials"); string path = "AssetBundles/scene/map_01"; //LoadFromMemoryAsync 和 LoadFromMemory --内存读取 AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path)); //异步的方式 yield return request; //异步的方式 必须等待完成后才继续执行 AssetBundle ab = request.assetBundle; //AssetBundle ab = AssetBundle.LoadFromMemory(File.ReadAllBytes(path));//同步的方式 //使用资源 GameObject gameObj = ab.LoadAsset<GameObject>("map_001"); Instantiate(gameObj); yield return null; } }
-
WWW(万维网)-WWW(万维网)对象方法可以从本地读取,也可以从服务器读取。
using System.Collections; using UnityEngine; public class LoadFromFileExample : MonoBehaviour { private IEnumerator Start() { //这里需要注意的是,如果你想加载的资源有依赖的资源 如贴图等资源,则必须先加载依赖资源后加载你所想加载的资源。 //即A依赖B 则必须先加载B到内存中,然后再加载A 并实例化---这里注意依赖项一般可以不用实例化只需要在内存中即可。 //AssetBundle abShare = AssetBundle.LoadFromFile("AssetBundles/materials/mapmaterials"); //注意!!! //www.LoadFromCacheOrDownload 这个方法是先下载存到cache的缓存空间内 然后在进行提取。 //如果第二次也进行下载一样的 则会在这个缓存空间内提取之前已经下载的数据 //开始下载前必须先判断是否准备好了,否则一直循环下去,等待准备好 while (!Caching.ready) //检查cache 缓存是否准备好了 yield return null; //完整的路径---本地下载 //string allPath = @"E:/03_TestDemo/01_UnityDemo/ShowMap_ABPackageTest_001/AssetBundles/scene/map_01"; //WWW www = WWW.LoadFromCacheOrDownload(allPath, 1); //远程服务器下载 WWW www = WWW.LoadFromCacheOrDownload(@"http://localhost/AssetBundles/scene/map_01", 1); //从远程服务器上下载AB包 yield return www; //因万维网是非常复杂的,经常容易出现非常意外的错误,所以必须加入一个判断。 if (!string.IsNullOrEmpty(www.error)) //当什么都没有时 { Debug.Log(www.error); yield break; //跳出协程 } AssetBundle ab = www.assetBundle; //使用资源 GameObject gameObj = ab.LoadAsset<GameObject>("map_001"); Instantiate(gameObj); yield return null; //上述下载时没有加载相应的贴图材质。。。注意!!! } }
-
第四种Unity封装的UnityWebRequest对象---(专用于替代WWW的远程加载方式)
using System.Collections; using UnityEngine; using UnityEngine.Networking; public class LoadFromFileExample : MonoBehaviour { private IEnumerator Start() { //这里需要注意的是,如果你想加载的资源有依赖的资源 如贴图等资源,则必须先加载依赖资源后加载你所想加载的资源。 //即A依赖B 则必须先加载B到内存中,然后再加载A 并实例化---这里注意依赖项一般可以不用实例化只需要在内存中即可。 //AssetBundle abShare = AssetBundle.LoadFromFile("AssetBundles/materials/mapmaterials"); //第四种远程加载方式---(专门用于替换WWW的远程加载方式) //string uri = @"E:/03_TestDemo/01_UnityDemo/ShowMap_ABPackageTest_001/AssetBundles/scene/map_001"; string uri = @"http://localhost/AssetBundles/scene/map_001"; UnityWebRequest request = UnityWebRequest.GetAssetBundle(uri); yield return request.SendWebRequest(); //注意是异步方式所以必须等待他完成后再执行 //两种获取ab对象的方式 //AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request); //第一种方法 AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle; //第二种方法 //使用资源 GameObject gameObj = ab.LoadAsset<GameObject>("map_001"); Instantiate(gameObj); yield return null; //注意上述的远程加载方式是没有加载其依赖的资源 } }
-
_加载<AB包依赖项> ---(根据AB包文件夹下的 "AssetBundle文件以及AssetBundle.manifest文件")
using System.Collections; using UnityEngine; using UnityEngine.Networking; public class Load : MonoBehaviour { //第一种是服务端加载AB资源包 和依赖包 private IEnumerator Start() { //从一个服务器下载一个AB包的管理文件AssetBundles 和 AssetBundles.manifest string uri = @"http://localhost/AssetBundles/AssetBundles"; UnityWebRequest request = UnityWebRequest.GetAssetBundle(uri); yield return request.SendWebRequest(); //AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle; //第一种方法 AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);//第二种方法 AssetBundleManifest manifest = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest"); string[] str = manifest.GetAllAssetBundles(); foreach (string s in str) { UnityWebRequest uwr = UnityWebRequest.GetAssetBundle(@"http://localhost/AssetBundles/" + s); yield return uwr.SendWebRequest(); AssetBundle TmpAB = DownloadHandlerAssetBundle.GetContent(uwr);//第二种方法 Object[] obj = TmpAB.LoadAllAssets(); foreach (Object o in obj) { if (o is GameObject) { Instantiate(o); } print(obj.Length); } } yield return null; } //第二种本地加载AB资源包 和依赖包 #region LoadAB.manifest //private void Start() //{ // //加载得到Manifest文件 // AssetBundle ab = AssetBundle.LoadFromFile("Assets /AssetBundle/AssetBundle"); // AssetBundleManifest manifest = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest"); // //从Manifest文件中得到所有的AB包的路径(包括依赖项) // string[] str = manifest.GetAllAssetBundles(); // foreach (string s in str) // { // AssetBundle assetBundle = AssetBundle.LoadFromFile("Assets/AssetBundle/" + s); // Object[] o = assetBundle.LoadAllAssets(); // foreach (Object temp in o) // { // if (temp is GameObject) // { // Instantiate(temp); // } // } // } //} #endregion }
上述方法直接在场景中见一个空物体挂载其脚本即可(注意前提是AB包必须已经按相应方式创建好了)
-
打包时的分组:
-
一个ui界面或者所有ui界面一个包(包含所有贴图和布局信息)
-
一个角色或者所有角色一个包(包含模型和动画)
-
所有场景共用一个包
-
所有声音一个包,所有shader一个包,或者按照关卡登。
-
经常更新的资源和不经常更新的区分开,同时加载的放在一起等等,一个资源两个版本,可通过后缀区分。
-
关于AssetBundle卸载:内存有限,转换场景或关卡,把之前不需要的ab包释放掉。减少内存使用,防止资源丢失。AssetBundle.Unload(true)卸载所有资源(在关卡切换时,资源没被调用时)。AssetBundle.Unload(fasle):卸载所有没有被使用的资源。个别资源通过Resources.UnLoadUnuseAssets();场景切换时,unity会自动调用该方法。
13.Image与RawImage的区别?
- RawImgae:可以是任何类型的Texture
- Iamge:只能是精灵Sprite
14.Unity有哪些特定的文件夹名字,有什么作用?
- Editor: 存放编辑器脚本文件夹。可放在Assets根目录下,或者其他子文件夹下。该文件夹所有资源不会被打包进发布包中,且脚本只能在编辑器中使用。一般工具类脚本,或者编辑用DLL。
- Resources:根目录或者子目录。该文件资源都会被打包进.apk或者.ipa。Resource.Load():编辑或运行直接读取。Resources.LoadAssetAtPath():读取Assets目录下任意资源,不能在真机上使用,路径是“Assets/XXX/XXX”,且带文件后缀名。AssetDatabase.LoadAssetAtPath():同上。
- Standard Assets:只能Assets根目录,且只有一个。文件中的脚本最先被编译。可以用C#脚本访问js脚本或者其他语言脚本。
- Plugins:Plugins/Android:存放Android插件,包括.jar或者xml;Plugins/iOS:存放iOS插件,包括.a .m .mm文件等。会自动打包。
- Hidden Assets:以Hideen命名的文件夹,以 . ~ cvs 命名的文件或文件夹,或tmp扩展名的文件。文件夹资源不会被导入,脚本不会被编译,也不会出现在Project视图中。
- WebPlayerTemplates:用来替换web build的默认网页。这个文件夹中的脚本都不会被编译。这个文件夹必须作为Assets文件夹的直接子目录。
15.Unity如何实现游戏截图?
using UnityEngine;
public class ScreenShot : MonoBehaviour {
void Update () {
if (Input.GetKeyDown(KeyCode.J)) {
Camera camera = GameObject.Find("Main Camera").gameObject.GetComponent<Camera>();
int ratio = 2; //图片大小取决于ratio
Rect rect = new Rect(0, 0, (int)Screen.width / ratio, (int)Screen.height / 2);
Texture2D tex = FunScreenShot(camera, rect);
}
}
private Texture2D FunScreenShot(Camera camera,Rect rect) {
RenderTexture rt = new RenderTexture((int)rect.width, (int)rect.height, 0);
camera.targetTexture = rt;
camera.Render();
RenderTexture.active = rt;
Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24, false);
screenShot.ReadPixels(rect, 0, 0); //从屏幕读取像素到保存的纹理数据中。
screenShot.Apply(); // 实际上应用所有以前的SetPixel和SetPixels更改。
camera.targetTexture = null;
RenderTexture.active = null;
GameObject.Destroy(rt);
byte[] bytes = screenShot.EncodeToPNG(); //设置文件类型
string fileName = Application.dataPath + "/Resources/ScreenShot/" + System.DateTime.Now.ToFileTime() + ".png"; //存放路径
System.IO.File.WriteAllBytes(fileName, bytes);
#if UNITY_EDITOR
UnityEditor.AssetDatabase.Refresh(); //刷新,这步很关键,否则后面调用图片时没有。
#endif
return screenShot;
}
}