有些移动端不支持触点,但是可以使用方向键的,这时候有些除了要支持方向键操作外,按钮的选择等也需要进行更改,维持,经过无数实验,最终定了一个比较方便使用,尽量少的更改源代码和原本架构的基础上的控制器
该控制器思路:
将挂载的界面(该界面)下的所有按钮(或者toggle)进行持有,存入二维的链表,表示按钮映射到二维坐标轴下的坐标,并允许用户指定该界面默认选择的按钮,当按下方向键时进行相应的切换,当按下确定键时触发按钮绑的事件,该控制器的有点在于不需要对按钮界面做过多操作,只要持有即可。
注意:
1,该控制器控制的是当前界面的所有按钮,当按钮隐藏或者未激活时,是无法选取 的,当按方向键会跳过该按钮
2 ,其次,要挂载在界面上,即不能挂载在某一界面的某一个部分上。
3,A 界面弹窗B界面时,要讲A界面的控制器关掉,调用控制器的EndCtr()方法,
4,A,B界面进行切换,如A显示到隐藏,B隐藏到显示不需要进行额外操作。
5 ,A,B共存,B为当前控制界面,关闭B时,要调用A 的resetartCtr方法。
接下来上代码:
控制器
public EventSystem system;
public bool startCtr;//开始控制
public bool loop;//是否循环选取
public ShowType selectType;//选中类型
//---------------------------------------展示位选中框时---------------------------------
public Image image;//展示背景
//----------------------------------------展示为放大时-------------------------------------
public float zoomSize = 1.3f;//放大尺寸
public int defaultHor, defaultVer;//默认索引
public int moveDir=1;//当五可选对象 切换方向 1:向上 -1:向下
public List<RowInfo> allSelectables;//当前所有可选对象
private int cur_Hor, cur_Ver, lastindex;//当前索引
private SelectableObj curSelect;//当前选中
private bool finding;//是否正在查找按钮
public OnClickEsc onClickEsc;
public bool Dely = true;
void OnEnable()
{
if (allSelectables.Count == 0)
Destroy(this);
else
{
if (system == null)
system = EventSystem.current;
for (int i = 0; i < allSelectables.Count; i++)
{
if (allSelectables[i].selectables.Count == 0)
{
allSelectables.RemoveAt(i);
i--;
Debug.LogWarning("已经将空数据删除,位置:" + i);
}
}
if (Dely)
{
Invoke("SetDefault", 0.1f);
}
else
SetDefault();
}
}
void OnDisable()
{
Debug.Log("Ode");
startCtr = false;
lastindex = 0;
cur_Ver = cur_Hor = 0;
ResetSelect();
}
//开始控制
public void ReStartCtr()
{
startCtr = true;
if (Dely)
{
Invoke("SetDefault",0.1f);
}
else
SetDefault();
}
//结束控制
public void EndCtr()
{
startCtr = false;
ResetSelect();
}
//设置默认按钮
private void SetDefault()
{
startCtr = true;
if (moveDir == 0) moveDir = 1;
defaultVer = Mathf.Clamp(defaultVer, 0, allSelectables.Count - 1);
defaultHor = Mathf.Clamp(defaultHor, 0, allSelectables[defaultVer].selectables.Count - 1);
curSelect = allSelectables[defaultVer].selectables[defaultHor];
cur_Hor = defaultHor;
cur_Ver = defaultVer;
SetSelect();
}
//选中按钮
private void SetSelect()
{
Debug.Log("select:" + cur_Ver + "--" + cur_Hor + "--" + curSelect.selectObj.gameObject.name);
switch (selectType)
{
case ShowType.ShowBG:
image.transform.position = curSelect.selectObj.transform.position;
break;
case ShowType.Zoom:
curSelect.selectObj.transform.localScale = Vector3.one * zoomSize;
break;
case ShowType.Default:
if (system.currentSelectedGameObject == null || system.currentSelectedGameObject != curSelect.selectObj.gameObject)
{
StartCoroutine(SetButton());
}
else
{
system.SetSelectedGameObject(curSelect.selectObj.gameObject);
}
Debug.Log("Current selected GameObject : " + system.firstSelectedGameObject);
break;
default:
break;
}
finding = false;
lastindex = -1;
}
IEnumerator SetButton()
{
yield return new WaitForEndOfFrame();
system.SetSelectedGameObject(curSelect.selectObj.gameObject);
}
//还原当前选中的
private void ResetSelect()
{
if (curSelect == null) return;
switch (selectType)
{
case ShowType.ShowBG:
//image.transform.position = curSelect.selectObj.transform.position;
break;
case ShowType.Zoom:
curSelect.selectObj.transform.localScale = Vector3.one;
break;
case ShowType.Default:
system.SetSelectedGameObject(null);
break;
default:
break;
}
curSelect = null;
}
// Update is called once per frame
void Update()
{
if (startCtr)
{
if (allSelectables.Count > 1 || allSelectables[0].selectables.Count > 1)
{
if (allSelectables.Count >= 1)
{
if (Input.GetKeyDown(KeyCode.UpArrow))
{
FindVer(-1);
finding = true;
}
else if (Input.GetKeyDown(KeyCode.RightArrow))
{
FindHor(1);
finding = true;
}
else if (Input.GetKeyDown(KeyCode.DownArrow))
{
FindVer(1);
finding = true;
}
else if (Input.GetKeyDown(KeyCode.LeftArrow))
{
FindHor(-1);
finding = true;
}
}
}
if ((Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.JoystickButton0)))
{
OnClick();
finding = true;
}
else if (Input .GetKeyDown (KeyCode.Escape))
{
if (onClickEsc !=null)
{
onClickEsc.Invoke();
}
}
}
}
//向上查找
public void FindVer(int dir)
{
if (cur_Ver == 0 && dir == -1)
{
if (loop)
{
cur_Ver = allSelectables.Count - 1;
}
else
{
return;
}
}
else if (cur_Ver == allSelectables.Count - 1 && dir == 1)
{
if (loop)
{
cur_Ver = 0;
}
else
{
return;
}
}
else
{
cur_Ver += dir;
}
cur_Hor = Mathf.Clamp(cur_Hor, 0, allSelectables[cur_Ver].selectables.Count - 1);
SelectableObj obj = allSelectables[cur_Ver].selectables[cur_Hor];
if (!obj.selectObj.interactable || !obj.selectObj.gameObject.activeInHierarchy || !obj.selectObj.enabled)
{
Debug.Log("再次查找");
if (!GetInHor(cur_Hor ))//上方的都隐藏,禁用了
{
FindVer(dir);
return;
}
}else
{
ResetSelect();
curSelect = obj;
SetSelect();
}
}
//向下查找
public void FindHor(int dir)
{
lastindex = cur_Hor;
if (cur_Hor == 0 && dir == -1)
{
if (loop)
{
cur_Hor = allSelectables[cur_Ver].selectables.Count - 1;
}
else
{
lastindex = -1;
return;
}
}
else if (cur_Hor == allSelectables[cur_Ver].selectables.Count - 1 && dir == 1)
{
if (loop)
{
cur_Hor = 0;
}
else
{
lastindex = -1;
return;
}
}
else
{
cur_Hor += dir;
}
SelectableObj obj = allSelectables[cur_Ver].selectables[cur_Hor];
if (!obj.selectObj.interactable || !obj.selectObj.gameObject.activeInHierarchy || !obj.selectObj.enabled || lastindex == cur_Hor)
{
Debug.Log("再次查找");
if (allSelectables[cur_Ver].selectables.Count <= 1 || !GetInHor (cur_Hor))//这一排只有一个或者没有可选的
{
cur_Hor += dir;
FindVer(moveDir);
return;
}
}else
{
ResetSelect();
curSelect = obj;
SetSelect();
}
}
private bool GetInHor(int id)
{
for (int i = 0; i < allSelectables[cur_Ver].selectables.Count; i++)
{
if (!allSelectables[cur_Ver].selectables[i].selectObj.interactable || !allSelectables[cur_Ver].selectables[i].selectObj.gameObject.activeInHierarchy || i == id||i==lastindex)
{
continue;
}
else
{
cur_Hor = i;
ResetSelect();
curSelect = allSelectables[cur_Ver].selectables[i];
SetSelect();
return true;
}
}
return false;
}
public void OnClick()
{
if (curSelect != null)
{
Debug.Log("click" + curSelect.selectObj.gameObject.name);
switch (curSelect.type)
{
case SelectType.Button:
curSelect.selectObj.gameObject.GetComponent<Button>().onClick.Invoke();
break;
case SelectType.Toggle:
Toggle tog = curSelect.selectObj.gameObject.GetComponent<Toggle>();
tog.onValueChanged.Invoke(tog.isOn);
break;
case SelectType.Other:
break;
default:
break;
}
}
if (curSelect !=null&&(!curSelect .selectObj.interactable || !curSelect.selectObj.gameObject.activeInHierarchy || !curSelect.selectObj.enabled))
{
FindHor(1);
}
}
公共类等
//可选对象类型
public enum SelectType
{
Button,
Toggle,
Other
}
//可选对象
[Serializable]
public class SelectableObj
{
public Selectable selectObj;
public SelectType type = SelectType.Button;
}
//每一排
[Serializable]
public class RowInfo
{
[SerializeField]
public List<SelectableObj> selectables;
}
//展示类型
public enum ShowType
{
ShowBG,//展示框
Zoom,//放大
Default,//使用UI自带的
}
[Serializable]
public class OnClickEsc : UnityEvent { }
代码不多,结构简单易懂使用实例就不放了!