1、思路:
(1)信息数据:需要展示属性信息
(2)信息的展示:负责显示UI属性信息
(3)UI的跟随:负责实现UI对人物的跟随
(4)UI的管理:负责对UI进行创建于回收,游戏中需要用到UI的地方都是与该脚本的交互。
2、将需要用到的UI资源打到一个图集中,以免出现大量人物的时候图集穿插造成不良的影响。
3、创建一个头顶UI预设,当道对应的目录下面:
为了测试的方便,在Resources下面也放一个做好的UI预设:
需要注意的是,做的这个预设是不带Panel的,因为希望可以把游戏展示的所有人物头顶UI信息放到同一个Panel下管理。
4、创建一个Panel,用来管理头顶的UI信息:
5、UI跟随脚本:
usingUnityEngine;///
///2DUI跟随3D物体///
public classUIFollow3DPosition : MonoBehaviour
{public Transform targetTrans; //2DUI需要跟随的3D目标
public Camera targetCa; //照射的3D目标的摄像机
public Vector3 offsetPos; //2DUI需要在3D目标点的基础上做出的偏移量
public float dis; //3D目标点与摄像机之间的距离,为了实现:3D目标点摄像机机发生变化的时候2DUI也跟随发生变化
public float ratio; //2DUI的缩放比例
[HideInInspector]public bool isAutoScale = false; //控制2DUI是否发生缩放
public const float FarDistance = 40f; //3D目标点与摄像机的最大距离
public const float NearDistance = 6.5f; //3D目标点与摄像机的最小距离
public static Vector3 MaxScale =Vector3.one;public static Vector3 MinScale = new Vector3(0.5f, 0.5f, 0.5f);private Camera uiCa; //NGUI摄像机
Transform selfTrans; //2DUI,因为该脚本是挂在2DUI上的
GameObject selfObj; //2DUI
Vector3 screenPos; //2DUI的屏幕坐标
Vector3 curPos; //2DUI的世界坐标
Vector3 backPos = new Vector3(3000, 0, 0);publicTransform cachedTransform
{get{if (trans == null)
trans=transform;returntrans;
}
}privateTransform trans;voidAwake()
{
selfTrans=transform;
selfObj=gameObject;
uiCa=UICamera.first.cachedCamera;
}public voidQuickUpdate()
{
LateUpdate();
}voidLateUpdate()
{if (targetTrans != null && targetCa != null)
{
screenPos= targetCa.WorldToScreenPoint(targetTrans.position +offsetPos);if(screenPos.z < 0)
{
selfTrans.localPosition=backPos;
}else{
curPos=uiCa.ScreenToWorldPoint(screenPos);
curPos.z= 0;
selfTrans.position=curPos;
}if(isAutoScale)
{
dis=Vector3.Distance(targetTrans.position, targetCa.transform.position);
ratio= Mathf.Clamp01((dis - NearDistance) / (FarDistance -NearDistance));
cachedTransform.localScale=Vector3.Lerp(MaxScale, MinScale, ratio);
}
}
}
}
6、数据及展示的实现:
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingUnityEngine;namespaceModule.UI
{//头顶显示需要用到的是数据
public classCharacterTopParam
{public intlevel;public stringname;public CharacterTopParam(int level, stringname)
{this.level =level;this.name =name;
}
}public classUI_Character_TopUI : MonoBehaviour
{
[SerializeField]
UILabel lblInfo;
GameObject obj= null;publicGameObject cachedGameObjec
{get{if (null ==obj)
obj=gameObject;returnobj;
}
}
UIFollow3DPosition followPos= null;publicUIFollow3DPosition FollowPos
{get{if (null ==followPos)
{
followPos= cachedGameObjec.GetComponent();
followPos.isAutoScale= true;
}returnfollowPos;
}
}public voidShow(CharacterTopParam param)
{if (null !=param)
{
lblInfo.text= string.Format("LV.{0} Name.{1}", param.level, param.name);
cachedGameObjec.SetActive(true);
}
}public voidHide()
{
cachedGameObjec.SetActive(false);
}
}
}
7、将以上两个脚本挂载到做好的UI预设上,并进行相应的设置:
8、UI管理脚本的实现:
usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;namespaceModule.UI
{public classBillboardUIManager
{static BillboardUIManager billboardMgr = null;public staticBillboardUIManager BillboardMgr
{get{if (null ==billboardMgr)
billboardMgr= newBillboardUIManager();returnbillboardMgr;
}
}
Transform childParent;publicBillboardUIManager()
{
GameObject go= GameObject.Find("UI Root/BillboardPanel");
childParent=NGUITools.AddChild(go).transform;
}public voidDestroy()
{
GameObject.Destroy(childParent.gameObject);
}public void SetParentRootActive(boolactive)
{
childParent.gameObject.SetActive(active);
}
Queue queueCharacterTopUI = new Queue();publicUI_Character_TopUI GetCharacterTopUI(Transform target, Camera cam)
{
UI_Character_TopUI topUI= null;if (queueCharacterTopUI.Count <= 0)
{
Object go= Resources.Load("ui_character_top");if(go)
{
GameObject prefab= GameObject.Instantiate(go) asGameObject;
prefab.transform.parent=childParent;
prefab.transform.localPosition=Vector3.zero;
prefab.transform.localRotation=Quaternion.identity;
prefab.transform.localScale=Vector3.one;
NGUITools.SetLayer(prefab, childParent.gameObject.layer);
topUI= prefab.GetComponent();
}
}else{
topUI=queueCharacterTopUI.Dequeue();
}
topUI.FollowPos.targetTrans=target;
topUI.FollowPos.targetCa=cam;
topUI.FollowPos.offsetPos= new Vector3(0, 1, 0);returntopUI;
}voidRecycleCharacterUI(UI_Character_TopUI topUI)
{if (null !=topUI)
{
topUI.Hide();
queueCharacterTopUI.Enqueue(topUI);
}
}
}
}
9,以上就是全部的核心逻辑,下面是调用逻辑:
usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;usingModule.UI;public classCubeCtrl : MonoBehaviour
{
[SerializeField]
Camera targetCam;float speed = 20.0f;
Transform trans= null;publicTransform Trans
{get{if (null ==trans)
trans=transform;returntrans;
}
}//Show UI Info
UI_Character_TopUI characterTopUI = null;publicUI_Character_TopUI CharacterTopUI
{get{if (null ==characterTopUI)
characterTopUI=BillboardUIManager.BillboardMgr.GetCharacterTopUI(Trans, targetCam);returncharacterTopUI;
}
}voidStart()
{
Trans.transform.rotation=Quaternion.identity;
CharacterTopParam param= new CharacterTopParam(12, "我是方的");
CharacterTopUI.Show(param);
}voidUpdate()
{if(Input.GetKey(KeyCode.A))
{
Trans.Translate(-Time.deltaTime * speed, 0, 0);
}else if(Input.GetKey(KeyCode.D))
{
Trans.Translate(Time.deltaTime* speed, 0, 0);
}else if(Input.GetKey(KeyCode.W))
{
Trans.Translate(0, 0, Time.deltaTime *speed);
}else if(Input.GetKey(KeyCode.S))
{
Trans.Translate(0, 0, -Time.deltaTime *speed);
}
}
}
10、项目运行前后的效果对比图:
11、项目运行时候的结构: