【unity3D】记忆翻牌小游戏教程

游戏介绍
  

游戏两两翻牌,一样则记成功一对;不一样,则两张都恢复初始状态。当所有卡牌配对成功后即获得胜利。
游戏流程:
1、玩家点击开始游戏后进入游戏;
2、系统初始化一组卡牌显示到界面上;
3、玩家点击卡牌将卡牌翻开;
4、系统检测到当翻开的卡牌为两张时进行评判,若相同则增加计数并判断是否达到指定数量,若不同则两张卡牌均恢复为原始状态。(当有两张卡牌被翻开时,需等待2秒后才能对其他卡牌进行点击,在2秒内对其他卡牌的点击都是无效的。)


开发过程


1、搭建界面,卡牌池使用自动布局(Grid Layout Group和Content Size Fitter组件)

创建一个3D模板工程后,在层次视图创建UI-Panel,在其属性视图中Add Component添加Gird Layout Group组件和Content Size Fitter组件。Gird Layout Group组件可对Panel的子元素自动进行排列布局,设置Padding下面的四个属性(元素距离四边的像素距离)、Cell Size(元素的宽高像素)、Spacing(元素间横向与纵向间隔)以及Constraint(行列约束)。Content Size Fitter组件用来约束当前Panel的尺寸。这两个组件一般搭配使用。

具体数值可根据后续添加图片尺寸进行设置,我的设置如下图二。

在panel下创建UI-Image,Ctrl+d进行复制,可发现它们会自动布局成为上面设置好的格式。

2、构建Card类,制作卡牌Prefab

Card类即翻牌游戏中的卡片,具有如下属性及方法:

属性:

(1)id:唯一标识id,利用同种卡牌id相同,不同卡牌id不同的原理对卡牌配对是否成功做出判断

(2)frontImg、backImg、successImg:卡牌的三种显示情况,依次代表翻开、未翻开、匹配成功状态。

(3)showImg:卡牌当前显示的图片,不同状态图片,都需要指定给卡牌的Image组件才能显示,所以我们需要声明Image类型的字段来获取Image组件对象。

(4)cardBtn:卡牌Button组件中的属性,获取当前组件中的属性来设置其是否能被点击。

方法:

(1)InitCard() :用于初始化卡片,将卡片的id、前景图像、背景图像和成功图像设置为指定的值。showImgcardBtn 通过外部调用获取组件属性值。

(2)SetFanPai() :用于将卡片翻开,显示卡片的前景图像,并禁用卡片按钮的交互性.

(3)SetSuccess() :用于将卡片标记为成功,显示卡片的成功图像。

(4)SetSuccess() :用于将卡片标记为成功,显示卡片的成功图像。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Card : MonoBehaviour
{
    public int ID
    {
        get
        {
            return id;
        }
    }
    // 卡牌需有唯一标识id,利用同种卡牌id相同,不同卡牌id不同的原理对卡牌配对是否成功做出判断
    private int id;
    // 卡牌会有三种显示情况:未被翻开状态,被翻开状态,配对成功状态
    private Sprite frontImg;
    private Sprite backImg;
    private Sprite successImg;
    // 不同状态图片,都需要指定给卡牌的Image组件才能显示
    private Image showImg;
    // 需要获取到卡牌Button组件中的属性来设置卡牌能否被点击
    public Button cardBtn;

    public void InitCard(int Id,Sprite front,Sprite back,Sprite success)
    {
        this.id = Id;
        this.frontImg = front;
        this.backImg = back;
        this.successImg = success;

        showImg = GetComponent<Image>();
        showImg.sprite = this.backImg;

        cardBtn = GetComponent<Button>();
    }
    //用于将卡片翻开,显示卡片的前景图像,并禁用卡片按钮的交互性
    public void SetFanPai()
    {
        showImg.sprite = frontImg;
        cardBtn.interactable = false;
    }
    //用于将卡片标记为成功,显示卡片的成功图像
    public void SetSuccess()
    {
        showImg.sprite = successImg;
    }
    //用于恢复卡片的状态,将卡片的图像恢复为背景图像,并启用卡片按钮的交互性
    public void SetRecover()
    {
        showImg.sprite = backImg;
        cardBtn.interactable = true;
    }
}
 我们在刚才疯狂创建的Image对象中,随便选一个,改名为CardPre,为其添加Button组件和Card脚本(其对象默认含有Image组件),将其Transition属性设置为None。这些做好后将其制作为Prefab,并将Panel下的子物体全部删除。

3、构建GameManager类

属性:

(1)winCardCouples:表示游戏胜利需要的卡牌对数,按照我们上述设计,这里制定为6;

(2)curCardCouples:记录当前已经匹配完成的卡牌对数;

(3)canPlayerClick:用来控制宏观点击,即根据策划,当两张牌均翻开时等待两秒才会出现结果,此时所有卡牌均不可以点击,所以这里设置此变量;

(4)Sprite类型的backImg和successImg两属性用来存放背面图和成功图;

(5)Sprite类型的数组FrontSprites,用来存放6种不同的卡牌图片;

(6)GameObject类型的卡牌实例列表集合CardObjs,此数组本质作用是过渡,即用6张图片来生成12张卡牌对象,将每个对象初始化好后存入当前数组,然后随机取出,做矫正设置后再指定给Panel作为子对象;

(7)Card类型的列表集合FaceCards,用来存放被翻开的卡牌;

(8)GameObject类型的Card;

(9)Transfrom类型的CardsView,用来存放Panel.

方法:

(1)在Start方法中设置初始化卡牌属性,并将其乱序添加到Panel下;

(2)添加CardOnClick方法,作为卡牌被点击的监听事件;

(3)添加JugdeTwoCards方法,此方法为协同程序的方法,用于判断两张牌是否一致。

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

public class Card_GameManager : MonoBehaviour
{
    //游戏胜利需要卡牌对数、当前匹配对数、控制点击变量
    private const int winCardCouples = 6;
    private int curCardCouples = 0;
    private bool canPlayerClick = true;
    //存放背面图和成功图
    public Sprite BackSprite;
    public Sprite SuccessSprite;
    //存放6种不同的卡牌图片
    public Sprite[] FrontSprites;
    //GameObject类型的卡牌实例列表集合CardObjs,此数组本质作用是过渡,
    //即用6张图片来生成12张卡牌对象,将每个对象初始化好后存入当前数组,
    //然后随机取出,做矫正设置后再指定给Panel作为子对象;
    public GameObject CardPre;
    //存放Panel
    public Transform CardsView;
    private List<GameObject> CardObjs;
    //存放被翻开的卡牌
    private List<Card> FaceCards;

    // Use this for initialization
    void Start()
    {

        CardObjs = new List<GameObject>();
        FaceCards = new List<Card>();

        //将12张卡牌制作完成后添加到CardObjs数组
        for (int i = 0; i < 6; i++)
        {
            Sprite FrontSprite = FrontSprites[i];
            for (int j = 0; j < 2; j++)
            {
                //实例化对象
                GameObject go = (GameObject)Instantiate(CardPre);
                //获取Card组件进行初始化,点击事件由游戏管理器统一处理
                //所以卡牌的点击事件的监听在管理器指定
                Card card = go.GetComponent<Card>();
                card.InitCard(i, FrontSprite, BackSprite, SuccessSprite);
                card.cardBtn.onClick.AddListener(() => CardOnClick(card));

                CardObjs.Add(go);
            }
        }

        while (CardObjs.Count > 0)
        {
            //取随机数,左闭右开区间
            int ran = Random.Range(0, CardObjs.Count);
            GameObject go = CardObjs[ran];
            //将对象指定给Panel作为子物体,这样就会被我们的组件自动布局
            go.transform.parent = CardsView;
            //local就表示相对于父物体的相对坐标系,此处做校正处理
            //有兴趣的同学可以把下面两句代码注释掉看看效果
            go.transform.localPosition = Vector3.zero;
            go.transform.localScale = Vector3.one;
            //从CardObjs列表中移除该索引指向对象,列表对象数量减少1个
            CardObjs.RemoveAt(ran);
        }
    }


    private void CardOnClick(Card card)
    {
        if (canPlayerClick)
        {
            //先判断是否可以点击,可点击则直接翻牌
            card.SetFanPai();
            //添加到比对数组中
            FaceCards.Add(card);
            //如果有两张牌了,则不可再点击,进入协同程序
            if (FaceCards.Count == 2)
            {
                canPlayerClick = false;
                StartCoroutine(JugdeTwoCards());
            }
        }
    }

    IEnumerator JugdeTwoCards()
    {
        //获取到两张卡牌对象
        Card card1 = FaceCards[0];
        Card card2 = FaceCards[1];
        //对ID进行比对
        if (card1.ID == card2.ID)
        {
            Debug.Log("Success......");
            //此时会在此处等待0.8秒后再执行下一条语句
            //协程不影响主程序的进行,这里可以做个小实验
            //将下面的0.8改成8秒,在Update中打印Time.time会发现不会有停顿的时候
            yield return new WaitForSeconds(0.8f);
            card1.SetSuccess();
            card2.SetSuccess();
            curCardCouples++;
            if (curCardCouples == winCardCouples)
            {
                //此处可以弹出游戏成功等字样的UI,同学们可以自由设定
                Debug.Log("Win!");
            }
        }
        else
        {
            Debug.Log("Failure......");
            //配对失败等待的时间要更长,因为要让玩家记忆更深刻
            yield return new WaitForSeconds(1.5f);
            card1.SetRecover();
            card2.SetRecover();
        }

        FaceCards = new List<Card>();
        canPlayerClick = true;
    }
}

新建空物体作为GameManager的对象,指定GameManager脚本,在属性面板设置其各项属性,如图所示。

卡牌图片可自主添加到资源,需要将Texture Type属性改为Sprite(2D and UI),这将把图片文件视为Sprite,才可在Front Sprites中使用这些图片。


游戏演示

3dunity入门小游戏制作——chiikawa记忆翻牌_哔哩哔哩_bilibili

参考博客:【Unity3D游戏教程】记忆翻牌游戏-CSDN博客

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值