技能指示器就是王者荣耀里面的技能按钮,这个按钮在点击之前是一个按钮的样子,但是点击之后,技能图标会缩小一定大小,并且会出现一个可以拖动的范围按钮,更joystick一样,但是经过从尝试发现单纯使用Easytouch提供的Joystick并不能够符合要求,所以我通过对其进行一下封装来实现这个技能指示器。
UI结构如下:
最外层是一个空物体,用来当作技能指示器来挂载脚本,Icon用于显示 技能图标,以及实现技能按钮缩小的效果,SkillJoystick 就是Easytouch的遥感 组件,用来实现拖动。
代码结构:
我这里的遥感的事件与其他逻辑是相互分离的,我只提供按钮 相应事件的接口, 具体实现是在其它地方,这里相当于使用了桥接者模式。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
namespace WangZhe.UI
{
public class SkillIndicator : MonoBehaviour
{
private static int s_skillJoysticNum = 0;
private ETCJoystick m_skillJoystic;
private Image m_skillBg;
private Image m_thumbIcon;
private Image m_skillIcon;
private Color m_skillBgColorShow;
private Color m_skillBgColorHide;
private Sprite m_skillIconSprite;
private Sprite m_thumbIconSprite;
#region 对外交互的数据
public float DragDisPersent { get; private set; }
public string Name { get; set; }
public int ID { get; private set; }
public Vector2 DragDir { get; private set; }
public UnityEvent OnDrag;
public UnityEvent OnDragEnd;
#endregion
private void Awake()
{
s_skillJoysticNum++;
m_skillJoystic = transform.GetComponentInChildren<ETCJoystick>();
m_skillBg = m_skillJoystic.GetComponent<Image>();
m_thumbIcon = m_skillJoystic.transform.Find("Thumb").GetComponent<Image>();
m_skillIcon = transform.Find("Icon").GetComponent<Image>();
m_skillBgColorShow = m_skillBg.color;
m_skillBgColorHide = new Color(0, 0, 0, 0);
m_skillIconSprite = m_skillIcon.sprite;
m_thumbIconSprite = m_thumbIcon.sprite;
#region 对外数据初始化
DragDisPersent = 0;
DragDir = Vector2.zero;
Name = transform.name;
ID = s_skillJoysticNum;
#endregion
m_skillIcon.gameObject.SetActive(false);
m_skillBg.color = m_skillBgColorHide;
m_thumbIcon.sprite = m_skillIconSprite;
m_skillJoystic.onMove.AddListener(OnThumbMove);
m_skillJoystic.onMoveEnd.AddListener(OnThumbMoveEnd);
}
public void OnThumbMove(Vector2 moveDir)
{
m_skillIcon.gameObject.SetActive(true); //显示技能图标
m_skillBg.color = m_skillBgColorShow; //显示拖动范围背景
m_thumbIcon.sprite = m_thumbIconSprite; //修改拖动按钮的背景
Vector3 thumbPos = m_thumbIcon.transform.localPosition; //偏移位置
Vector3 bgPos = m_skillBg.transform.localPosition; //中心点位置
DragDisPersent = Vector3.Distance(thumbPos, bgPos) / m_skillJoystic.GetRadius(); //偏移距离除以半径得到拖动偏移的百分比
DragDir = moveDir; //设置位移方向
OnDrag.Invoke(); //提供接口做处理
}
public void OnThumbMoveEnd()
{
m_skillIcon.gameObject.SetActive(false); //隐藏技能图标
m_skillBg.color = m_skillBgColorHide; //隐藏拖动范围图标
m_thumbIcon.sprite = m_skillIconSprite; //修改拖动按钮图标
DragDisPersent = 0; //设置拖动距离百分比为0
DragDir = Vector2.zero; //设置拖动方向为0
OnDragEnd.Invoke(); //提供接口
}
}
}
最上面的一些数据是控制按钮本身的UI显示用的变量,还有一部分是用来与外界交互的变量(后面可能会添加一些,后面不够用了再添就是)。
初始化里面就不说了, 都是些绑定操作,最后两句就是将joystick的move 事件与函数相绑定,重点在这 两个函数里面。
这两个函数里面主要都是对自身按钮UI显示的操作,而对外提供的接口就是OnDrag和OnDragEnd这两个委托函数,这两个使得我可以在其它地方去绑定具体的按钮事件。
使用:
这只是一个技能指示器按钮,相当于一个控制里面的 一个部分,而 王者荣耀的控制按钮中,左边的移动按钮永远是不变的,只是 右边的按钮会根据技能个数而改变,所以我讲右边的部分整体做成 一个预制体,根据技能个数来加载对应的预制体,所以控制 逻辑与实现逻辑分开是必要的。
这个使用如下:
using HedgehogTeam.EasyTouch;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using WydUtility.Extension;
using WangZhe.Battle.Charactor;
using WangZhe.UI;
namespace WangZhe.Battle.UI
{
public enum Skill_ID
{
ATK,
Skill1,
Skill2,
Skill3,
Skill4
}
public class BattleControlPanel : MonoBehaviour
{
protected ETCButton m_ATKBtn;
protected ETCJoystick m_joystick;
protected SkillIndicator[] m_skillIndicators;
private void Awake()
{
m_joystick = GameObject.Find("CharaJoystic").GetComponent<ETCJoystick>();
m_skillIndicators = transform.GetComponentsInChildren<SkillIndicator>();
if (null == m_joystick)
Debug.LogWarningFormat("未找到遥感");
if (m_skillIndicators.Length <= 0)
Debug.LogWarningFormat("未找到任何技能控制器");
m_joystick.onMove.AddListener(OnJoysticMove);
foreach(SkillIndicator si in m_skillIndicators)
{
si.OnDrag.AddListener(new UnityAction(() => OnSkillStart(si)));
}
}
protected virtual void OnJoysticMove(Vector2 moveDir)
{
PlayerSystem.Instance.PlayerMove(moveDir);
}
protected virtual void OnSkillStart(SkillIndicator skillIndicator)
{
Vector2 skillDir = skillIndicator.DragDir;
float skillDisPercent = skillIndicator.DragDisPersent;
PlayerSystem.Instance.SkillReleasBegin(skillDir, skillDisPercent);
}
protected virtual void OnSkillRelease()
{
}
protected virtual void InitOnAwake() { }
}
}
当这个按钮使用的时候回去通知PlayerSystem去实现相对应的技能效果。
效果: