unity选择关卡的跑马灯效果

最近项目中需要做一个类似乱斗西游的选择关卡的效果,如下所示


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

四元数公式:
    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);
	}
}


  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
Unity中制作剧情关卡可以按照以下步骤进行: 1. 设定关卡目标:确定关卡的主要任务和玩家需要达到的目标。这可以是解决谜题、击败敌人、找到特定物品等等。 2. 设计关卡地图:使用Unity的场景编辑器创建关卡的地图布局。可以在地图上放置各种元素,如墙壁、道具、敌人等,以营造合适的游戏环境。 3. 创建角色控制器:使用Unity的角色控制器组件来控制玩家角色的移动、跳跃和互动。可以设置玩家与关卡中的其他对象的碰撞行为。 4. 设置触发器:使用Unity的触发器组件来创建与关卡剧情相关的触发事件。例如,当玩家进入特定区域时触发对话、触发故事情节的发展等。 5. 设计关卡流程:通过编写脚本来控制关卡的流程和剧情的进展。可以使用Unity的编程语言例如C#来创建关卡事件、剧情对话和游戏状态转换等。 6. 添加特效和音效:通过在关卡中添加视觉特效和音效来增强剧情的氛围和体验。可以使用Unity的粒子系统来创建特殊效果,使用音频组件来添加音效。 7. 测试和优化:在完成关卡后,进行测试并修复任何可能出现的问题。确保关卡的难度适当、剧情流畅,并优化性能以确保游戏在不同平台上的稳定运行。 总结起来,制作Unity剧情关卡的关键是设定目标、设计地图、创建角色控制器、设置触发器、设计关卡流程、添加特效和音效,并进行测试和优化以提高玩家的游戏体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梁工123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值