Unity非常简单的翻牌游戏教程,纯UI实现

首先在场景中创建Canvas,加几个Button
在这里插入图片描述

为了排版方便,用了GridLayout在这里插入图片描述
每个Button的结构是这样的,你要为Button里面加四个Image,我这样弄是为了省事,少写脚本

这四个Image的名字也不能改,因为我后续是按照Image的名字进行检索的,也是为了省事……

在这里插入图片描述
在Fade上记得加个Button组件
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
简单说下这四个图片的作用:首先这是个翻牌游戏,游戏规则就是当玩家翻到两张一样的牌时计数板加一,计数到6个时游戏完成并加一分。这里面的Icon是放牌面的,就是让玩家知道这两张牌是一样的还是不一样的,起提示作用。Fade是牌背,玩家刚开始看到的就是12张牌背,点击牌背,牌背隐藏,出现牌面。True和False也起提示作用,当两张牌一样时,显示绿色的True,说明玩家选对了,不一样就显示红色的False。
然后你需要调整一下这四张Image的状态。
在这里插入图片描述
完事了把它复制12张,当然你也可以复制很多,保证是偶数就行了。

在这里插入图片描述
新建脚本CardGame,挂到Canvas或随便一个地方
在这里插入图片描述

新建三个Text,一个用于显示倒计时,一个用于显示计数,一个用于显示得分
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
新建一个Button,用于开始游戏
在这里插入图片描述
在网上找几张卡面,拖到Unity里(如果是3D项目,注意转换下格式),为了省事,我没新建文件夹,大家做游戏一定要注意项目的整洁哦
在这里插入图片描述

然后开始写CardGame脚本了
脚本的思路都在注释了,也没啥好说的,写好后在外面把找的图片赋给Sprite数组,按这一套下来应该就可以运行了,点击开始游戏即可开始翻牌
(之前的脚本忘记把引用加上,其实用vs自动纠错都可以解决的,现在的脚本已经不会报错了。)
(还有像我这种一个脚本写完翻牌游戏的,以后做项目或者做游戏尽量不要这样,这样写起来是省事,但是不利于项目维护。就这个游戏来说,起码应该写三个脚本,一个卡牌Model类,一个游戏控制类,一个UI显示类。)
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CardGame : MonoBehaviour
{
    /// <summary>
    /// 最大时间,超过该时间游戏失败
    /// </summary>
    public float maxTime=15;
    /// <summary>
    /// 用于计时
    /// </summary>
    private float m_time;
    /// <summary>
    /// 当前翻对了多少组牌
    /// </summary>
    private int Count;
    /// <summary>
    /// 需要翻对多少组牌才能胜利,简单来说就是所有牌数量除2
    /// </summary>
    private int maxCount;
    /// <summary>
    /// 得分
    /// </summary>
    private int Score;

    /// <summary>
    /// 储存牌面图片,注意你用了多少组牌,就得赋多少个牌面,比如教程里用了12个牌,就需要赋值6个Sprite
    /// </summary>
    public List<Sprite> sprites = new List<Sprite>();
    /// <summary>
    /// 储存所有牌的列表,
    /// </summary>
    private List<Transform> cardList = new List<Transform>();
    /// <summary>
    /// 用于初始化牌列表
    /// </summary>
    public Transform cardTrans;
    /// <summary>
    /// 编号列表,用于给每张卡进行编号
    /// </summary>
    private List<int> indexList = new List<int>();
    /// <summary>
    /// 是否开始游戏
    /// </summary>
    private bool isStart;
    /// <summary>
    /// 用于等待,主要是给玩家一点看牌的时间
    /// </summary>
    private bool isWaiting;
    /// <summary>
    /// 储存翻到的第一张牌
    /// </summary>
    private Transform FirstCard;
    /// <summary>
    /// 储存翻到的第二张牌
    /// </summary>
    private Transform NextCard;

    /// <summary>
    /// 开始游戏的按钮
    /// </summary>
    public Button startBtn;
    /// <summary>
    /// 倒计时的Text
    /// </summary>
    public Text timeText;
    //[SerializeField]
    //private Text timeText;
    //你也可以尝试这种写法,不过我个人觉得这种写法多此一举
    /// <summary>
    /// 计数Text
    /// </summary>
    public Text countText;
    /// <summary>
    /// 计分Text
    /// </summary>
    public Text scoreText;


    protected void Awake()
    {
        //初始化cardList
        for (int i = 0; i < cardTrans.childCount; i++)
        {
            //遍历cardTrans,把他的每个子物体都加到list里
            cardList.Add(cardTrans.GetChild(i));
            int id = i;
            //给卡背添加点击的监听,每张卡都绑定了一个Id
            cardTrans.GetChild(i).Find("Fade").GetComponent<Button>().onClick.AddListener(() => 
            { 
                CardClick(id); 
            });
        }
        for (int i = 0; i < cardList.Count / 2; i++)
        {
            for (int j = 0; j < 2; j++)
            {
                indexList.Add(i);//初始化编号列表,这里的结果是[0,0,1,1,2,2,3,3,4,4,5,5]
            }
        }

        maxCount = cardList.Count / 2;
        startBtn.onClick.AddListener(() =>
        {
            CardStart();
        });

    }
    protected void Update()
    {       
        //UI显示,我这里图省事写在了Update里,以后尽量别写Update里,可以用事件,或者把值封装下
        timeText.text = m_time.ToString("f2") + "秒";
        countText.text = "计数:" + Count;
        scoreText.text = "得分:"+Score;

        if (!isStart) //游戏没有进行中,不计时
            return;

        m_time -= Time.deltaTime;

        if (m_time <= 0)//时间用完了还没结束游戏,则游戏失败
            CardResult(false);
    }
    /// <summary>
    /// 开始游戏
    /// </summary>
    private void CardStart()
    {
        if (isStart)//如果游戏在进行中,则点击无效
            return;

        m_time = maxTime;
        Count = 0;//计数归0
        indexList = RandomList(indexList);//把编号随机排序,相当于洗牌

        for (int i = 0; i < cardList.Count; i++)
        {
            cardList[i].name = indexList[i] + "";//我这里直接用卡名作为判断依据,每两张卡如果卡名一样则为一组
            cardList[i].Find("Icon").GetComponent<Image>().sprite = sprites[indexList[i]];

            cardList[i].Find("Fade").gameObject.SetActive(true);
            cardList[i].Find("True").gameObject.SetActive(false);
            cardList[i].Find("False").gameObject.SetActive(false);
        }

        isStart = true;
    }
    /// <summary>
    /// List随机排序
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <returns></returns>
    public List<T> RandomList<T>(List<T> list)
    {
        var random = new System.Random();
        var newList = new List<T>();
        foreach (var item in list)
        {
            newList.Insert(random.Next(newList.Count), item);
        }
        return newList;
    }
    /// <summary>
    /// 点击卡背
    /// </summary>
    /// <param name="id"></param>
    private void CardClick(int id)
    {
        if (!isStart)  //游戏没有进行中,不能点
            return;
        if (isWaiting)
            return;

        Transform t = cardList[id];//找到这张卡
        t.Find("Fade").gameObject.SetActive(false);//隐藏卡背
        if (FirstCard == null) //翻第一张
            FirstCard = t;
        else if (NextCard == null)//翻第二张
        {
            NextCard = t;
            bool isSame;
            if (FirstCard.name == NextCard.name)//卡名相同,所以这两张卡是一样的,计数加1
            {
                FirstCard.Find("True").gameObject.SetActive(true);//用于提示玩家,你翻对了
                NextCard.Find("True").gameObject.SetActive(true);

                isSame = true;
                Count++;
            }
            else//我这里为了易懂,写的比较啰嗦
            {
                FirstCard.Find("False").gameObject.SetActive(true);//用于提示玩家,你翻错了
                NextCard.Find("False").gameObject.SetActive(true);

                isSame = false;
            }

            if (Count >= maxCount)//如果都翻对了,游戏胜利
            {
                CardResult(true);
            }
            else
            {
                StartCoroutine(WaitFlip(isSame));//还没翻完,开启一个等待的协程
            }
        }
    }
    /// <summary>
    /// 等待牌翻过来
    /// </summary>
    /// <param name="a">这两张牌是否一致</param>
    /// <returns></returns>
    IEnumerator WaitFlip(bool a)
    {
        isWaiting = true;
        yield return new WaitForSeconds(0.35f);//等待0.35秒

        //把用于提示的Image隐藏掉,这样看起来很啰嗦,其实应该给牌单独写个类,大家可以自己优化下
        FirstCard.Find("True").gameObject.SetActive(false);
        FirstCard.Find("False").gameObject.SetActive(false);
        NextCard.Find("True").gameObject.SetActive(false);
        NextCard.Find("False").gameObject.SetActive(false);

        if (!a)//没翻对,这两卡翻回去
        {
            FirstCard.Find("Fade").gameObject.SetActive(true);
            NextCard.Find("Fade").gameObject.SetActive(true);
        }
        //小重置一下,开启下一轮判断
        FirstCard = null;
        NextCard = null;
        isWaiting = false;
    }
    /// <summary>
    /// 游戏结果
    /// </summary>
    /// <param name="isSuccess">是否成果</param>
    private void CardResult(bool isSuccess)
    {
        StopAllCoroutines();//停止所有运行中的协程

        if (isSuccess)//游戏胜利,加一分
        {
            Score++;
        }
        else//游戏失败,减一分
        {
            Score--;
        }

        //重置变量
        FirstCard = null;
        NextCard = null;
        isStart = false;
        m_time = 0;
        Count = 0;
    }
}

效果预览
在这里插入图片描述
源文件链接
链接:https://pan.baidu.com/s/1KKIojoOxntCfVGBOJpQ9gg
提取码:jr7r

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值