一、3D轮转图
想要实现3D轮转图的效果,需要在场景里面创建一个空对象,然后创建生成轮转图的脚本,
创建好脚本之后,我们需要先明确几个变量:
1.生成物体的数量
2,生成物体范围的半径
3,物体移动的弧度
这三个变量缺一不可,在代码中这样体现:
//你生成的cube
public GameObject prefab;
//生成cube的数量
public int num = 10;
//cube组成圆的半径
public int r = 10;
public float moveAng = 0;//移动后的弧度
之后就开始生成了,生成物体,物体的位置是算出来的
void Start()
{
ang = 2 * Mathf.PI / num;
OnMove();
}
public void OnMove()
{
for (int i = 0; i < num; i++)
{
float x = Mathf.Sin(ang * i + moveAng) * r;
float y = Mathf.Cos(ang * i + moveAng) * r;
if (list.Count <= i)
{
GameObject cell = Instantiate(prefab, transform);
list.Add(cell);
sotrs.Add(cell);
}
list[i].transform.localPosition = new Vector3(x, 0, y);
}
}
这里的list和sorts是GameObject类型的集合
之后创建完物体之后,我们可以在场景中通过调整moveAng的值来控制旋转
之后我们要通过鼠标的拖拽凯控制旋转了
首先创建脚本,这个脚本是挂载到你生成的物体上的,
private void OnMouseDrag()
{
Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
Vector3 mouse = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos.z));
float dis = mouse.x - transform.position.x;
transform.parent.GetComponent<Cyclogam>().OnDrag(dis);
}
之后在生成物体的脚本上写
public void OnDrag(float dis)
{
tweener.Kill();
float dragAng = dis / r;
moveAng -= dragAng;
OnMove();
}
这样就可以实现通过鼠标拖这旋转了
我们还可以加一点缓冲效果
首先先加上这样的代码在生成物体的脚本上
public void Inertia(float dis)
{
float time = Mathf.Abs(dis / cutspeed);
tweener = DOTween.To((a) =>
{
float dragAng = dis / r;
moveAng -= dragAng;
OnMove();
}, dis, 0, time).OnComplete(() =>
{
Align(list.IndexOf(sotrs[0]));
});
}
public void Align(int n)
{
//找到z最小的
sotrs.Sort((a, b) =>
{
if (a.transform.localPosition.z < b.transform.localPosition.z)
{
return -1;
}
else if (a.transform.localPosition.z == b.transform.localPosition.z)
{
return 0;
}
else
{
return 1;
}
});
//找到z最小的在list里的下标
int id = list.IndexOf(sotrs[0]);
//正方形
int zheng = id - n;
//反方向的长度=总长度-正方向长度
int fan = num - Mathf.Abs(zheng);
fan = zheng < 0 ? fan : -fan;
int interval = Mathf.Abs(zheng) < Mathf.Abs(fan) ? zheng : fan;
float interca = (id - n) * ang;
float alianAng = Mathf.Asin(sotrs[0].transform.localPosition.x / r)+ interca;
float alignDis = alianAng * r;
float aligntime = Mathf.Abs(alignDis / cutspeed);
DOTween.To((b) =>
{
moveAng = b;
OnMove();
}, moveAng, moveAng + alianAng, aligntime);
}
然后再挂载在生成物体上的脚本上加上这样的代码:
private void OnMouseUp()
{
Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
Vector3 mouse = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos.z));
float dis = mouse.x - transform.position.x;
transform.parent.GetComponent<Cyclogam>().Inertia(dis);
}
加上之后可以直接去实验,下面附上全部代码
生成物体的脚本:
//你生成的cube
public GameObject prefab;
//生成cube的数量
public int num = 10;
//cube组成圆的半径
public int r = 10;
public float moveAng = 0;//移动后的弧度
public float cutspeed = 10;//减速
//存储生成的cube
List<GameObject> list = new List<GameObject>();
List<GameObject> sotrs = new List<GameObject>();
float ang;
Tweener tweener;
// Start is called before the first frame update
void Start()
{
ang = 2 * Mathf.PI / num;
OnMove();
}
public void OnMove()
{
for (int i = 0; i < num; i++)
{
float x = Mathf.Sin(ang * i + moveAng) * r;
float y = Mathf.Cos(ang * i + moveAng) * r;
if (list.Count <= i)
{
GameObject cell = Instantiate(prefab, transform);
list.Add(cell);
sotrs.Add(cell);
}
list[i].transform.localPosition = new Vector3(x, 0, y);
}
}
public void OnDrag(float dis)
{
tweener.Kill();
float dragAng = dis / r;
moveAng -= dragAng;
OnMove();
}
public void Inertia(float dis)
{
float time = Mathf.Abs(dis / cutspeed);
tweener = DOTween.To((a) =>
{
float dragAng = dis / r;
moveAng -= dragAng;
OnMove();
}, dis, 0, time).OnComplete(() =>
{
Align(list.IndexOf(sotrs[0]));
});
}
public void Align(int n)
{
//找到z最小的
sotrs.Sort((a, b) =>
{
if (a.transform.localPosition.z < b.transform.localPosition.z)
{
return -1;
}
else if (a.transform.localPosition.z == b.transform.localPosition.z)
{
return 0;
}
else
{
return 1;
}
});
//找到z最小的在list里的下标
int id = list.IndexOf(sotrs[0]);
//正方形
int zheng = id - n;
//反方向的长度=总长度-正方向长度
int fan = num - Mathf.Abs(zheng);
fan = zheng < 0 ? fan : -fan;
int interval = Mathf.Abs(zheng) < Mathf.Abs(fan) ? zheng : fan;
float interca = (id - n) * ang;
float alianAng = Mathf.Asin(sotrs[0].transform.localPosition.x / r)+ interca;
float alignDis = alianAng * r;
float aligntime = Mathf.Abs(alignDis / cutspeed);
DOTween.To((b) =>
{
moveAng = b;
OnMove();
}, moveAng, moveAng + alianAng, aligntime);
}
// Update is called once per frame
void Update()
{
}
物体身上的脚本:
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
private void OnMouseDrag()
{
Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
Vector3 mouse = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos.z));
float dis = mouse.x - transform.position.x;
transform.parent.GetComponent<Cyclogam>().OnDrag(dis);
}
private void OnMouseUp()
{
Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
Vector3 mouse = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos.z));
float dis = mouse.x - transform.position.x;
transform.parent.GetComponent<Cyclogam>().Inertia(dis);
}
二、2d轮转图
2d轮转图的逻辑跟3d轮转图的差不多,基本上你3d轮转图理解之后2d轮转图就也差不多了
首先还是跟3d轮转图一样先创建物体
public GameObject prefab;
public int num;
public float r;
public float max = 1;
public float min = 0.5f;
public float ang;
public float moveAng = 0;
public float cutspeed = 50f;//减速
List<GameObject> GList = new List<GameObject>();
List<GameObject> sorts = new List<GameObject>();
void Start()
{
r = prefab.GetComponent<RectTransform>().sizeDelta.x * num / (2 * Mathf.PI);
ang = 2 * Mathf.PI / num;
OnMove();
}
public void OnMove()
{
for (int i = 0; i < num; i++)
{
float x = Mathf.Sin(ang * i + moveAng) * r;
float z = Mathf.Cos(ang * i + moveAng) * r;
if (GList.Count<=i)
{
GameObject cell = Instantiate(prefab, transform);
GList.Add(cell);
sorts.Add(cell);
}
GList[i].transform.localPosition = new Vector3(x, 0, 0);
float scale = (z + r) / (2 * r) * (max - min) + min;
GList[i].transform.localScale = Vector3.one * scale;
}
}
附上效果图:
之后就可以通过拖拽的方法让生成物体进行旋转了,
public void OnDrag(PointerEventData eventData)
{
moveAng += eventData.delta.x / r;
OnMove();
}
public void OnEndDrag(PointerEventData eventData)
{
float time = Mathf.Abs(eventData.delta.x / cutspeed);
DOTween.To((a) =>
{
moveAng += a / r;
OnMove();
}, eventData.delta.x, 0, time).OnComplete(() =>
{
Align(GList.IndexOf(sorts[num - 1]));
});
}
public void Align(int n)
{
int id = GList.IndexOf(sorts[num - 1]);
int zheng = id - n;
int fan = num - Mathf.Abs(zheng);
fan = zheng < 0 ? fan : -fan;
int interval = Mathf.Abs(zheng) < Mathf.Abs(zheng) ? zheng : fan;
float intervalAng = interval * ang;
float AlignAng = Mathf.Asin(sorts[num - 1].transform.localPosition.x / r) + intervalAng;
float time =Mathf.Abs(AlignAng * r / cutspeed);
DOTween.To((b) =>
{
moveAng = b;
OnMove();
}, moveAng, moveAng - AlignAng, time).OnComplete(() =>
{
Debug.Log(n);
});
}
这里需要添加using UnityEngine.EventSystems;命名空间,继承IDragHandler,IEndDragHandler这两个接口,之后就饿可以使用OnDrag方法和OnEndDrag方法
这样就可以实现拖拽旋转和旋转之后可以进行缓冲的效果了
因为在2d轮转图上在后面的图片需要变小所以我们在OnMove方法中添加代码
sorts.Sort((a,b) =>
{
if (a.transform.localScale.z<b.transform.localScale.z)
{
return -1;
}
else if (a.transform.localScale.z == b.transform.localScale.z)
{
return 0;
}
else
{
return 1;
}
});
for (int i = 0; i < sorts.Count; i++)
{
sorts[i].transform.SetSiblingIndex(i);
}
这样就可以实现2d轮转图的拖拽旋转,在后面的物体变小的效果了
附上全部代码
public GameObject prefab;
public int num;
public float r;
public float max = 1;
public float min = 0.5f;
public float ang;
public float moveAng = 0;
public float cutspeed = 50f;//减速
List<GameObject> GList = new List<GameObject>();
List<GameObject> sorts = new List<GameObject>();
// Start is called before the first frame update
void Start()
{
r = prefab.GetComponent<RectTransform>().sizeDelta.x * num / (2 * Mathf.PI);
ang = 2 * Mathf.PI / num;
OnMove();
}
public void OnMove()
{
for (int i = 0; i < num; i++)
{
float x = Mathf.Sin(ang * i + moveAng) * r;
float z = Mathf.Cos(ang * i + moveAng) * r;
if (GList.Count<=i)
{
GameObject cell = Instantiate(prefab, transform);
GList.Add(cell);
sorts.Add(cell);
}
GList[i].transform.localPosition = new Vector3(x, 0, 0);
float scale = (z + r) / (2 * r) * (max - min) + min;
GList[i].transform.localScale = Vector3.one * scale;
}
sorts.Sort((a,b) =>
{
if (a.transform.localScale.z<b.transform.localScale.z)
{
return -1;
}
else if (a.transform.localScale.z == b.transform.localScale.z)
{
return 0;
}
else
{
return 1;
}
});
for (int i = 0; i < sorts.Count; i++)
{
sorts[i].transform.SetSiblingIndex(i);
}
}
public void OnDrag(PointerEventData eventData)
{
moveAng += eventData.delta.x / r;
OnMove();
}
public void OnEndDrag(PointerEventData eventData)
{
float time = Mathf.Abs(eventData.delta.x / cutspeed);
DOTween.To((a) =>
{
moveAng += a / r;
OnMove();
}, eventData.delta.x, 0, time).OnComplete(() =>
{
Align(GList.IndexOf(sorts[num - 1]));
});
}
public void Align(int n)
{
int id = GList.IndexOf(sorts[num - 1]);
int zheng = id - n;
int fan = num - Mathf.Abs(zheng);
fan = zheng < 0 ? fan : -fan;
int interval = Mathf.Abs(zheng) < Mathf.Abs(zheng) ? zheng : fan;
float intervalAng = interval * ang;
float AlignAng = Mathf.Asin(sorts[num - 1].transform.localPosition.x / r) + intervalAng;
float time =Mathf.Abs(AlignAng * r / cutspeed);
DOTween.To((b) =>
{
moveAng = b;
OnMove();
}, moveAng, moveAng - AlignAng, time).OnComplete(() =>
{
Debug.Log(n);
});
}