您的位置:首页 > 移动开发 > Unity3D

unity选择关卡的跑马灯效果

2016-03-09 16:14 519 查看
最近项目中需要做一个类似乱斗西游的选择关卡的效果,如下所示



涉及到的知识点也就四元数在旋转中的应用。

四元数公式:

    q.w=cos(a/2) 

    q.x=RAix.x*sin(a/2)

    q.y=RAix.y*sin(a/2)

    q.z=RAix.z*sin(a/2)

首先,需要需要假定一个旋转的半径,然后在该空间中放入一系列的单元,这些单元围绕着坐标系的某跟轴旋转,每个单元必然存在一个围绕该轴的角度,比如放入三个单元,那么,这三个单元围绕某个轴旋转的角度必然依次是0, 120, 240,。然后拖拽屏幕,这三个单元在初始旋转角度的基础上做角度的偏移,再根据这个新值计算出新的位置。原理就是这样,下面放上代码。

using UnityEngine;
using System.Collections;
using UnityEngine.Events;
using System.Collections.Generic;

public class LoopScrollView : MonoBehaviour {
[SerializeField]
protected TouchEvent mTouchEvent;
[SerializeField]
private List<GameObject> mChildrenList;
[SerializeField]
private Vector2 mStartTouchPosition;
[SerializeField]
private Vector2 mLastTouchPosition;
[SerializeField]
private UILayer mUILayer;
[SerializeField]
protected float mR = 400;		//虚拟旋转半径
[SerializeField]
private float mAngle = 0;	//虚拟当前旋转角度
[SerializeField]
private float mTargetAngle = 1000;	//选择目标角度
private float mTouchOffsetAngle = 0;	//每次拖动旋转的角度
private int mCurSelectIndex = 0;

public static LoopScrollView Create(Vector2 size, RectTransform rectT, UILayer uiLayer)
{
LoopScrollView obj = UINode.Create<LoopScrollView>("Layout/Common/LoopScrollView", rectT);
obj.GetComponent<RectTransform>().sizeDelta = size;
obj.mUILayer = uiLayer;
return obj;
}

void Awake()
{
mTouchEvent.AddTouchEventListener(onTouchCallBack);
}

void Update()
{
if(mTargetAngle != 1000)
{
mAngle = Mathf.Lerp(mAngle, mTargetAngle, 0.2f);
for(int i = 0; i < mChildrenList.Count; ++i)
{
UpdatePositionByAngle(mChildrenList[i], -2.0f*Mathf.PI*i/mChildrenList.Count + mAngle);
}
float deltaAngle = 180*(mTargetAngle - mAngle)/Mathf.PI;
if(deltaAngle < 0.5f && deltaAngle > -0.5f)
{
mAngle = mTargetAngle;
for(int i = 0; i < mChildrenList.Count; ++i)
{
UpdatePositionByAngle(mChildrenList[i], -2.0f*Mathf.PI*i/mChildrenList.Count + mAngle);
}
mTargetAngle = 1000;
}
UpdateZOrder();
}
}

void setR(int r)
{
mR = r;
for(int i = 0; i < mChildrenList.Count; ++i)
{
UpdatePositionByAngle(mChildrenList[i], -2.0f*Mathf.PI*i/mChildrenList.Count);
}
}

public void AddItem(GameObject obj)
{
obj.transform.parent = this.transform;
obj.transform.localScale = new Vector3(1,1,1);
mChildrenList.Add(obj);
for(int i = 0; i < mChildrenList.Count; ++i)
{
UpdatePositionByAngle(mChildrenList[i], -2.0f*Mathf.PI*i/mChildrenList.Count);
}
UpdateZOrder();
}

void onTouchCallBack(TouchEvent touchEvent)
{
switch (touchEvent.GetTouchEventType())
{
case TouchEvent.TouchEventType.Down:
mLastTouchPosition = touchEvent.Position;
mStartTouchPosition = touchEvent.Position;
break;
case TouchEvent.TouchEventType.Move:
//Debug.Log("拖动");
if(mLastTouchPosition != Vector2.zero)
{
MoveChildren(mLastTouchPosition, touchEvent.Position);
}
mLastTouchPosition = touchEvent.Position;
break;
case TouchEvent.TouchEventType.Up:
mLastTouchPosition = Vector2.zero;
if(mTouchOffsetAngle > 0.4*Mathf.PI/mChildrenList.Count)
{
mTargetAngle = mAngle + 2.0f*Mathf.PI/mChildrenList.Count;
++mCurSelectIndex;
if(mCurSelectIndex > mChildrenList.Count - 1)
{
mCurSelectIndex = 0;
}
}
else if(mTouchOffsetAngle < -0.4*Mathf.PI/mChildrenList.Count)
{
mTargetAngle = mAngle - 2.0f*Mathf.PI/mChildrenList.Count;
--mCurSelectIndex;
if(mCurSelectIndex < 0)
{
mCurSelectIndex = mChildrenList.Count - 1;
}
}
else
{
mTargetAngle = mAngle;
}
mAngle = mAngle + mTouchOffsetAngle;
mTouchOffsetAngle = 0;
UpdateSelectIndex(mCurSelectIndex);
break;
default:
break;
}
}

void MoveChildren(Vector2 lastPosiotn, Vector2 curPosition)
{
//圆心坐标
Vector2 center = new Vector2(0, mR);
for(int i = 0; i < mChildrenList.Count; ++i)
{
Vector2 lastUIPos;
Vector2 curUIPos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(mUILayer.transform as RectTransform, lastPosiotn, mUILayer.UICanvas.worldCamera, out lastUIPos);
RectTransformUtility.ScreenPointToLocalPointInRectangle(mUILayer.transform as RectTransform, curPosition, mUILayer.UICanvas.worldCamera, out curUIPos);
Vector2 offset = curUIPos - lastUIPos;
//位移转角度
if(mTouchOffsetAngle < 2.0f*Mathf.PI/mChildrenList.Count && mTouchOffsetAngle > -2.0f*Mathf.PI/mChildrenList.Count)
{
//mAngle = mAngle - (offset.x)/(2.0f*Mathf.PI*mR);
mTouchOffsetAngle = mTouchOffsetAngle - (offset.x)/(2.0f*Mathf.PI*mR);
}
UpdatePositionByAngle(mChildrenList[i], -2.0f*Mathf.PI*i/mChildrenList.Count + mAngle + mTouchOffsetAngle);
}
UpdateZOrder();
}

void UpdatePositionByAngle(GameObject obj,  float angle)
{
angle += Mathf.PI/2;
Quaternion q = new Quaternion(0, 1*Mathf.Sin(angle/2), 0, Mathf.Cos(angle/2));
Vector3 vec = q * new Vector3(mR, 0, 0);
obj.transform.localPosition = vec + new Vector3(0, 0, mR);
obj.transform.localPosition = new Vector3(obj.transform.localPosition.x, (obj.transform.localPosition.z - mR)/6, obj.transform.localPosition.z);
}

//深度排序
void UpdateZOrder()
{
List<GameObject> sortBuf = new List<GameObject>();
List<GameObject> sortResult = new List<GameObject>();
float leastZ = 10000;
for(int i = 0; i < mChildrenList.Count; ++i)
{
sortBuf.Add(mChildrenList[i]);
}
for(int i = 0; i < mChildrenList.Count; ++i)
{
int index = -1;
for(int j = 0; j < sortBuf.Count; ++j)
{
if(sortBuf[j].transform.localPosition.z < leastZ)
{
leastZ = sortBuf[j].transform.localPosition.z;
index = j;
}
}
sortResult.Add(sortBuf[index]);
sortBuf.RemoveAt(index);
leastZ = 10000;
}

for(int i = 0; i < sortResult.Count; ++i)
{
sortResult[i].transform.SetSiblingIndex(sortResult.Count - i - 1);
}
}

//更新选择
void UpdateSelectIndex(int index)
{
Debug.Log("选择的序号:" + index);
EventCenter.Single.PostEvent("LOOP_SCROLL_VIEW_SELECT_INDEX", index);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: