2D


3D 人物移动

Transform

在这里插入代码片

刚体

在这里插入代码片

导航网格

在这里插入代码片

摄像机跟随第三人称

在这里插入代码片

工具类

单例模式

很多地方都需要使用单例模式,只要需要继承这个类,就可以在任何地方通过:类名._Instance使用类中的方法和变量。

public class SingletonBase<T> : MonoBehaviour where T : MonoBehaviour
    {
        protected static T _instance;
        private static object _lock = new object();

        /// <summary>
        /// 单例
        /// </summary>
        /// <returns></returns>
        public static T _Instance
        {
            get
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        _instance = (T) FindObjectOfType(typeof(T));

                        if (FindObjectsOfType(typeof(T)).Length > 1)
                        {
                            return _instance;
                        }

                        if (_instance == null)
                        {
                            GameObject singleton = new GameObject();
                            _instance = singleton.AddComponent<T>();
                            singleton.name = typeof(T).ToString();

                            DontDestroyOnLoad(singleton);
                        }
                    }

                    return _instance;
                }
            }
        }
    }

上面的方法由我师傅提供。虽然他不晓得。
下面这个简单一些。

public class Singleton<T> : MonoBehaviour where T:Singleton<T>
{
    public static T _Instance { get; private set; }
    protected void Awake()
    {
        if (_Instance == null)
        {
            _Instance = (T)this;
            DontDestroyOnLoad(gameObject);
        }
        else {
            Destroy(gameObject);
        }
    }
}

调用的方式是一样的。

public class GameManager : Singleton<GameManager>//需要继承自Singleton
{
     //公有字段
     public string MyName = "GoodCooking";

    //私有字段
    private string MySex = "Boy";

  
    //公有方法
    public void SayHello()
    {
        Debug.Log("Hello");
    }

    //私有方法
    private void SayError()
    {
        Debug.Log("Error");
    }
}

调用

public class LoadTXT : MonoBehaviour
{
    void Start()
    {
        string name = GameManager._Instance.MyName;//可以访问GameManager中使用public修饰的变量或方法
        string sex = GameManager._Instance.MySex;//private 的字段会报错 ,提示有一定的访问级别
        GameManager._Instance.SayHello();//public 的就可以访问
        GameManager._Instance.SayError();//private 的方法会报错 ,提示有一定的访问级别
    }
}

查找一个物体

本方法由我师傅提供

使用了递归,

/// <summary>
        /// 查找子节点对象
        /// </summary>
        /// <param name="goParent">父对象</param>
        /// <param name="childName">子节点名称</param>
        /// <returns></returns>
        public static Transform FindTheChildNode(GameObject goParent, string childName)
        {
            Transform searchTrans = goParent.transform.Find(childName);

            if (searchTrans == null)
            {
                foreach (Transform trans in goParent.transform)
                {
                    searchTrans = FindTheChildNode(trans.gameObject, childName);
                    if (searchTrans != null)
                    {
                        return searchTrans;
                    }
                }
            }

            return searchTrans;
        }

在别的地方可以通过,具体的用法和find是一样的。

FindTheChildNode(gameObject,"你找的物体的名字");

gameObject是你要找的物体的父物体,
后面需要找的子物体的名称,返回值类型是Transform.
目前是只可以查找子物体,同一级别查找不到,需要使用FindWithTag(),当物体在”DontDestroyOnLoad“下,但是需要查找不在”DontDestroyOnLoad“的物体的时候需要使用FindWithTag();

打开一个PDF

前置:需要引用名空间

using System.IO;

然后再GameManager中方法

public class GameManager : Singleton<GameManager>//使用了上面的单例
{
    /// <summary>
    /// 打开PDF
    /// </summary>
    /// <param name="fileName">文件名称</param>
    public void OpenBook(string fileName)
    {
        string path = "file:///" + Application.dataPath + "/StreamingAssets/";
        if(File.Exists(path + fileName))
        {
            Application.OpenURL(path + fileName);
        }
        else {
            Debug.Log("文件不存在,请检查文件路径"+path+fileName);
        }
    }
}

可以在任何位置通过

GameManager._Instance.OpenBook("文件名");

调用。
方法的文档链接:File.Exists , Application.OpenURL

匹配字符串

在一大堆字符串中找到对应的字符串,使用的KMP算法,具体使用KMP算法

public class GameManager : Singleton<GameManager>
{
    private void GetNext(string T, int[] next)
    {
        int i = 0, j = 0;
        next[0] = 0;
        while ((i + 1) < T.Length)
        {
            if (j == 0 || T[i] == T[j - 1])
            {
                ++i;
                ++j;
                next[i] = j;
            }
            else
            {
                j = next[j - 1];
            }
        }
    }

    /// <summary>
    /// 查找字符串
    /// </summary>
    /// <param name="S">一大堆字符串</param>
    /// <param name="T">你想找的字符串</param>
    /// <returns>你要找的字符串在一大堆字符串中出现的位置</returns>
    public int GetStringIndex_KMP(string S, string T)
    {
        int i = 0, j = 0;
        int[] next = new int[T.Length];
        GetNext(T, next);
        while (i < S.Length && j < T.Length)
        {
            if (j == 0 || S[i] == T[j])
            {
                ++j;
                ++i;
            }
            else
            {
                j = next[j - 1];
            }
        }
        if (T.Length <= j)
        {
            return i - T.Length;
        }
        else
        {
            return -1;
        }
    }
}

使用示例

string LongLongString = "123123123123123123123123123123567";
        string targetString = "567";
        if (GameManager._Instance.GetStringIndex_KMP(LongLongString, targetString) >0)
        {
            Debug.Log("找到了,位置在:" + (GameManager._Instance.GetStringIndex_KMP(LongLongString, targetString)));
        }
        else
        {
            Debug.Log("没有找到目标字符串");
        }

给按钮添加事件

实现的主要方式是使用"UnityAction",
说明文档=>UnityAction的官方文档黑洞 首先引用命名空间

using UnityEngine.UI;//需要使用按钮UI
using UnityEngine.Events;//需要使用UnityAction

同样GameManager需要继承单例,单例的脚本在最上面

public class GameManager : Singleton<GameManager>

方法体如下

/// <summary>
    /// 为按钮添加点击事件
    /// </summary>
    /// <param name="buttonName">需要添加事件的按钮名称</param>
    /// <param name="buttonOnClickFunc">需要添加的方法</param>
    public void AnyButtonOnClickEvent(string buttonName, UnityAction buttonOnClickFunc)
    {
        Button OnClickButton = null;//需要增加点击事件的按钮
        OnClickButton = GameObject.Find(buttonName).GetComponent<Button>();//使用如果没找到使用GameObject寻找,不过有弊端,不能有重名的, 使用GameObject.Find(buttonName)性能消耗很高,可以按照需求修改,具体就利益相关。
        OnClickButton.onClick.AddListener(buttonOnClickFunc);//为按钮添加事件。
    }

使用方式

GameManager._Instance.AnyButtonOnClickEvent("ButtonA", ()=>{
            Debug.Log("GoodCooking");
        });

        GameManager._Instance.AnyButtonOnClickEvent("ButtonB", () => {
            Debug.Log("ButtonB");
        });

由于“GameObject.Find(buttonName)”的缘故脚本可以挂载到任何位置。
弊端:只能使用无参的方法,可有改成有一个或更多参数的,但是目前我不会。
优化:可以使用Button的主要是在UI上,所以可以有一个UI基础类,所有的UI都继承自这个UI基础类,这样就可以更加高效的调用这个方法,同样也可以修改“ GameObject.Find(buttonName)”换成更高效的查找方式。

删除列表中符合条件的东西

7-19更新。

//首先在list中添加对应的数据,用于测试
 List<String> list=new List<String>();
list.Add("早上好");
list.Add("中午好");
list.Add("晚上好");
/// <summary>
    ///删除列表中符合条件的东西
    /// </summary>
    private void DeleteDate()
    {
       list.ForEach(p =>
        {
            if (p.text == "早上好")//这这里进行进行条件的判断
            {
                list.Remove(p);
                Debug.Log("删掉了哦");
            };
        });
    }

上面那种会有神奇的错误,比如要操作一个占用的list的时候就会抛出一个 InvalidOperationException: Collection was modified; enumeration operation may not execute. 的错误。所以我会使用另外一种方式用于代替。

for(int i=0;i<list.count;i++)
{
  if(list[i]=="中午好")
	{
		list.RemoveAt(i);
		break;//在找到之后停止循环
	}
}

使用上面的方式暂时没有遇到报错。

将多个字节数组合并成一个字节数组

7-27更新

/// <summary>
        /// 将多个byte[] 合并成一个
        /// </summary>
        /// <param name="bytesList">存储 byte[]  列表</param>
        /// <returns>合并之后的 byts [] </returns>
        private static byte[] MergeBytes(List<byte[]> bytesList)
        {

            int bytesLength = 0;//lbytesList中每一行byte元素的总长度

            for (int i = 0; i < bytesList.Count; i++)
            {
                bytesLength = bytesLength + bytesList[i].Length;
            }
            int k = 0;
            byte[] mergeBytes = new byte[bytesLength];//用于存储合并之后的 byts[] 

            for (int i = 0; i < bytesList.Count; i++)
            {
                for (int j = 0; j < bytesList[i].Length; j++)
                {
                    mergeBytes[k] = (bytesList[i])[j];
                    k = k + 1;
                }
            }
            return mergeBytes;
        }

使用说明:
将多个 byte[] 合并成一个 byte[]
参数 bytesList :存储需要转换的字节数组的列表
返回值 mergeBytes :转换好的字节数组

文件读取

using System.IO;
        /// <summary>
        /// 文件读取
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns>读取到的文件的byte []</returns>
        private static byte[] FileContent(string filePath)
        { 
            if(!File.Exists(filePath))
            {
                Console.WriteLine("文件不存在,请检查路径是否错误");
                return null;
            }

            using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                try
                {
                    byte[] buffur = new byte[fs.Length];
                    fs.Read(buffur, 0, (int)fs.Length);
                    fs.Flush();//刷新缓冲区
                    fs.Close();
                    return buffur;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

使用说明:
参数
filePath :文件路径
返回值
读取到的byte []
异常
文件不存在,检查文件路径是否正确。

获取或者添加组件

/// <summary>
        /// 获取或者添加一个组件
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="go"></param>
        /// <returns></returns>
        private static T GetOrAddComponent<T>(GameObject go) where T : Component
        {
            T comp = go.GetComponent<T>();
            if (!comp)
            {
                comp = go.AddComponent<T>();
            }
            return comp;
        }

使用说明:
参数
T :组件的名称
GameObject go :需要获取组件的GameObject
返回值:获取一个组件