Unity2d收金币特效及卡片翻转demo

5 篇文章 0 订阅

一、效果图

1、收集金币效果(可根据需求自行更改)

收集金币特效效果

2、翻页效果(可自行改成搓牌效果【支持4边】)搓牌效果

二、脚本及绑定对象

收集金币需要创建金币的预制体

1、金币脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using DG.Tweening;
using UnityEngine.UI;

/// <summary>
/// 特效管理
/// </summary>
public class EffectManager : MonoBehaviour 
{
    public Button btn1;
    public Button btn2;
    public Button btn3;
    public Button btn4;
    public Button btn5;
    public Button btn6;
    public Button btn7;
    public Button btn8;
    public Button btn9;

	// 货币预制体
	public GameObject[] mCoinPrefab;
	public float mRate = 0.03f;

	// 移动速度
	public float mMoveSpeed = 10;
	public AnimationCurve mMoveSpeedCurve;
	public float mRotateSpeed = 3;
	// 随机位置
	public float startRangeOffect = 1f;
	// 点击播放动画
	public Button btnClick;

	private static EffectManager Instance;
	//货币属性
    private class Coin
    {
        //移动时间
        public float mMoveProgress;
        //货币对象
        public Transform mTransform;
        public Vector3 mRotateSpeed;
        //起始位置
        public Vector3 startIn;
        //目标
        public Vector3 targetIn;
    }
 
    private void Start()
    {
        btnClick.onClick.AddListener(BtnPlay);
        Instance = this;
    }
 
    private void OnDestroy()
    {
        Instance = null;
    }
 
    public void BtnPlay()
    {
        Debug.LogError("位置为:"+new Vector3(4, 4));
        // Play(0, btnClick.transform.position, new Vector3(4, 4), 10);
        Play(0, btnClick.transform.position, btn5.transform.position, 10);
    }
 
    private IEnumerator OnAnimation(float flyTime, int type, Vector3 startIn, Vector3 targetIn, int count)
    {
        Camera sceneCamera = Camera.main;
        Camera uiCamera = null;
 
        Vector3 start, target;
        if (null != uiCamera)
        {
            start = startIn;
            target = targetIn;
 
            // 将UI起点坐标转换为场景起点坐标并保存
            startIn = sceneCamera.ViewportToWorldPoint(uiCamera.WorldToViewportPoint(startIn));
        }
        else
        {
            start = startIn;
            target = targetIn;
        }
 
        System.Collections.Generic.List<Coin> coins = new System.Collections.Generic.List<Coin>();
        float generateTime = 0;
        float generateCount = 0;
        float moveSpeed = flyTime;
 
        while (true)
        {
            if (generateCount < count && generateTime <= 0)
            {
                //计算实例化数量(创建数量依次增多 count / 2 时依次减少)
                int instantiateCount = (int)(generateCount >= count / 2 ? count / 2 - (generateCount - count / 2) : generateCount);
                //实例化对象
                for (int i = 0; i <= instantiateCount; ++i)
                {
                    Coin coin = new Coin();
 
                    coin.mRotateSpeed = new Vector3(
                        Mathf.Lerp(0, 360, UnityEngine.Random.Range(0, 1f)),
                        Mathf.Lerp(0, 360, UnityEngine.Random.Range(0, 1f)),
                        Mathf.Lerp(0, 360, UnityEngine.Random.Range(0, 1f))) * mRotateSpeed;
                    //实例化的对象可从列表中根据自己需求来
                    GameObject go = Instantiate(mCoinPrefab[type], start, UnityEngine.Random.rotationUniform) as GameObject;
                    go.SetActive(true);
                    go.transform.SetParent(transform);
                    go.transform.localScale = Vector3.one;
                    //将实例化的货币初始化
                    coin.mTransform = go.transform;
                    coin.startIn = new Vector3(UnityEngine.Random.Range(startIn.x - startRangeOffect, startIn.x + startRangeOffect), UnityEngine.Random.Range(startIn.y - startRangeOffect, startIn.y + startRangeOffect), UnityEngine.Random.Range(startIn.z - startRangeOffect, startIn.z + startRangeOffect));
                    coin.targetIn = targetIn;
                    coins.Add(coin);
                }
                generateTime = mRate;
                //创建次数
                generateCount++;
            }
            else
            {//实例化间隔时间
                generateTime -= Time.deltaTime;
            }
 
            if (null != uiCamera)
            {
                // 将场景起点坐标转换为UI起点坐标,因为场景可以拖动,不然会造成效果分离的问题,所以必须转换一次
                start = uiCamera.ViewportToWorldPoint(sceneCamera.WorldToViewportPoint(startIn));
            }
 
            for (int i = coins.Count - 1; i >= 0; --i)
            {
                Coin coin = coins[i];
                coin.mTransform.position = Vector3.Lerp(coin.startIn, coin.targetIn, coins[i].mMoveProgress);
                coin.mTransform.Rotate(coin.mRotateSpeed.x * Time.deltaTime, coin.mRotateSpeed.y * Time.deltaTime, coin.mRotateSpeed.z * Time.deltaTime);
                //现在的移动进度
                coin.mMoveProgress = coin.mMoveProgress + Mathf.Max(mMoveSpeedCurve.Evaluate(coin.mMoveProgress), 0.1f) * moveSpeed * Time.deltaTime;
                if (coin.mMoveProgress >= 1)
                {//移动结束之后删除预制体
                    coins.RemoveAt(i);
                    Destroy(coin.mTransform.gameObject);
                }
            }
            //播放结束退出
            if (generateCount >= count && coins.Count == 0)
                break;
 
            yield return null;
        }
    }
 
    public float BeginAnimation(int type, Vector3 source, Vector3 target, int count)
    {
        // 飞行时长
        float flyTime = (target - source).magnitude / mMoveSpeed;
        StartCoroutine(OnAnimation(flyTime, type, source, target, Mathf.Clamp(count, 1, 20)));
        return flyTime;
    }
 
    /// <summary>
    /// 播放特效
    /// </summary>
    /// <param name="type">类型</param>
    /// <param name="source">UI相机中的起点坐标</param>
    /// <param name="target">UI相机中的终点坐标</param>
    /// <param name="count">粒子数量</param>
    /// <returns>播放时长</returns>
    public static float Play(int type, Vector3 source, Vector3 target, int count)
    {
        if (null != Instance)
        {
            return Instance.BeginAnimation(type, source, target, count);
        }
        return 0;
    }

}

2、按钮脚本绑定(其他Button也是照样绑定)

脚本绑定

3、翻卡片脚本
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.Events;
public enum FlipMode
{
    RightToLeft,
    LeftToRight,
	TopToBottom,
	BottomToTop
}

[ExecuteInEditMode]
public class Poker : MonoBehaviour {
    public Canvas canvas;
    [SerializeField]
	public RectTransform PokerPanel;
    public Sprite background;
	public Sprite pokerBack;
	public Sprite pokerFront;
    public bool interactable=true;
    public bool enableShadowEffect=true;
    //represent the index of the sprite shown in the right page

    public Vector3 EndBottomLeft
    {
        get { return ebl; }
    }
    public Vector3 EndBottomRight
    {
        get { return ebr; }
    }
    public float Height
    {
        get
        {
            return PokerPanel.rect.height ; 
        }
    }
    public Image ClippingPlane;
    public Image NextPageClip;
    public Image Shadow;
    //public Image ShadowLTR;
    public Image Left;
    public Image Right;
    public Image RightNext;
    public UnityEvent OnFlip;

    //Spine Bottom
    Vector3 sb;
    //Spine Top
    Vector3 st;
    //corner of the page
    Vector3 c;
    //Edge Bottom Right
    Vector3 ebr;
    //Edge Bottom Left
    Vector3 ebl;
    //follow point 
    Vector3 f;
	//Edge middle Right
	Vector3 mr;
	//middle
	Vector3 mm;
	//Edge middle Left
	Vector3 ml;
	//Edge Top middle
	Vector3 tm;
	//Edge Bottom middle
	Vector3 bm;

    bool pageDragging = false;
    //current flip mode
    FlipMode mode;

    void Start()
    {
        float scaleFactor = 1;
        if (canvas) scaleFactor = canvas.scaleFactor;
		float pageWidth = PokerPanel.rect.width* scaleFactor / 2;
		float pageHeight = PokerPanel.rect.height* scaleFactor;
        Left.gameObject.SetActive(false);
        Right.gameObject.SetActive(false);
		RightNext.sprite= pokerBack;

        Vector3 globalsb = PokerPanel.transform.position + new Vector3(0, -pageHeight / 2);
        sb = transformPoint(globalsb);
		Vector3 globalebr = PokerPanel.transform.position + new Vector3(pageWidth, -pageHeight / 2);
        ebr = transformPoint(globalebr);
        Vector3 globalebl = PokerPanel.transform.position + new Vector3(-pageWidth, -pageHeight / 2);
        ebl = transformPoint(globalebl);
        Vector3 globalst = PokerPanel.transform.position + new Vector3(0, pageHeight / 2);
        st = transformPoint(globalst);
		Vector3 globalmr = PokerPanel.transform.position + new Vector3(pageWidth, 0);
		mr = transformPoint(globalmr);
		Vector3 globalmm = PokerPanel.transform.position + new Vector3(0, 0);
		mm = transformPoint(globalmm);
		Vector3 globalml = PokerPanel.transform.position + new Vector3(-pageWidth, 0);
		ml = transformPoint(globalml);
		Vector3 globaltm = PokerPanel.transform.position + new Vector3(0, pageHeight / 2);
		tm = transformPoint(globaltm);
		Vector3 globalbm = PokerPanel.transform.position + new Vector3(0, -pageHeight / 2);
		bm = transformPoint(globalbm);

        float scaledPageWidth = pageWidth / scaleFactor;
        float scaledPageHeight = pageHeight / scaleFactor;

		ClippingPlane.rectTransform.sizeDelta = new Vector2(scaledPageWidth*2,scaledPageHeight);
		Shadow.rectTransform.sizeDelta = new Vector2(scaledPageWidth*2,scaledPageWidth*2);
		NextPageClip.rectTransform.sizeDelta = new Vector2(scaledPageWidth*2,scaledPageHeight);

		Left.rectTransform.pivot = new Vector2(0.5f,0.5f);
		ClippingPlane.rectTransform.pivot = new Vector2(0.5f,0.5f);
		NextPageClip.rectTransform.pivot = new Vector2(0.5f,0.5f);
		RightNext.rectTransform.pivot = new Vector2(0.5f,0.5f);
		Right.rectTransform.pivot = new Vector2(0.5f,0.5f);
		Shadow.rectTransform.pivot = new Vector2(0.5f,0.5f);

		ClippingPlane.transform.position = PokerPanel.transform.position;
		NextPageClip.transform.position = PokerPanel.transform.position;
		RightNext.transform.position = PokerPanel.transform.position;
		Right.transform.position = PokerPanel.transform.position;
		Shadow.transform.position = PokerPanel.transform.position;
    }
    public Vector3 transformPoint(Vector3 global)
    {
        Vector2 localPos = PokerPanel.InverseTransformPoint(global);
        return localPos;
    }
    void Update()
    {
        if (pageDragging&&interactable)
        {
            UpdatePoker();
        }
    }
	public void UpdatePoker()
    {
        f= Vector3.Lerp(f,transformPoint( Input.mousePosition), Time.deltaTime * 10);
		if (mode == FlipMode.RightToLeft)
			UpdateBookRTLToPoint (f);
		else if (mode == FlipMode.LeftToRight)
			UpdateBookLTRToPoint (f);
		else if (mode == FlipMode.TopToBottom)
			UpdateBookTTBToPoint (f);
		else {
			UpdateBookBTTToPoint (f);
		}
    }

	public void UpdateBookBTTToPoint(Vector3 followLocation)
	{
		mode = FlipMode.BottomToTop;
		f = followLocation;
		Shadow.transform.SetParent(ClippingPlane.transform, true);
		Shadow.transform.localPosition = new Vector3(0, 0, 0);
		Shadow.transform.localEulerAngles = new Vector3(0, 0, -90);
		float moveTopLineY = mm.y + (mr.x - tm.y);
		Shadow.transform.localPosition = new Vector3(0, moveTopLineY, 0);

		Right.transform.SetParent(ClippingPlane.transform, true);
		Left.transform.SetParent(PokerPanel.transform, true);
		RightNext.transform.SetParent(PokerPanel.transform, true);
		c = f;
		//判断点是否超出屏幕
		if (c.y < bm.y) { //下边屏幕
			c.y = bm.y;
		} else {
			//上边屏幕
			if (c.y > tm.y*3.0f) {
				c.y = tm.y*3.0f;
			}
		}

		float ClippingPlaneY = mm.y + Mathf.Abs(bm.y - c.y)/2.0f;
		ClippingPlane.transform.position = PokerPanel.TransformPoint(new Vector2(mm.x,ClippingPlaneY));

		float RightY = bm.y*2.0f - (bm.y - c.y);
		Right.transform.position = PokerPanel.TransformPoint(new Vector2(mm.x,RightY));

		float nextPageClipY = bm.y*2.0f - (bm.y - c.y)/2.0f;
		NextPageClip.transform.position = PokerPanel.TransformPoint(new Vector2(mm.x,nextPageClipY));

		RightNext.transform.SetParent(NextPageClip.transform, true);
		Left.transform.SetParent(ClippingPlane.transform, true);
		Left.transform.SetAsFirstSibling();
		Shadow.rectTransform.SetParent(Right.rectTransform, true);
	}

	public void UpdateBookTTBToPoint(Vector3 followLocation)
	{
		mode = FlipMode.TopToBottom;
		f = followLocation;
		Shadow.transform.SetParent(ClippingPlane.transform, true);
		Shadow.transform.localEulerAngles = new Vector3(0, 0, 90);
		float moveTopLineY = mm.y - (mr.x - tm.y);
		Shadow.transform.localPosition = new Vector3(0, moveTopLineY, 0);

		Right.transform.SetParent(ClippingPlane.transform, true);
		Left.transform.SetParent(PokerPanel.transform, true);
		RightNext.transform.SetParent(PokerPanel.transform, true);
		c = f;
		//判断点是否超出屏幕
		if (c.y > tm.y) { //上边屏幕
			c.y = tm.y;
		} else {
			//下边屏幕
			if (c.y < 0 && Mathf.Abs (c.y) > (3.0f * tm.y))
				c.y = -(3.0f * tm.y);
		}

		float ClippingPlaneY = mm.y - (tm.y - c.y)/2.0f;
		ClippingPlane.transform.position = PokerPanel.TransformPoint(new Vector2(tm.x,ClippingPlaneY));

		float RightY = tm.y*2.0f - (tm.y - c.y);
		Right.transform.position = PokerPanel.TransformPoint(new Vector2(tm.x,RightY));

		float nextPageClipY = tm.y*2.0f - (tm.y - c.y)/2.0f;
		NextPageClip.transform.position = PokerPanel.TransformPoint(new Vector2(tm.x,nextPageClipY));

		RightNext.transform.SetParent(NextPageClip.transform, true);
		Left.transform.SetParent(ClippingPlane.transform, true);
		Left.transform.SetAsFirstSibling();
		Shadow.rectTransform.SetParent(Right.rectTransform, true);
	}

    public void UpdateBookLTRToPoint(Vector3 followLocation)
    {
        mode = FlipMode.LeftToRight;
		f = followLocation;
		Shadow.transform.SetParent(ClippingPlane.transform, true);
		Shadow.transform.localPosition = new Vector3(0, 0, 0);
		Shadow.transform.localEulerAngles = new Vector3(0, 0, 180);

		Right.transform.SetParent(ClippingPlane.transform, true);
		Left.transform.SetParent(PokerPanel.transform, true);
		RightNext.transform.SetParent(PokerPanel.transform, true);
		c = f;
		//判断点是否超出屏幕
		if (c.x < ml.x) { //左边屏幕
			c.x = ml.x;
		} else {
			//右边屏幕
			if (c.x > mr.x*3.0f) {
				c.x = mr.x*3.0f;
			}
		}

		float ClippingPlaneX = mm.x + Mathf.Abs(ml.x - c.x)/2.0f;
		ClippingPlane.transform.position = PokerPanel.TransformPoint(new Vector2(ClippingPlaneX,ml.y));

		float RightX = ml.x*2.0f - (ml.x - c.x);
		Right.transform.position = PokerPanel.TransformPoint(new Vector2(RightX,ml.y));

		float nextPageClipX = ml.x*2.0f - (ml.x - c.x)/2.0f;
		NextPageClip.transform.position = PokerPanel.TransformPoint(new Vector2(nextPageClipX,ml.y));

		RightNext.transform.SetParent(NextPageClip.transform, true);
		Left.transform.SetParent(ClippingPlane.transform, true);
		Left.transform.SetAsFirstSibling();
		Shadow.rectTransform.SetParent(Right.rectTransform, true);
    }

	public void DragPageToPoint(Vector3 point)
	{
		pageDragging = true;
		f = point;

		Left.gameObject.SetActive(true);
		Left.transform.position = RightNext.transform.position;

		Left.sprite = pokerBack;
		Left.transform.SetAsFirstSibling();

		Right.gameObject.SetActive(true);
		Right.transform.position = RightNext.transform.position;
		Right.sprite = pokerFront;
		RightNext.sprite = background;
		if (enableShadowEffect) Shadow.gameObject.SetActive(true);
	}

    public void UpdateBookRTLToPoint(Vector3 followLocation)
    {
		mode = FlipMode.RightToLeft;
		f = followLocation;
		Shadow.transform.SetParent(ClippingPlane.transform, true);
		Shadow.transform.localPosition = new Vector3(0, 0, 0);
		Shadow.transform.localEulerAngles = new Vector3(0, 0, 0);
		Right.transform.SetParent(ClippingPlane.transform, true);
		Left.transform.SetParent(PokerPanel.transform, true);
		RightNext.transform.SetParent(PokerPanel.transform, true);
		c = f;
		//判断点是否超出屏幕
		if (c.x > 0 && c.x > mr.x) { //右边屏幕
			c.x = mr.x;
		} else {
			//左边界
			if (c.x < 0 && Mathf.Abs (c.x) > (3.0f * mr.x))
				c.x = -(3.0f * mr.x);
		}

		float ClippingPlaneX = mm.x - (mr.x - c.x)/2.0f;
		ClippingPlane.transform.position = PokerPanel.TransformPoint(new Vector2(ClippingPlaneX,mr.y));

		float RightX = mr.x*2.0f - (mr.x - c.x);
		Right.transform.position = PokerPanel.TransformPoint(new Vector2(RightX,mr.y));

		float nextPageClipX = mr.x*2.0f - (mr.x - c.x)/2.0f;
		NextPageClip.transform.position = PokerPanel.TransformPoint(new Vector2(nextPageClipX,mr.y));

		RightNext.transform.SetParent(NextPageClip.transform, true);
		Left.transform.SetParent(ClippingPlane.transform, true);
		Left.transform.SetAsFirstSibling();
		Shadow.rectTransform.SetParent(Right.rectTransform, true);
    }

	//点击右边的热点
    public void OnMouseDragRightPage()
    {
		if (interactable) {
			mode = FlipMode.RightToLeft;
			DragPageToPoint(transformPoint(Input.mousePosition));
		}
    }
	//点击左边的热点
	public void OnMouseDragLeftPage()
	{
		if (interactable) {
			mode = FlipMode.LeftToRight;
			DragPageToPoint(transformPoint(Input.mousePosition));
		}
	}
	//点击上方的热点
	public void OnMouseDragTopPage()
	{
		if (interactable) {
			mode = FlipMode.TopToBottom;
			DragPageToPoint(transformPoint(Input.mousePosition));
		}
	}
	//点击下方的热点
	public void OnMouseDragBottomPage()
	{
		if (interactable) {
			mode = FlipMode.BottomToTop;
			DragPageToPoint(transformPoint(Input.mousePosition));
		}
	}

    public void OnMouseRelease()
    {
        if (interactable)
            ReleasePage();
    }

    public void ReleasePage()
    {
        if (pageDragging)
        {
            pageDragging = false;
            float distanceToLeft = Vector2.Distance(c, ebl);
            float distanceToRight = Vector2.Distance(c, ebr);
			float distanceToTop = Vector2.Distance (c, tm);
			float distanceToBottom = Vector2.Distance (c, bm);

			if (distanceToRight < distanceToLeft && mode == FlipMode.RightToLeft)
				TweenBack (ebr);
			else if (distanceToRight > distanceToLeft && mode == FlipMode.LeftToRight)
				TweenBack (ebl);
			else if (distanceToTop < distanceToBottom && mode == FlipMode.TopToBottom)
				TweenBack (tm);
			else if (distanceToTop > distanceToBottom && mode == FlipMode.BottomToTop)
				TweenBack (bm);
            else
                TweenForward();
        }
    }

    Coroutine currentCoroutine;
    public void TweenForward()
    {
		if (mode == FlipMode.RightToLeft) {
			currentCoroutine = StartCoroutine(TweenTo(ebl, 0.15f, () => { Flip(); }));
		} else if (mode == FlipMode.LeftToRight) {
			currentCoroutine = StartCoroutine(TweenTo(ebr, 0.15f, () => { Flip(); }));
		} else if (mode == FlipMode.TopToBottom) {
			currentCoroutine = StartCoroutine(TweenTo(bm, 0.15f, () => { Flip(); }));
		} else {
			currentCoroutine = StartCoroutine(TweenTo(tm, 0.15f, () => { Flip(); }));
		}
    }

    void Flip()
    {
        Left.transform.SetParent(PokerPanel.transform, true);
        Left.gameObject.SetActive(false);
        Right.gameObject.SetActive(false);
        Right.transform.SetParent(PokerPanel.transform, true);
        RightNext.transform.SetParent(PokerPanel.transform, true);
		RightNext.sprite= pokerFront;
        Shadow.gameObject.SetActive(false);
        if (OnFlip != null)
            OnFlip.Invoke();
    }

	public void TweenBack(Vector3 toLocation)
    {
		currentCoroutine = StartCoroutine(TweenTo(toLocation,0.15f,
			() =>
			{
				RightNext.sprite= pokerBack;
				RightNext.transform.SetParent(PokerPanel.transform);
				Right.transform.SetParent(PokerPanel.transform);

				Left.gameObject.SetActive(false);
				Right.gameObject.SetActive(false);
				pageDragging = false;
			}
		));
    }

    public IEnumerator TweenTo(Vector3 to, float duration, System.Action onFinish)
    {
        int steps = (int)(duration / 0.025f);
        Vector3 displacement = (to - f) / steps;
        for (int i = 0; i < steps-1; i++)
        {
			if (mode == FlipMode.RightToLeft) {
				UpdateBookRTLToPoint (f + displacement);
			} else if (mode == FlipMode.LeftToRight) {
				UpdateBookLTRToPoint (f + displacement);
			} else if (mode == FlipMode.TopToBottom) {
				UpdateBookTTBToPoint (f + displacement);
			} else {
				UpdateBookBTTToPoint (f + displacement);
			}
            yield return new WaitForSeconds(0.025f);
        }
        if (onFinish != null)
            onFinish();
    }
}

4、翻牌脚本挂载

翻牌脚本挂载

三、下载demo地址

https://download.csdn.net/download/weixin_45786770/15138018

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值