using DG.Tweening; using SC.XR.Unity.Module_InputSystem; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; using SC.XR.Unity; using XRTool.Util; public class MenuUI : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler { Transform _pointParent;//曲线控制点父物体 List _anchorPointGroup = new List();//曲线控制点集合 Transform _menuParent;//菜单元素父物体 List _menuElementGroup = new List();//菜单元素集合 List _elementDataGroup = new List();//元素数据集合。菜单元素集合与元素数据集合始终保持一 一对应的关系(在集合中的位置) int _preMidIndex;//元素集合中间索引的上一个索引 int _middleIndex;//元素集合中间索引 int _nextMidIndex;//元素集合中间索引的下一个索引 int _segmentNum;//所需贝塞尔曲线点连接的段数(点的数量减一) public Dictionary _bezierPointGroup = new Dictionary();//记录所需贝塞尔曲线定位点的集合 Vector3[] _velocityGroup;//从一点到另一点的最大速度集合 float _spacingTime = 0.2f;//从一点到另一点的最短时间(用于计算预设的最大速度) bool _isInLeft = false;//图标是否开始真正往左串位 bool _isInRight = false;//图标是否开始真正往右串位 float _maxDragValue = 100f;//拖动时,x坐标的预设增量基数 Vector3 _normalScale;//正常的缩放值 Vector3 _targetScale;//预设的目标放大值 float _scaleFactor = 1.4f;//缩放系数 bool _isOver = false;//链表中数据是否读取完 bool _isClickDel = false;//是否点击了删除按钮 bool _isInit = false;//是否初始化完毕 /// /// 初始化 /// public void Init() { _pointParent = transform.Find("AnchorPoint"); _menuParent = transform.Find("Element"); LoadAnchorPoint(); LoadGameObject(); _segmentNum = _menuElementGroup.Count + 1; _velocityGroup = new Vector3[_segmentNum]; _normalScale = _menuElementGroup[0].localScale; _targetScale = _normalScale * _scaleFactor; SaveCurvePoint(); GetVelocity(); DisplayMenuElement(); RecordValue(); EventTool._rearrange += RearrangeElements; _isInit = true; } void LoadAnchorPoint()//加载定位点 { foreach (Transform item in _pointParent) { _anchorPointGroup.Add(item); } } MenuIcon _tempIcon; void LoadGameObject()//加载游戏对象和游戏对象所承载的数据 { foreach (Transform item in _menuParent) { _tempIcon = item.gameObject.AddComponent(); _tempIcon.Init(); _menuElementGroup.Add(item); _elementDataGroup.Add(_tempIcon); } LoadData(); _preMidIndex = _menuElementGroup.Count / 2 - 1; _middleIndex = _menuElementGroup.Count / 2; _nextMidIndex = _menuElementGroup.Count / 2 + 1; } /// /// 初始化加载数据 /// public void LoadData() { _isOver = false; //清空数据 for (int i = 0; i < _elementDataGroup.Count; i++) { _elementDataGroup[i].DataConfig = null; } DoubleLinkNode _node = ConfigModel.Instance.GetFirstMenuItem(); //初始化数据 for (int i = 0; i < _elementDataGroup.Count; i++) { if (!_isOver) { if (ConfigModel.Instance.GetFirstMenuItem() != null) { _elementDataGroup[i].DataConfig = _node; _node = _node.NextNode; if (_node.PreNode == ConfigModel.Instance.GetLastMenuItem()) { _isOver = true; } } } } } void GetVelocity()//求得从一点到另一点的最大速度(存入数组中)(速度方向从左指向右) { for (int i = 0; i < _velocityGroup.Length; i++) { float _dis = Vector3.Distance(_bezierPointGroup[i - 1], _bezierPointGroup[i]); _velocityGroup[i] = (_dis / _spacingTime) * (_bezierPointGroup[i] - _bezierPointGroup[i - 1]).normalized; } } void DisplayMenuElement()//刷新让元素处于对应的坐标点和缩放值 { for (int i = 0; i < _menuElementGroup.Count; i++) { _menuElementGroup[i].localPosition = _bezierPointGroup[i]; } if (!_isClickDel)//如果没有点击删除按钮,则中间位置元素为放大显示 { // _menuElementGroup[_middleIndex].localScale = _targetScale; _menuElementGroup[_preMidIndex].localScale = _normalScale; _menuElementGroup[_nextMidIndex].localScale = _normalScale; // } } private void SaveCurvePoint()//存储贝塞尔曲线上的七个定位点位置 { for (int i = -1; i < _segmentNum; i++) { float t = (i + 1) / (float)_segmentNum; int nodeIndex = 0; Vector3 pixel = CalculateBezierPoint(t, _anchorPointGroup[nodeIndex].localPosition, _anchorPointGroup[nodeIndex + 1].localPosition, _anchorPointGroup[nodeIndex + 2].localPosition); _bezierPointGroup.Add(i, pixel); } } void ResetCurvePoint()//重置贝塞尔曲线上的七个定位点 { for (int i = -1; i < _segmentNum; i++) { float t = (i + 1) / (float)_segmentNum; int nodeIndex = 0; Vector3 pixel = CalculateBezierPoint(t, _anchorPointGroup[nodeIndex].localPosition, _anchorPointGroup[nodeIndex + 1].localPosition, _anchorPointGroup[nodeIndex + 2].localPosition); _bezierPointGroup[i] = pixel; } } void Update() { if (_isInit) { ResetCurvePoint(); } } private Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2)//根据t值计算相应曲线上的点 { float u = 1 - t; float tt = t * t; float uu = u * u; Vector3 p = uu * p0; p += 2 * u * t * p1; p += tt * p2; return p; } public void OnBeginDrag(PointerEventData eventData) { IsDrag(true); } public void OnDrag(PointerEventData eventData) { float _delta = eventData.delta.x / _maxDragValue;//记录拖动的增量比值(用作速度比值) if (_delta < -0.1f)//向左拖动时 { _isInRight = false; if (!_isInLeft)//如果没有归位到当前元素应该处于的位置上,就先让元素先移动到对应的位置上 { if (_menuElementGroup[0].localPosition == _bezierPointGroup[0]) { if (!_isClickDel)//如果没有点击删除按钮,则播中间位置元素为放大显示 { // _menuElementGroup[_middleIndex].localScale = _targetScale; _menuElementGroup[_preMidIndex].localScale = _normalScale; // } _isInLeft = true; return; } for (int i = 0; i < _menuElementGroup.Count; i++) { if (!_isClickDel)//如果没有点击删除按钮,则播放缩放动画 { // if (i == _middleIndex) { float _prop = Vector3.Distance(_menuElementGroup[i].localPosition, _bezierPointGroup[i + 1]) / Vector3.Distance(_bezierPointGroup[i], _bezierPointGroup[i + 1]); _menuElementGroup[i].localScale = Vector3.Lerp(_normalScale, _targetScale, _prop); } else if (i == _preMidIndex) { float _prop = Vector3.Distance(_menuElementGroup[i].localPosition, _bezierPointGroup[i + 1]) / Vector3.Distance(_bezierPointGroup[i], _bezierPointGroup[i + 1]); _menuElementGroup[i].localScale = Vector3.Lerp(_targetScale, _normalScale, _prop); } // } _menuElementGroup[i].DOKill(); //拖拽的增量比值乘以预设的最大速度,实现设备拖拽速度与游戏对象移动速度成正比 _menuElementGroup[i].DOLocalMove(_bezierPointGroup[i], -_delta * _velocityGroup[i + 1].magnitude).SetSpeedBased(); } } else//开始移位 { for (int i = 0; i < _menuElementGroup.Count; i++) { if (!_isClickDel)//如果没有点击删除按钮,则播放缩放动画 { // if (i == _middleIndex) { float _prop = Vector3.Distance(_menuElementGroup[i].localPosition, _bezierPointGroup[i]) / Vector3.Distance(_bezierPointGroup[i], _bezierPointGroup[i - 1]); _menuElementGroup[i].localScale = Vector3.Lerp(_targetScale, _normalScale, _prop); } else if (i == _nextMidIndex) { float _prop = Vector3.Distance(_menuElementGroup[i].localPosition, _bezierPointGroup[i]) / Vector3.Distance(_bezierPointGroup[i], _bezierPointGroup[i - 1]); _menuElementGroup[i].localScale = Vector3.Lerp(_normalScale, _targetScale, _prop); } // } _menuElementGroup[i].DOKill(); _menuElementGroup[i].DOLocalMove(_bezierPointGroup[i - 1], -_delta * _velocityGroup[i].magnitude).SetSpeedBased(); } if (_menuElementGroup[0].localPosition == _bezierPointGroup[-1]) { _menuElementGroup[0].DOKill(); ShiftToLeft(); DisplayMenuElement(); } } } else if (_delta > 0.1f)//向右拖动时 { _isInLeft = false; if (!_isInRight)//如果没有归位到当前元素应该处于的位置上,就先让元素移动到对应的位置上 { if (_menuElementGroup[0].localPosition == _bezierPointGroup[0]) { if (!_isClickDel)//如果没有点击删除按钮,则中间位置元素为放大显示 { // _menuElementGroup[_middleIndex].localScale = _targetScale; _menuElementGroup[_nextMidIndex].localScale = _normalScale; // } _isInRight = true; return; } for (int i = 0; i < _menuElementGroup.Count; i++) { if (!_isClickDel)//如果没有点击删除按钮,则播放缩放动画 { // if (i == _middleIndex) { float _prop = Vector3.Distance(_menuElementGroup[i].localPosition, _bezierPointGroup[i - 1]) / Vector3.Distance(_bezierPointGroup[i], _bezierPointGroup[i - 1]); _menuElementGroup[i].localScale = Vector3.Lerp(_normalScale, _targetScale, _prop); } else if (i == _nextMidIndex) { float _prop = Vector3.Distance(_menuElementGroup[i].localPosition, _bezierPointGroup[i - 1]) / Vector3.Distance(_bezierPointGroup[i], _bezierPointGroup[i - 1]); _menuElementGroup[i].localScale = Vector3.Lerp(_targetScale, _normalScale, _prop); } // } _menuElementGroup[i].DOKill(); _menuElementGroup[i].DOLocalMove(_bezierPointGroup[i], _delta * _velocityGroup[i].magnitude).SetSpeedBased(); } } else//开始移位 { for (int i = 0; i < _menuElementGroup.Count; i++) { if (!_isClickDel)//如果没有点击删除按钮,则播放缩放动画 { // if (i == _middleIndex) { float _prop = Vector3.Distance(_menuElementGroup[i].localPosition, _bezierPointGroup[i]) / Vector3.Distance(_bezierPointGroup[i], _bezierPointGroup[i + 1]); _menuElementGroup[i].localScale = Vector3.Lerp(_targetScale, _normalScale, _prop); } else if (i == _preMidIndex) { float _prop = Vector3.Distance(_menuElementGroup[i].localPosition, _bezierPointGroup[i]) / Vector3.Distance(_bezierPointGroup[i], _bezierPointGroup[i + 1]); _menuElementGroup[i].localScale = Vector3.Lerp(_normalScale, _targetScale, _prop); } // } _menuElementGroup[i].DOKill(); _menuElementGroup[i].DOLocalMove(_bezierPointGroup[i + 1], _delta * _velocityGroup[i + 1].magnitude).SetSpeedBased(); } if (_menuElementGroup[_menuElementGroup.Count - 1].localPosition == _bezierPointGroup[_menuElementGroup.Count]) { _menuElementGroup[_menuElementGroup.Count - 1].DOKill(); ShiftToRight(); DisplayMenuElement(); } } } else//无位置变换时间超过一秒,则游戏对象不会移动 { for (int i = 0; i < _menuElementGroup.Count; i++) { _menuElementGroup[i].DOKill(); } } } public void OnEndDrag(PointerEventData eventData) { //拖拽结束时,移动回当前对应的定位点位置 for (int i = 0; i < _menuElementGroup.Count; i++) { _menuElementGroup[i].DOKill(); _menuElementGroup[i].DOLocalMove(_bezierPointGroup[i], 0.5f); if (!_isClickDel)//如果没有点击删除按钮,则播放缩放动画 { _menuElementGroup[_middleIndex].DOScale(_targetScale, 0.5f); } else { _menuElementGroup[_middleIndex].DOScale(_normalScale, 0.5f); } _menuElementGroup[_preMidIndex].DOScale(_normalScale, 0.5f); _menuElementGroup[_nextMidIndex].DOScale(_normalScale, 0.5f); } IsDrag(false); } private void ShiftToLeft()//集合元素(游戏对象与数据)往左串位 { //游戏对象往左串位 var _tran = _menuElementGroup[0]; _menuElementGroup.RemoveAt(0); _menuElementGroup.Add(_tran); //数据脚本往左串位 var _icon = _elementDataGroup[0]; if (_elementDataGroup[0].DataConfig != null && _elementDataGroup[_elementDataGroup.Count - 1].DataConfig != null) { _icon.DataConfig = _elementDataGroup[_elementDataGroup.Count - 1].DataConfig.NextNode; } _elementDataGroup.RemoveAt(0); _elementDataGroup.Add(_icon); _icon.RefreshData(); //刷新记录物体的缩放值和索引值 RecordValue(); } private void ShiftToRight()//集合元素(游戏对象与数据)往右串位 { //游戏对象往右串位 var _tran = _menuElementGroup[_menuElementGroup.Count - 1]; _menuElementGroup.RemoveAt(_menuElementGroup.Count - 1); _menuElementGroup.Insert(0, _tran); //数据脚本往右串位 var _icon = _elementDataGroup[_elementDataGroup.Count - 1]; if (_elementDataGroup[0].DataConfig != null && _elementDataGroup[_elementDataGroup.Count - 1].DataConfig != null) { _icon.DataConfig = _elementDataGroup[0].DataConfig.PreNode; } _elementDataGroup.RemoveAt(_elementDataGroup.Count - 1); _elementDataGroup.Insert(0, _icon); _icon.RefreshData(); //刷新记录物体的缩放值和索引值 RecordValue(); } void RearrangeElements(Transform tran)// 回调方法:当删除完元素时,后续元素所在的游戏对象和数据往前移位 { int index = -1; for (int i = 0; i < _menuElementGroup.Count; i++)//求出删除元素所在的位置 { if (_menuElementGroup[i] == tran) { index = i; break; } } //所删除元素的游戏对象位置变换到最后一个定位点(等待向前移位) var _tempElement = _menuElementGroup[index]; _tempElement.position = _bezierPointGroup[_menuElementGroup.Count]; _menuElementGroup.RemoveAt(index); _menuElementGroup.Add(_tempElement); //游戏数据向前移位,赋予给所删除的游戏对象 var _tempData = _elementDataGroup[index]; _elementDataGroup.RemoveAt(index); _elementDataGroup.Add(_tempData); if (_elementDataGroup[_elementDataGroup.Count - 2].DataConfig.NextNode != ConfigModel.Instance.GetFirstMenuItem()) { _elementDataGroup[_elementDataGroup.Count - 1].DataConfig = _elementDataGroup[_elementDataGroup.Count - 2].DataConfig.NextNode; } else { Debug.LogError("这个节点的下一个节点元素为头节点,出错了!"); } //游戏对象向前移位 for (int i = index; i < _menuElementGroup.Count; i++) { _menuElementGroup[i].DOLocalMove(_bezierPointGroup[i], 0.2f); if (i == _preMidIndex) { _menuElementGroup[_preMidIndex].DOScale(_normalScale, 0.2f); _menuElementGroup[_middleIndex].DOScale(_targetScale, 0.2f); } else if (i == _middleIndex) { _menuElementGroup[_middleIndex].DOScale(_targetScale, 0.2f); _menuElementGroup[_menuElementGroup.Count - 1].localScale = _normalScale; } } //刷新记录物体的缩放值和索引值 RecordValue(); } /// /// 刷新记录物体的缩放值和索引值 /// void RecordValue() { for (int i = 0; i < _elementDataGroup.Count; i++) { _elementDataGroup[i].RoomIndex = i; if (i == _middleIndex) { _elementDataGroup[i].initAV3 = _targetScale; } else { _elementDataGroup[i].initAV3 = _normalScale; } } } /// /// 显示房间游戏对象动画 /// public void ShowItemEffect() { for (int i = 0; i < _elementDataGroup.Count; i++) { _elementDataGroup[i].ShowItem(); } } /// /// 隐藏房间游戏对象动画 /// public void HideItemEffect() { for (int i = 0; i < _elementDataGroup.Count; i++) { _elementDataGroup[i].HideItem(); } } /// /// 刷新删除按钮的显示状态 /// public void RefreshDteBtn() { for (int i = 0; i < _elementDataGroup.Count; i++) { _elementDataGroup[i].ChangeDteBtn(); } } /// /// 当加入房间失败时,取消事件监听 /// public void RefeshisClick() { for (int i = 0; i < _elementDataGroup.Count; i++) { _elementDataGroup[i].Refeshbool(); } } /// /// 刷新数据 /// public void UpdateData() { for (int i = 0; i < _elementDataGroup.Count; i++) { _elementDataGroup[i].RefreshData(); } } /// /// 游戏对象是否处于拖拽状态 /// /// private void IsDrag(bool isDrag) { for (int i = 0; i < _elementDataGroup.Count; i++) { _elementDataGroup[i]._isDrag = isDrag; } } void OnDestroy() { EventTool._rearrange -= RearrangeElements; } }