unity问答-基础知识与数据结构

目录

1.委托是什么?Event关键字有什么用?

2.Unity协程是如何实现的 (IEnumerator)

3.摄像机有几种模式,成像原理分别是什么?

4.Canvas 有几种模式,如何配置?

5.UGUI如何打包图集?

6.UGUI如何实现UI物体淡入淡出?

7.Hash表的原理是什么, 如何实现?

8.链表如何实现?

9.Unity节点缓存池如何实现?

10.Unity如何实现单例模式?

11.MenuItem 什么意思?

12.AB包;.manifest有什么作用?

13.Image与RawImage的区别?

14.Unity有哪些特定的文件夹名字,有什么作用?

15.Unity如何实现游戏截图?

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.链表如何实现?

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定义和作用:
  1. AssetBundle是一个压缩包含模型,贴图,预制体,声音,甚至是整个场景,可以在游戏运行时加载。
  2. AssetBundle自身保存依赖关系;(AB包后缀为 manifest的文件可被文本形式打开)
  3. 压缩可以使用LZ4和LZMA压缩算法,减少包大小,更快进行网络传输。
  4. 把一些可以下载的内存放进AssetBundle里,减少安装包的大小。
  • 使用流程:
  1. 基本设置:指定资源的AssetBundle属性,选择资源,(xxxa/xxx):xxxa会生成目录,名字为xxx。
  2. 打包:使用编辑扩展器--build所有以及设置好要打包的assetbundle资料。脚本要放到Editor文件夹下,否则报错
  3. 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. 加载: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包必须已经按相应方式创建好了)

  • 打包时的分组:

  1. 一个ui界面或者所有ui界面一个包(包含所有贴图和布局信息)

  2. 一个角色或者所有角色一个包(包含模型和动画)

  3. 所有场景共用一个包

  4. 所有声音一个包,所有shader一个包,或者按照关卡登。

  5. 经常更新的资源和不经常更新的区分开,同时加载的放在一起等等,一个资源两个版本,可通过后缀区分。

  • 关于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;
	}
}

16.Unity如何调用android与iOS的 API函数?

猜你喜欢

转载自blog.csdn.net/wang_lvril/article/details/108998105