首页 > 编程 > C# > 正文

Unity实现游戏卡牌滚动效果

2020-01-24 00:09:14
字体:
来源:转载
供稿:网友

最近项目中的活动面板要做来回滚动卡牌预览效果,感觉自己来写的话,也能写,但是可能会比较耗时,看到Github上有开源的项目,于是就借用了,Github的资源地址,感谢作者的分享。

本篇博客旨在告诉大家如何利用这个插件。

插件的核心在于工程中的6个脚本,以下是六个脚本的源码:

DragEnhanceView.cs

using UnityEngine;using System.Collections;using UnityEngine.UI;using UnityEngine.EventSystems; public class UGUIEnhanceItem : EnhanceItem{ private Button uButton; private Image image;  protected override void OnStart() { image = GetComponent<Image>(); uButton = GetComponent<Button>(); uButton.onClick.AddListener(OnClickUGUIButton); }  private void OnClickUGUIButton() { OnClickEnhanceItem(); }  // Set the item "depth" 2d or 3d protected override void SetItemDepth(float depthCurveValue, int depthFactor, float itemCount) { int newDepth = (int)(depthCurveValue * itemCount); this.transform.SetSiblingIndex(newDepth); }  public override void SetSelectState(bool isCenter) { if (image == null)  image = GetComponent<Image>(); image.color = isCenter ? Color.white : Color.gray; }}

EnhanceScrollViewDragController.cs

using UnityEngine;using System.Collections; public class EnhanceScrollViewDragController : MonoBehaviour{ private Vector2 lastPosition = Vector2.zero; private Vector2 cachedPosition = Vector2.zero; private GameObject dragTarget;  private Camera targetCamera; private int rayCastMask = 0; private bool dragStart = false;  public void SetTargetCameraAndMask(Camera camera, int mask) { this.targetCamera = camera; this.rayCastMask = mask; }  void Update() { if (this.targetCamera == null)  return;#if UNITY_EDITOR ProcessMouseInput();#elif UNITY_IOS || UNITY_ANDROID ProcessTouchInput();#endif }  /// <summary> /// Process Mouse Input /// </summary> private void ProcessMouseInput() { if (Input.GetMouseButtonDown(0)) {  if (targetCamera == null)  return;  dragTarget = RayCast(this.targetCamera, Input.mousePosition);  lastPosition.x = Input.mousePosition.x;  lastPosition.y = Input.mousePosition.y; } if (Input.GetMouseButton(0)) {  if (dragTarget == null)  return;  cachedPosition.x = Input.mousePosition.x;  cachedPosition.y = Input.mousePosition.y;  Vector2 delta = cachedPosition - lastPosition;  if (!dragStart && delta.sqrMagnitude != 0f)  dragStart = true;   if (dragStart)  {  // Notify target  dragTarget.SendMessage("OnEnhanceViewDrag", delta, SendMessageOptions.DontRequireReceiver);  }  lastPosition = cachedPosition; }  if (Input.GetMouseButtonUp(0)) {  if (dragTarget != null && dragStart)  {  dragTarget.SendMessage("OnEnhaneViewDragEnd", SendMessageOptions.DontRequireReceiver);  }  dragTarget = null;  dragStart = false; } }  /// <summary> /// Process Touch input /// </summary> private void ProcessTouchInput() { if (Input.touchCount > 0) {  Touch touch = Input.GetTouch(0);  if (touch.phase == TouchPhase.Began)  {  if (targetCamera == null)   return;  dragTarget = RayCast(this.targetCamera, Input.mousePosition);  }  else if (touch.phase == TouchPhase.Moved)  {  if (dragTarget == null)   return;  if (!dragStart && touch.deltaPosition.sqrMagnitude != 0f)  {   dragStart = true;  }  if (dragStart)  {   // Notify target   dragTarget.SendMessage("OnEnhanceViewDrag", touch.deltaPosition, SendMessageOptions.DontRequireReceiver);  }  }  else if (touch.phase == TouchPhase.Ended)  {  if (dragTarget != null && dragStart)  {   dragTarget.SendMessage("OnEnhaneViewDragEnd", SendMessageOptions.DontRequireReceiver);  }  dragTarget = null;  dragStart = false;  } } }  public GameObject RayCast(Camera cam, Vector3 inPos) { Vector3 pos = cam.ScreenToViewportPoint(inPos); if (float.IsNaN(pos.x) || float.IsNaN(pos.y))  return null; if (pos.x < 0f || pos.x > 1f || pos.y < 0f || pos.y > 1f) return null;  Ray ray = cam.ScreenPointToRay(inPos); float dis = 100f; RaycastHit[] hits = Physics.RaycastAll(ray, dis, rayCastMask); if (hits.Length > 0) {  for (int i = 0; i < hits.Length; i++)  {  GameObject go = hits[i].collider.gameObject;  DragEnhanceView dragView = go.GetComponent<DragEnhanceView>();  if (dragView == null)   continue;  else  {   // just return current hover object our drag target   return go;  }  } } return null; }}

EnhanceItem.cs

using UnityEngine;using System.Collections; public class EnhanceItem : MonoBehaviour{ // Start index private int curveOffSetIndex = 0; public int CurveOffSetIndex { get { return this.curveOffSetIndex; } set { this.curveOffSetIndex = value; } }  // Runtime real index(Be calculated in runtime) private int curRealIndex = 0; public int RealIndex { get { return this.curRealIndex; } set { this.curRealIndex = value; } }  // Curve center offset  private float dCurveCenterOffset = 0.0f; public float CenterOffSet { get { return this.dCurveCenterOffset; } set { dCurveCenterOffset = value; } } private Transform mTrs;  void Awake() { mTrs = this.transform; OnAwake(); }  void Start() { OnStart(); }  // Update Item's status // 1. position // 2. scale // 3. "depth" is 2D or z Position in 3D to set the front and back item public void UpdateScrollViewItems( float xValue, float depthCurveValue, int depthFactor, float itemCount, float yValue, float scaleValue) { Vector3 targetPos = Vector3.one; Vector3 targetScale = Vector3.one; // position targetPos.x = xValue; targetPos.y = yValue; mTrs.localPosition = targetPos;  // Set the "depth" of item // targetPos.z = depthValue; SetItemDepth(depthCurveValue, depthFactor, itemCount); // scale targetScale.x = targetScale.y = scaleValue; mTrs.localScale = targetScale; }  protected virtual void OnClickEnhanceItem() { EnhanceScrollView.GetInstance.SetHorizontalTargetItemIndex(this); }  protected virtual void OnStart() { }  protected virtual void OnAwake() { }  protected virtual void SetItemDepth(float depthCurveValue, int depthFactor, float itemCount) { }  // Set the item center state public virtual void SetSelectState(bool isCenter) { }}

EnhanceScrollView.cs

using UnityEngine;using System.Collections;using System.Collections.Generic; public class EnhanceScrollView : MonoBehaviour{ public enum InputSystemType { NGUIAndWorldInput, // use EnhanceScrollViewDragController.cs to get the input(keyboard and touch) UGUIInput,  // use UDragEnhanceView for each item to get drag event }  // Input system type(NGUI or 3d world, UGUI) public InputSystemType inputType = InputSystemType.NGUIAndWorldInput; // Control the item's scale curve public AnimationCurve scaleCurve; // Control the position curve public AnimationCurve positionCurve; // Control the "depth"'s curve(In 3d version just the Z value, in 2D UI you can use the depth(NGUI)) // NOTE: // 1. In NGUI set the widget's depth may cause performance problem // 2. If you use 3D UI just set the Item's Z position public AnimationCurve depthCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0)); // The start center index [Tooltip("The Start center index")] public int startCenterIndex = 0; // Offset width between item public float cellWidth = 10f; private float totalHorizontalWidth = 500.0f; // vertical fixed position value  public float yFixedPositionValue = 46.0f;  // Lerp duration public float lerpDuration = 0.2f; private float mCurrentDuration = 0.0f; private int mCenterIndex = 0; public bool enableLerpTween = true;  // center and preCentered item private EnhanceItem curCenterItem; private EnhanceItem preCenterItem;  // if we can change the target item private bool canChangeItem = true; private float dFactor = 0.2f;  // originHorizontalValue Lerp to horizontalTargetValue private float originHorizontalValue = 0.1f; public float curHorizontalValue = 0.5f;  // "depth" factor (2d widget depth or 3d Z value) private int depthFactor = 5;  // Drag enhance scroll view [Tooltip("Camera for drag ray cast")] public Camera sourceCamera; private EnhanceScrollViewDragController dragController;  public void EnableDrag(bool isEnabled) { if (isEnabled) {  if (inputType == InputSystemType.NGUIAndWorldInput)  {  if (sourceCamera == null)  {   Debug.LogError("## Source Camera for drag scroll view is null ##");   return;  }   if (dragController == null)   dragController = gameObject.AddComponent<EnhanceScrollViewDragController>();  dragController.enabled = true;  // set the camera and mask  dragController.SetTargetCameraAndMask(sourceCamera, (1 << LayerMask.NameToLayer("UI")));  } } else {  if (dragController != null)  dragController.enabled = false; } }  // targets enhance item in scroll view public List<EnhanceItem> listEnhanceItems; // sort to get right index private List<EnhanceItem> listSortedItems = new List<EnhanceItem>();  private static EnhanceScrollView instance; public static EnhanceScrollView GetInstance { get { return instance; } }  void Awake() { instance = this; }  void Start() { canChangeItem = true; int count = listEnhanceItems.Count; dFactor = (Mathf.RoundToInt((1f / count) * 10000f)) * 0.0001f; mCenterIndex = count / 2; if (count % 2 == 0)  mCenterIndex = count / 2 - 1; int index = 0; for (int i = count - 1; i >= 0; i--) {  listEnhanceItems[i].CurveOffSetIndex = i;  listEnhanceItems[i].CenterOffSet = dFactor * (mCenterIndex - index);  listEnhanceItems[i].SetSelectState(false);  GameObject obj = listEnhanceItems[i].gameObject;   if (inputType == InputSystemType.NGUIAndWorldInput)  {  DragEnhanceView script = obj.GetComponent<DragEnhanceView>();  if (script != null)   script.SetScrollView(this);  }  else  {  UDragEnhanceView script = obj.GetComponent<UDragEnhanceView>();  if (script != null)   script.SetScrollView(this);  }  index++; }  // set the center item with startCenterIndex if (startCenterIndex < 0 || startCenterIndex >= count) {  Debug.LogError("## startCenterIndex < 0 || startCenterIndex >= listEnhanceItems.Count out of index ##");  startCenterIndex = mCenterIndex; }  // sorted items listSortedItems = new List<EnhanceItem>(listEnhanceItems.ToArray()); totalHorizontalWidth = cellWidth * count; curCenterItem = listEnhanceItems[startCenterIndex]; curHorizontalValue = 0.5f - curCenterItem.CenterOffSet; LerpTweenToTarget(0f, curHorizontalValue, false);  //  // enable the drag actions //  EnableDrag(true); }  private void LerpTweenToTarget(float originValue, float targetValue, bool needTween = false) { if (!needTween) {  SortEnhanceItem();  originHorizontalValue = targetValue;  UpdateEnhanceScrollView(targetValue);  this.OnTweenOver(); } else {  originHorizontalValue = originValue;  curHorizontalValue = targetValue;  mCurrentDuration = 0.0f; } enableLerpTween = needTween; }  public void DisableLerpTween() { this.enableLerpTween = false; }  ///  /// Update EnhanceItem state with curve fTime value ///  public void UpdateEnhanceScrollView(float fValue) { for (int i = 0; i < listEnhanceItems.Count; i++) {  EnhanceItem itemScript = listEnhanceItems[i];  float xValue = GetXPosValue(fValue, itemScript.CenterOffSet);  float scaleValue = GetScaleValue(fValue, itemScript.CenterOffSet);  float depthCurveValue = depthCurve.Evaluate(fValue + itemScript.CenterOffSet);  itemScript.UpdateScrollViewItems(xValue, depthCurveValue, depthFactor, listEnhanceItems.Count, yFixedPositionValue, scaleValue); } }  void Update() { if (enableLerpTween)  TweenViewToTarget(); }  private void TweenViewToTarget() { mCurrentDuration += Time.deltaTime; if (mCurrentDuration > lerpDuration)  mCurrentDuration = lerpDuration;  float percent = mCurrentDuration / lerpDuration; float value = Mathf.Lerp(originHorizontalValue, curHorizontalValue, percent); UpdateEnhanceScrollView(value); if (mCurrentDuration >= lerpDuration) {  canChangeItem = true;  enableLerpTween = false;  OnTweenOver(); } }  private void OnTweenOver() { if (preCenterItem != null)  preCenterItem.SetSelectState(false); if (curCenterItem != null)  curCenterItem.SetSelectState(true); }  // Get the evaluate value to set item's scale private float GetScaleValue(float sliderValue, float added) { float scaleValue = scaleCurve.Evaluate(sliderValue + added); return scaleValue; }  // Get the X value set the Item's position private float GetXPosValue(float sliderValue, float added) { float evaluateValue = positionCurve.Evaluate(sliderValue + added) * totalHorizontalWidth; return evaluateValue; }  private int GetMoveCurveFactorCount(EnhanceItem preCenterItem, EnhanceItem newCenterItem) { SortEnhanceItem(); int factorCount = Mathf.Abs(newCenterItem.RealIndex) - Mathf.Abs(preCenterItem.RealIndex); return Mathf.Abs(factorCount); }  // sort item with X so we can know how much distance we need to move the timeLine(curve time line) static public int SortPosition(EnhanceItem a, EnhanceItem b) { return a.transform.localPosition.x.CompareTo(b.transform.localPosition.x); } private void SortEnhanceItem() { listSortedItems.Sort(SortPosition); for (int i = listSortedItems.Count - 1; i >= 0; i--)  listSortedItems[i].RealIndex = i; }  public void SetHorizontalTargetItemIndex(EnhanceItem selectItem) { if (!canChangeItem)  return;  if (curCenterItem == selectItem)  return;  canChangeItem = false; preCenterItem = curCenterItem; curCenterItem = selectItem;  // calculate the direction of moving float centerXValue = positionCurve.Evaluate(0.5f) * totalHorizontalWidth; bool isRight = false; if (selectItem.transform.localPosition.x > centerXValue)  isRight = true;  // calculate the offset * dFactor int moveIndexCount = GetMoveCurveFactorCount(preCenterItem, selectItem); float dvalue = 0.0f; if (isRight) {  dvalue = -dFactor * moveIndexCount; } else {  dvalue = dFactor * moveIndexCount; } float originValue = curHorizontalValue; LerpTweenToTarget(originValue, curHorizontalValue + dvalue, true); }  // Click the right button to select the next item. public void OnBtnRightClick() { if (!canChangeItem)  return; int targetIndex = curCenterItem.CurveOffSetIndex + 1; if (targetIndex > listEnhanceItems.Count - 1)  targetIndex = 0; SetHorizontalTargetItemIndex(listEnhanceItems[targetIndex]); }  // Click the left button the select next next item. public void OnBtnLeftClick() { if (!canChangeItem)  return; int targetIndex = curCenterItem.CurveOffSetIndex - 1; if (targetIndex < 0)  targetIndex = listEnhanceItems.Count - 1; SetHorizontalTargetItemIndex(listEnhanceItems[targetIndex]); }  public float factor = 0.001f; // On Drag Move public void OnDragEnhanceViewMove(Vector2 delta) { // In developing if (Mathf.Abs(delta.x) > 0.0f) {  curHorizontalValue += delta.x * factor;  LerpTweenToTarget(0.0f, curHorizontalValue, false); } }  // On Drag End public void OnDragEnhanceViewEnd() { // find closed item to be centered int closestIndex = 0; float value = (curHorizontalValue - (int)curHorizontalValue); float min = float.MaxValue; float tmp = 0.5f * (curHorizontalValue < 0 ? -1 : 1); for (int i = 0; i < listEnhanceItems.Count; i++) {  float dis = Mathf.Abs(Mathf.Abs(value) - Mathf.Abs((tmp - listEnhanceItems[i].CenterOffSet)));  if (dis < min)  {  closestIndex = i;  min = dis;  } } originHorizontalValue = curHorizontalValue; float target = ((int)curHorizontalValue + (tmp - listEnhanceItems[closestIndex].CenterOffSet)); preCenterItem = curCenterItem; curCenterItem = listEnhanceItems[closestIndex]; LerpTweenToTarget(originHorizontalValue, target, true); canChangeItem = false; }}

NGUIEnhanceItem.cs

using UnityEngine;using System.Collections; /// <summary>/// NGUI Enhance item example/// </summary>public class NGUIEnhanceItem : EnhanceItem{ private UITexture mTexture;  protected override void OnAwake() { this.mTexture = GetComponent<UITexture>(); UIEventListener.Get(this.gameObject).onClick = OnClickNGUIItem; }  private void OnClickNGUIItem(GameObject obj) { this.OnClickEnhanceItem(); }  // Set the item "depth" 2d or 3d protected override void SetItemDepth(float depthCurveValue, int depthFactor, float itemCount) { if (mTexture.depth != (int)Mathf.Abs(depthCurveValue * depthFactor))  mTexture.depth = (int)Mathf.Abs(depthCurveValue * depthFactor); }  // Item is centered public override void SetSelectState(bool isCenter) { if (mTexture == null)  mTexture = this.GetComponent<UITexture>(); if (mTexture != null)  mTexture.color = isCenter ? Color.white : Color.gray; }  protected override void OnClickEnhanceItem() { // item was clicked base.OnClickEnhanceItem(); }}

UGUIEnhanceItem.cs

using UnityEngine;using System.Collections;using UnityEngine.UI;using UnityEngine.EventSystems; public class UGUIEnhanceItem : EnhanceItem{ private Button uButton; private Image image;  protected override void OnStart() { image = GetComponent<Image>(); uButton = GetComponent<Button>(); uButton.onClick.AddListener(OnClickUGUIButton); }  private void OnClickUGUIButton() { OnClickEnhanceItem(); }  // Set the item "depth" 2d or 3d protected override void SetItemDepth(float depthCurveValue, int depthFactor, float itemCount) { int newDepth = (int)(depthCurveValue * itemCount); this.transform.SetSiblingIndex(newDepth); }  public override void SetSelectState(bool isCenter) { if (image == null)  image = GetComponent<Image>(); image.color = isCenter ? Color.white : Color.gray; }}

导入以上6个脚本以后,我们开始制作效果,先从NGUI开始,我们先在场景中,随便添加一个背景,然后,我们在UIRoot下面添加一个空物体,取名Scrollview,添加EnhanceScrollView.cs脚本,然后制作六个Texture作为Scrollview的子物体,添加DragEnhanceView.cs脚本,NGUIEnhanceItem.cs脚本,BoxCollider组件。接着,我们在六个图片下方添加两个Button,作为左右切换卡牌的按钮,在点击事件中,拖入Scrollview,分别添加OnBtnLeftClick,OnBtnRightClick方法。做完以上操作以后,场景大概是这样:

接着,我们选中Scrollview,调整脚本参数:

ScaleCurve图像参数,设置为如下,左右循环都为pingpong:

PositionCurve图像参数如下,左右循环都为loop:

DepthCurve图像参数如下,左右循环都为loop:

然后把Scrollview的子物体都拖到ListEnhanceItems这个公开数组下:

这样,我们就把配置工作都做好了,运行游戏:

可以看到,效果还不错,左右滑动或者点击切换按钮,就能实现切换卡牌的功能。

接着,我们看一下UGUI的实现,UGUI的UI布局基本和NGUI保持一致,所不同的是Scrollview的子物体添加的脚本不一样,所需要的脚本及组件如下图所示:

然后,还有需要注意的一点是,在Scrollview上的参数配置上,我们需要把InputType这个属性调整为UGUI Input

曲线设置和子物体数组设置和NGUI一样,这里就不再重复了,配置完这些操作以后,运行,UGUI也能实现一样的卡牌滚动效果:

以上,感谢Github。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表