1.BasePanel和UIManager
子类面板继承BasePanel,UIManager实现动态创建面板,展示面板,隐藏面板,得到面板
(1)单例类
(2)canvas设置为预制体,将新创建的面板设置为该子类
(3)面板和预制体名字一致
abstract class BasePanel : MonoBehaviour
{private CanvasGroup canvasGroup;private float alphaSpeed = 10;public bool IsShow = false;private UnityAction hideCallback = null;protected virtual void Awake(){canvasGroup = this.GetComponent<CanvasGroup>();if (canvasGroup == null)canvasGroup = this.gameObject.AddComponent<CanvasGroup>();}protected virtual void Start(){Init();}/// <summary>/// 注册控件的方法 让所有的子面板都去注册一些方法 子类必须实现父类中的抽象方法/// </summary>public abstract void Init();public virtual void ShowMe(){canvasGroup.alpha = 0;IsShow = true;}public virtual void HideMe(UnityAction action){canvasGroup.alpha = 1;IsShow = false;hideCallback = action;}// Update is called once per frameprotected virtual void Update(){//透明度不为1 就一直加 这样可以保证不会反复进入这个方法//渐入if(IsShow && canvasGroup.alpha != 1){canvasGroup.alpha += alphaSpeed * Time.deltaTime;if(canvasGroup.alpha >= 1)canvasGroup.alpha = 1;}//渐出else if (!IsShow && canvasGroup.alpha != 0){canvasGroup.alpha -= alphaSpeed * Time.deltaTime;if (canvasGroup.alpha <= 0){canvasGroup.alpha = 0;hideCallback?.Invoke();}}}
}
public class UIManager
{//不继承mono 所以可以newprivate static UIManager instance = new UIManager();public static UIManager Instance => instance;private Transform canvasTrans;//在构造函数中对canvas进行初始化public UIManager(){GameObject canvasObj = GameObject.Instantiate(Resources.Load<GameObject>("UI/Canvas"));canvasTrans = canvasObj.transform;GameObject.DontDestroyOnLoad(canvasObj);}//字典管理已经显示过的面板 当需要隐藏时就移除该面板private Dictionary<string, BasePanel> panelDic = new Dictionary<string, BasePanel>();//显示面板//泛型约束:是BasePanel类或者BasePanel子类都可以public T ShowPanel<T>() where T : BasePanel{//要保证泛型T的类型 和 面板预制体名字一致string panelName = typeof(T).Name;//判断字典中是否显示过该面板//显示过就返回该面板if (panelDic.ContainsKey(panelName)){return (T)panelDic[panelName];}//字典没有 那就根据面板名字 实例化对象GameObject panelObj = GameObject.Instantiate(Resources.Load<GameObject>("UI/" + panelName));//设置父对象为canvas的transformpanelObj.transform.SetParent(canvasTrans, false);//得到面板中的对应脚本T panel = panelObj.GetComponent<T>();//存储面板中的脚本在字典中,方便获取和隐藏panelDic.Add(panelName, panel);//显示逻辑panel.ShowMe();return panel;}/// <summary>/// 隐藏面板/// </summary>/// <typeparam name="T">面板类名</typeparam>/// <param name="isFade">是否淡出完毕过后才删除面板,true为是</param>public void HidePanel<T>(bool isFade = true) where T : BasePanel{string panelName = typeof(T).Name;if (panelDic.ContainsKey(panelName)){if (isFade){//面板淡出过后删除panelDic[panelName].HideMe(() =>{//删除对象 并删除字典中存储的脚本GameObject.Destroy(panelDic[panelName].gameObject);panelDic.Remove(panelName);});}else{//删除对象 并删除字典中存储的脚本GameObject.Destroy(panelDic[panelName].gameObject);panelDic.Remove(panelName);}}}//得到面板public T GetPanel<T>() where T : BasePanel{string panelName = typeof(T).Name;if (panelDic.ContainsKey(panelName)){return (T)panelDic[panelName];}return null;}
}
2.摄像机跟随人物
(1)首先要设置看向的人物,摄像机的偏移(偏移多少),看向人物的偏移(头还是脚),移动速度和旋转速度
public class CameraMove : MonoBehaviour
{//摄像机看向的目标public Transform target;//摄像机相对目标位置的偏移值public Vector3 offsetPos;//看向位置的y的偏移值(看向人的脚还是头)public float bodyHeight;//移动和旋转速度public float moveSpeed;public float rotationSpeed;//目标位置private Vector3 targetPos;//目标旋转四元数private Quaternion targetRot;private void Update(){if (target == null) return;//根据目标对象 计算 摄像机当前的位置和角度//位置的计算//向后偏移z坐标targetPos = target.position + target.forward * offsetPos.z;//向上偏移y坐标targetPos += target.up * offsetPos.y;//左右偏移x坐标targetPos += target.right * offsetPos.x;//通过插值运算 让摄像机不断的向目标点靠拢this.transform.position = Vector3.Lerp(this.transform.position, targetPos, moveSpeed + Time.deltaTime);//旋转//人物位置 + 向上偏移 = 人物身体的点 - 摄像机的点 = 向量//得到最终要看向哪个点的四元数targetRot = Quaternion.LookRotation(target.position + Vector3.up * bodyHeight - this.transform.position);//让摄像机不断的向这个角度靠拢this.transform.rotation = Quaternion.Slerp(this.transform.rotation, targetRot, rotationSpeed * Time.deltaTime);}public void SetTarget(Transform player){this.target = player;}
}