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 frame
protected 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 所以可以new
private 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的transform
panelObj.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;
}
}