|
轮转图是游戏中较为常见的功能,在我们制作一些场景选关或者是做一些选择类似的UI时,我们会觉得想制作一种3D效果的选择方式,3D轮转图往往就是最恰当的一种
实现原理:
利用父物体生成子物体选项,子物体利用x轴上的间距和 最中心靠前的物体最大显示(缩放最大),两侧物体逐渐变小(缩放逐渐变小)的原理制造视觉差,从而形成3D效果,之后利用DragHandler事件制作拖动旋转即可
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.EventSystems;using UnityEngine.UI;using DG.Tweening;public class Chart2d : MonoBehaviour,IDragHandler,IEndDragHandler{ public Image prefab;//预制体 public int num;//个数 public float spacing;//间距 float c;//周长 float r;//半径 float ang;//每个角的弧度 float dis = 0;//拖动的距离 float max = 1;//缩放最大值 float min = 0.5f;//缩放最小值 float cutSpeed = 100;//速度 List<GameObject> list = new List<GameObject>();//查找预制体用集合 List<Transform> sorts = new List<Transform>();//排序用集合 // Start is called before the first frame update void Start() { //周长 = (宽 + 间距)* 个数 c = (prefab.rectTransform.rect.width + spacing) * num; //半径 = 周长/圆的弧度 r = c / (2 * Mathf.PI); //每个角的弧度 = 圆的弧度/个数 ang = (2 * Mathf.PI) / num; Move(); } public void Move() { //移动的弧度 = 拖动的距离/半径 float moveang = dis / r; for (int i = 0; i < num; i++) { float x = Mathf.Sin(i * ang + moveang) * r; float z = Mathf.Cos(i * ang + moveang) * r; //计算缩放比值,例如:半径是1,最近是-1最远是1,所以要算直径的比值,将最近和最远都+1,得出0到2的值,用它与直径2作比较 float p = (z + r) / (2 * r); //进大远小需要反过来,0是离你比较进的距离 p = 1 - p; //用比值计算缩放 区间 * 比例 + 最小值 float scale = (max - min) * p + min; //没有就创建 if (list.Count <= i) { GameObject image = Instantiate(prefab.gameObject, transform); image.name = i.ToString(); list.Add(image); sorts.Add(image.transform); } //设置位置 list.transform.localPosition = Vector3.right * x; //设置缩放 list.transform.localScale = Vector3.one * scale; } //按缩放排序 sorts.Sort((a, b) => { if (a.localScale.x < b.localScale.x) { return -1; } else if (a.localScale.x == b.localScale.x) { return 0; } else { return 1; } }); //根据排序设置渲染顺序 for (int i = 0; i < sorts.Count; i++) { sorts.SetSiblingIndex(i); } } // Update is called once per frame void Update() { } //拖动 public void OnDrag(PointerEventData eventData) { //横向拖动距离 dis -= eventData.delta.x; Move(); } //拖动停止计算惯性 public void OnEndDrag(PointerEventData eventData) { //停止时的速度 float startspeed = eventData.delta.x; float endspeed = 0; //计算停止的时间 float tme = Mathf.Abs(startspeed) / cutSpeed; DOTween.To((float a) => { dis -= a; Move(); }, startspeed, endspeed, time).OnComplete(() => { //停止后对齐最大的 Align(list.IndexOf(sorts[num - 1].gameObject)); }); } //对齐指定下标 public void Align(int n) { //当前的下标 int i = list.IndexOf(sorts[num - 1].gameObject); //计算与指定下标相隔多少个 int s = i - n; int s2 = num - Mathf.Abs(s); s2 = s > 0 ? -s2 : s2; int s3 = Mathf.Abs(s) < Mathf.Abs(s2) ? s : s2; //需要转动的弧度 float moveAng = Mathf.Asin(sorts[num - 1].localPosition.x / r) + s3 * ang; //需要转动的距离 float moveDis = moveAng * r; //需要转动的时间 float time = Mathf.Abs(moveDis) / cutSpeed; DOTween.To((float a) => { dis = a; Move(); }, dis, dis + moveDis, time).OnComplete(() => { //对齐后调用预制体上的函数 //sorts[num - 1].GetComponent<xx>().xx(); }); }} |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|