制作王者荣耀技能范围指示器
发表于2017-09-30
今天教大家制作王者荣耀中使用的技能范围指示器
类型包含:区域圆形、小范围圆形、矩形、扇形
参考下图:
代码已写好注释,有不懂的可以留言问我。
技能摇杆代码:
using UnityEngine; using System.Collections; using UnityEngine.UI; using UnityEngine.EventSystems; using System; public class SkillJoystick : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler { public float outerCircleRadius = 100; Transform innerCircleTrans; Vector2 outerCircleStartWorldPos = Vector2.zero; public Action<Vector2> onJoystickDownEvent; // 按下事件 public Action onJoystickUpEvent; // 抬起事件 public Action<Vector2> onJoystickMoveEvent; // 滑动事件 void Awake() { innerCircleTrans = transform.GetChild(0); } void Start() { outerCircleStartWorldPos = transform.position; } /// <summary> /// 按下 /// </summary> public void OnPointerDown(PointerEventData eventData) { innerCircleTrans.position = eventData.position; if (onJoystickDownEvent != null) onJoystickDownEvent(innerCircleTrans.localPosition / outerCircleRadius); } /// <summary> /// 抬起 /// </summary> public void OnPointerUp(PointerEventData eventData) { innerCircleTrans.localPosition = Vector3.zero; if (onJoystickUpEvent != null) onJoystickUpEvent(); } /// <summary> /// 滑动 /// </summary> public void OnDrag(PointerEventData eventData) { Vector2 touchPos = eventData.position - outerCircleStartWorldPos; if (Vector3.Distance(touchPos, Vector2.zero) < outerCircleRadius) innerCircleTrans.localPosition = touchPos; else innerCircleTrans.localPosition = touchPos.normalized * outerCircleRadius; if (onJoystickMoveEvent != null) onJoystickMoveEvent(innerCircleTrans.localPosition / outerCircleRadius); } }
技能范围指示器代码:
using UnityEngine; using System.Collections; using System.Collections.Generic; public enum SkillAreaType { OuterCircle = 0, OuterCircle_InnerCube = 1, OuterCircle_InnerSector = 2, OuterCircle_InnerCircle = 3, } public class SkillArea : MonoBehaviour { enum SKillAreaElement { OuterCircle, // 外圆 InnerCircle, // 内圆 Cube, // 矩形 Sector60, // 扇形 Sector120, // 扇形 } SkillJoystick joystick; public GameObject player; public SkillAreaType areaType; // 设置指示器类型 Vector3 deltaVec; float outerRadius = 6; // 外圆半径 float innerRadius = 2f; // 内圆半径 float cubeWidth = 2f; // 矩形宽度 (矩形长度使用的外圆半径) int angle = 60; // 扇形角度 bool isPressed = false; string path = "Effect/Prefabs/Hero_skillarea/"; // 路径 string circle = "quan_hero"; // 圆形 string cube = "chang_hero"; // 矩形 string sector60 = "shan_hero_60"; // 扇形60度 string sector120 = "shan_hero_120"; // 扇形120度 Dictionary<SKillAreaElement, string> allElementPath; Dictionary<SKillAreaElement, Transform> allElementTrans; // Use this for initialization void Start() { joystick = GetComponent<SkillJoystick>(); joystick.onJoystickDownEvent = OnJoystickDownEvent; joystick.onJoystickMoveEvent = OnJoystickMoveEvent; joystick.onJoystickUpEvent = OnJoystickUpEvent; InitSkillAreaType(); } void OnDestroy() { joystick.onJoystickDownEvent -= OnJoystickDownEvent; joystick.onJoystickMoveEvent -= OnJoystickMoveEvent; joystick.onJoystickUpEvent -= OnJoystickUpEvent; } void InitSkillAreaType() { allElementPath = new Dictionary<SKillAreaElement, string>(); allElementPath.Add(SKillAreaElement.OuterCircle, circle); allElementPath.Add(SKillAreaElement.InnerCircle, circle); allElementPath.Add(SKillAreaElement.Cube, cube); allElementPath.Add(SKillAreaElement.Sector60, sector60); allElementPath.Add(SKillAreaElement.Sector120, sector120); allElementTrans = new Dictionary<SKillAreaElement, Transform>(); allElementTrans.Add(SKillAreaElement.OuterCircle, null); allElementTrans.Add(SKillAreaElement.InnerCircle, null); allElementTrans.Add(SKillAreaElement.Cube, null); allElementTrans.Add(SKillAreaElement.Sector60, null); allElementTrans.Add(SKillAreaElement.Sector120, null); } void OnJoystickDownEvent(Vector2 deltaVec) { isPressed = true; this.deltaVec = new Vector3(deltaVec.x, 0, deltaVec.y); CreateSkillArea(); } void OnJoystickUpEvent() { isPressed = false; HideElements(); } void OnJoystickMoveEvent(Vector2 deltaVec) { this.deltaVec = new Vector3(deltaVec.x, 0, deltaVec.y); } void LateUpdate() { if(isPressed) UpdateElement(); } /// <summary> /// 创建技能区域展示 /// </summary> void CreateSkillArea() { switch (areaType) { case SkillAreaType.OuterCircle: CreateElement(SKillAreaElement.OuterCircle); break; case SkillAreaType.OuterCircle_InnerCube: CreateElement(SKillAreaElement.OuterCircle); CreateElement(SKillAreaElement.Cube); break; case SkillAreaType.OuterCircle_InnerSector: CreateElement(SKillAreaElement.OuterCircle); switch (angle) { case 60: CreateElement(SKillAreaElement.Sector60); break; case 120: CreateElement(SKillAreaElement.Sector120); break; default: break; } break; case SkillAreaType.OuterCircle_InnerCircle: CreateElement(SKillAreaElement.OuterCircle); CreateElement(SKillAreaElement.InnerCircle); break; default: break; } } /// <summary> /// 创建技能区域展示元素 /// </summary> /// <param name="element"></param> void CreateElement(SKillAreaElement element) { Transform elementTrans = GetElement(element); if (elementTrans == null) return; allElementTrans[element] = elementTrans; switch (element) { case SKillAreaElement.OuterCircle: elementTrans.localScale = new Vector3(outerRadius * 2, 1, outerRadius * 2) / player.transform.localScale.x; elementTrans.gameObject.SetActive(true); break; case SKillAreaElement.InnerCircle: elementTrans.localScale = new Vector3(innerRadius * 2, 1, innerRadius * 2) / player.transform.localScale.x; break; case SKillAreaElement.Cube: elementTrans.localScale = new Vector3(cubeWidth, 1, outerRadius) / player.transform.localScale.x; break; case SKillAreaElement.Sector60: case SKillAreaElement.Sector120: elementTrans.localScale = new Vector3(outerRadius, 1, outerRadius) / player.transform.localScale.x; break; default: break; } } Transform elementParent; /// <summary> /// 获取元素的父对象 /// </summary> /// <returns></returns> Transform GetParent() { if (elementParent == null) { elementParent = player.transform.FindChild("SkillArea"); } if (elementParent == null) { elementParent = new GameObject("SkillArea").transform; elementParent.parent = player.transform; elementParent.localEulerAngles = Vector3.zero; elementParent.localPosition = Vector3.zero; elementParent.localScale = Vector3.one; } return elementParent; } /// <summary> /// 获取元素物体 /// </summary> Transform GetElement(SKillAreaElement element) { if (player == null) return null; string name = element.ToString(); Transform parent = GetParent(); Transform elementTrans = parent.Find(name); if (elementTrans == null) { GameObject elementGo = Instantiate(Resources.Load(path allElementPath[element])) as GameObject; elementGo.transform.parent = parent; elementGo.gameObject.SetActive(false); elementGo.name = name; elementTrans = elementGo.transform; } elementTrans.localEulerAngles = Vector3.zero; elementTrans.localPosition = Vector3.zero; elementTrans.localScale = Vector3.one; return elementTrans; } /// <summary> /// 隐藏所有元素 /// </summary> void HideElements() { if (player == null) return; Transform parent = GetParent(); for (int i = 0, length = parent.childCount; i < length; i ) { parent.GetChild(i).gameObject.SetActive(false); } } /// <summary> /// 隐藏指定元素 /// </summary> /// <param name="element"></param> void HideElement(SKillAreaElement element) { if (player == null) return; Transform parent = GetParent(); Transform elementTrans = parent.Find(element.ToString()); if (elementTrans != null) elementTrans.gameObject.SetActive(false); } /// <summary> /// 每帧更新元素 /// </summary> void UpdateElement() { switch (areaType) { case SkillAreaType.OuterCircle: break; case SkillAreaType.OuterCircle_InnerCube: UpdateElementPosition(SKillAreaElement.Cube); break; case SkillAreaType.OuterCircle_InnerSector: switch (angle) { case 60: UpdateElementPosition(SKillAreaElement.Sector60); break; case 120: UpdateElementPosition(SKillAreaElement.Sector120); break; default: break; } break; case SkillAreaType.OuterCircle_InnerCircle: UpdateElementPosition(SKillAreaElement.InnerCircle); break; default: break; } } /// <summary> /// 每帧更新元素位置 /// </summary> /// <param name="element"></param> void UpdateElementPosition(SKillAreaElement element) { if (allElementTrans[element] == null) return; switch (element) { case SKillAreaElement.OuterCircle: break; case SKillAreaElement.InnerCircle: allElementTrans[element].transform.position = GetCirclePosition(outerRadius); break; case SKillAreaElement.Cube: case SKillAreaElement.Sector60: case SKillAreaElement.Sector120: allElementTrans[element].transform.LookAt(GetCubeSectorLookAt()); break; default: break; } if (!allElementTrans[element].gameObject.activeSelf) allElementTrans[element].gameObject.SetActive(true); } /// <summary> /// 获取InnerCircle元素位置 /// </summary> /// <returns></returns> Vector3 GetCirclePosition(float dist) { if (player == null) return Vector3.zero; Vector3 targetDir = deltaVec * dist; float y = Camera.main.transform.rotation.eulerAngles.y; targetDir = Quaternion.Euler(0, y, 0) * targetDir; return targetDir player.transform.position; } /// <summary> /// 获取Cube、Sector元素朝向 /// </summary> /// <returns></returns> Vector3 GetCubeSectorLookAt() { if (player == null) return Vector3.zero; Vector3 targetDir = deltaVec; float y = Camera.main.transform.rotation.eulerAngles.y; targetDir = Quaternion.Euler(0, y, 0) * targetDir; return targetDir player.transform.position; } }
效果展示: