• Unity3D_(游戏)卡牌04_游戏界面


     

     

     

    启动屏界面、主菜单界面、选关界面、游戏界面

    卡牌01_启动屏界面  传送门

    卡牌02_主菜单界面  传送门

    卡牌03_选关界面   传送门

    卡牌04_游戏界面     传送门

     选关界面效果

     

       (源代码在文章最下面,本篇有点长 (´・_・`) )

    实现过程

    选关界面

      添加Canvas画布自适应屏幕分辨率、设置背景图片

      添加显示关卡文本

      两个文本Text,LevelLabel文本显示固定关卡文字,leveltxt文本作为LevelLabel文本的子对象,动态显示关卡数

      创建三个按钮控件(主菜单、声音、游戏说明)

      

      使用Panel控件创建游戏区域

     

    卡牌预设体

      GameArea游戏区域下创建一个空物体对象,改名为Card,在Card下新建一个Image对象,作为卡牌背景

      每一个卡牌具有三种状态:未翻转状态、翻转开进行匹配状态、翻转开匹配完成状态

      卡牌未翻转状态bg(Image):

      翻转开进行匹配状态icon(Image)

      翻转开匹配完成状态mask(Image)

      将卡牌设置为预设体,绑定Card.cs脚本(绑定完Apply一下)

    制作棋盘

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    //用来管理游戏运行状态资源、整体性
    
    public class GameManager : MonoBehaviour {
        public GameObject carPreb;
        private LevelInfo levelInfo;    //本关卡数据信息
        int levelId;
    
        private void Awake()
        {
            levelInfo = DataMgr.Instance().levelInfo;
            levelId = DataMgr.Instance().levelId;
        }
    
    
        // Use this for initialization
        void Start () {
            InitBoard();
        }
        
        // Update is called once per frame
        void Update () {
            
        }
    
        //初始化棋盘
        void InitBoard()
        {
            //求游戏区域的宽高
            GameObject gameAreaObj = GameObject.Find("GameArea");
            RectTransform rectTrans = gameAreaObj.GetComponent<RectTransform>();
            float gameWidth = rectTrans.rect.width;
            float gameHeigh = rectTrans.rect.height;
            //获取关卡信息
            int row = levelInfo.row;
            int col = levelInfo.col;
            //根据关卡信息的行列信息,初始化位置
            float spacingW = gameWidth / col / 10;
            float spacingH = gameHeigh / row / 10;
            float cellW = (gameWidth - spacingW * (col + 1)) / col;
            float cellH = (gameHeigh - spacingH * (row + 1)) / row;
            float cellSize = Mathf.Min(cellW,cellH);        //最终求出正方形卡牌尺寸
    
            //求出水平和垂直方向实际空格间隙
            float spacingX = (gameWidth - cellSize * col) / (col + 1);
            float spacingY = (gameHeigh - cellSize * row) / (row + 1);
    
            int count = row * col;
    
            //创建所有卡牌
            for(int i=0;i<count;i++)
            {
                int row2 = i / col;
                int col2 = i % col;
                GameObject cardObj = Instantiate(carPreb,rectTrans);    //通过预制体创建卡牌对象
                cardObj.name = "Card" + i.ToString();
                RectTransform cardTrans = cardObj.GetComponent<RectTransform>();
                cardTrans.anchoredPosition = new Vector2(spacingX + (spacingX + cellSize) * col2, -spacingY - (spacingY + cellSize) * row2);
                cardTrans.sizeDelta = new Vector2(cellSize, cellSize);
            }
    
        }
    }
    GameManager.cs

      创建GameManager(GameObject),挂载游戏管理器脚本

      游戏管理器中添加卡牌预设体

    public GameObject carPreb;

      游戏管理器获得数据管理器中的关卡数据和关卡Id

        private void Awake()
        {
            levelInfo = DataMgr.Instance().levelInfo;
            levelId = DataMgr.Instance().levelId;
        }

      初始化棋盘

    void InitBoard()
        {
            //求游戏区域的宽高
            GameObject gameAreaObj = GameObject.Find("GameArea");
            RectTransform rectTrans = gameAreaObj.GetComponent<RectTransform>();
            float gameWidth = rectTrans.rect.width;
            float gameHeigh = rectTrans.rect.height;
            //获取关卡信息
            int row = levelInfo.row;
            int col = levelInfo.col;
            //根据关卡信息的行列信息,初始化位置
            float spacingW = gameWidth / col / 10;
            float spacingH = gameHeigh / row / 10;
            float cellW = (gameWidth - spacingW * (col + 1)) / col;
            float cellH = (gameHeigh - spacingH * (row + 1)) / row;
            float cellSize = Mathf.Min(cellW,cellH);        //最终求出正方形卡牌尺寸
    
            //求出水平和垂直方向实际空格间隙
            float spacingX = (gameWidth - cellSize * col) / (col + 1);
            float spacingY = (gameHeigh - cellSize * row) / (row + 1);
    
            int count = row * col;
    
            //创建所有卡牌
            for(int i=0;i<count;i++)
            {
                int row2 = i / col;
                int col2 = i % col;
                GameObject cardObj = Instantiate(carPreb,rectTrans);    //通过预制体创建卡牌对象
                cardObj.name = "Card" + i.ToString();
                RectTransform cardTrans = cardObj.GetComponent<RectTransform>();
                cardTrans.anchoredPosition = new Vector2(spacingX + (spacingX + cellSize) * col2, -spacingY - (spacingY + cellSize) * row2);
                cardTrans.sizeDelta = new Vector2(cellSize, cellSize);
            }
    
        }

    卡牌数据关联

      Card.cs中初始化卡牌三种状态,并在UI上关联卡牌的状态

    public class Card : MonoBehaviour {
    
        public GameObject bgObj;
        public Image iconImg;
        public GameObject maskObj;
    
        // Use this for initialization
        void Start () {
            
        }
        
        // Update is called once per frame
        void Update () {
            
        }
    }

      根据关卡定义中图片素材个数,初始化一个卡牌游戏索引下标的列表

            List<int> src_ids = new List<int>(levelInfo.sprites.Length);
            for(int i=0;i<src_ids.Count;i++)
            {
                src_ids.Add(i);
            }

      从src_ids的下标集合中,随机关卡中定义的count数出来

            int[] rand_ids = new int[levelInfo.count];  //卡牌随机的素材下标集合
            for(int i=0;i<levelInfo.count;i++)
            {
                int idx = Random.Range(0,src_ids.Count);
                rand_ids[i] = src_ids[idx];
                src_ids.Remove(idx);        //删除随机过的素材下标,下次循环从剩余的集合中随机
            }

      初始化卡牌id数组,我们卡牌id,可以用数组下标来表示,并且要保证卡牌成对出现

     List<int> cardIds = new List<int>(row * col);
            for(int i = 0; i < row * col / 2; i++)
            {
                if(i<levelInfo.count)
                {
                    cardIds.Add(rand_ids[i]);
                    cardIds.Add(rand_ids[i]);
                }
                else
                {
                    int idx = Random.Range(0, rand_ids.Length);
                    cardIds.Add(idx);
                    cardIds.Add(idx);
                }
            }

      对所有卡牌下标集合进行随机打乱

      for(int i=0;i<row*col;i++)
            {
                int idx = Random.Range(0,cardIds.Count);
                int temp = cardIds[i];        //随机一张牌,跟i对调,进而打乱顺序
                cardIds[i] = cardIds[idx];
                cardIds[idx] = temp;
            }

      Card.cs脚本中初始化卡牌

        public void Init(int id,Sprite spr,GameManager manager)
        {
            this.id = id;
            gameMgr = manager;
            //根据卡牌id,设置对应的图片素材
            iconImg.sprite = spr;
        }

    卡牌状态的实现

      点击游戏卡牌三种状态,游戏开始停留5s时间,卡牌全部翻转过去,点击卡牌,卡牌翻转过来

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    
    public class Card : MonoBehaviour,IPointerClickHandler {
    
        public GameObject bgObj;
        public Image iconImg;
        public GameObject maskObj;
    
        public enum STATE
        {
            Init,       //进入游戏时,展示几秒钟
            Closed,     //卡牌扣下状态
            Opened,     //点击一张卡牌时,翻开状态
            OK,        //匹配成功状态
            Fail        //匹配失败状态,短暂展示1秒钟,自动切换到扣下状态
        }
    
        int id;
        GameManager gameMgr;
        STATE m_state;
        float _timer;   
    
        // Use this for initialization
        void Start () {
            SwithState(STATE.Init);
    
        }
        
        // Update is called once per frame
        void Update () {
            _timer += Time.deltaTime;
    
            switch (m_state)
            {
                case STATE.Init:
                    {
                        if (_timer > 5)
                        {
                            SwithState(STATE.Closed);
                        }
                    }
                    break;
                case STATE.Closed:
                    break;
                case STATE.Opened:
                    break;
                case STATE.OK:
                    break;
                case STATE.Fail:
                    {
                        if (_timer > 1)
                        {
                            SwithState(STATE.Closed);
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    
        public void Init(int id,Sprite spr,GameManager manager)
        {
            this.id = id;
            gameMgr = manager;
            //根据卡牌id,设置对应的图片素材
            iconImg.sprite = spr;
        }
    
    
        //卡牌点击事件,系统自动调用
        public void OnPointerClick(PointerEventData eventData)
        {
            //卡牌切换到opened状态
            if (m_state == STATE.Closed)
            {
                SwithState(STATE.Opened);
            }
        }
    
        //卡牌状态切换
        void SwithState(STATE state)
        {
            _timer = 0;
            m_state = state;
            switch (state)
            {
                case STATE.Init:
                    iconImg.gameObject.SetActive(true);
                    maskObj.SetActive(false);
                    break;
                case STATE.Closed:
                    iconImg.gameObject.SetActive(false);
                    break;
                case STATE.Opened:
                    iconImg.gameObject.SetActive(true);
                    break;
                case STATE.OK:
                    maskObj.SetActive(true);
                    break;
                case STATE.Fail:
                    break;
                default:
                    break;
            }
        }
    }
    Card.cs

      枚举卡牌状态

        public enum STATE
        {
            Init,       //进入游戏时,展示几秒钟
            Closed,     //卡牌扣下状态
            Opened,     //点击一张卡牌时,翻开状态
            OK,        //匹配成功状态
            Fail        //匹配失败状态,短暂展示1秒钟,自动切换到扣下状态
        }

      管理卡牌状态切换

    void SwithState(STATE state)
        {
            _timer = 0;
            m_state = state;
            switch (state)
            {
                case STATE.Init:
                    iconImg.gameObject.SetActive(true);
                    maskObj.SetActive(false);
                    break;
                case STATE.Closed:
                    iconImg.gameObject.SetActive(false);
                    break;
                case STATE.Opened:
                    iconImg.gameObject.SetActive(true);
                    break;
                case STATE.OK:
                    maskObj.SetActive(true);
                    break;
                case STATE.Fail:
                    break;
                default:
                    break;
            }
        }

      卡牌点击事件,系统自动调用

    public void OnPointerClick(PointerEventData eventData)
        {
            //卡牌切换到opened状态
            if (m_state == STATE.Closed)
            {
                SwithState(STATE.Opened);
            }
        }
        void Start () {
            SwithState(STATE.Init);
    
        }
        
        // Update is called once per frame
        void Update () {
            _timer += Time.deltaTime;
    
            switch (m_state)
            {
                case STATE.Init:
                    {
                        if (_timer > 5)
                        {
                            SwithState(STATE.Closed);
                        }
                    }
                    break;
                case STATE.Closed:
                    break;
                case STATE.Opened:
                    break;
                case STATE.OK:
                    break;
                case STATE.Fail:
                    {
                        if (_timer > 1)
                        {
                            SwithState(STATE.Closed);
                        }
                    }
                    break;
                default:
                    break;
            }
        }

    核心算法实现

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    //用来管理游戏运行状态资源、整体性
    
    public class GameManager : MonoBehaviour {
        public GameObject carPreb;
        private LevelInfo levelInfo;    //本关卡数据信息
        int levelId;
        int open_card_num;          //翻开卡牌的数量
        int match_ok_num;           //匹配成功的卡牌数量
    
        Card selectCard1;           //保存翻开的第一张牌
        Card selectCard2;           //保存翻开的第二张牌
    
        private void Awake()
        {
            levelInfo = DataMgr.Instance().levelInfo;
            levelId = DataMgr.Instance().levelId;
        }
    
    
        // Use this for initialization
        void Start () {
            InitBoard();
        }
        
        // Update is called once per frame
        void Update () {
            
        }
    
        //初始化棋盘
        void InitBoard()
        {
            open_card_num = 0;
            match_ok_num = 0;
    
            //求游戏区域的宽高
            GameObject gameAreaObj = GameObject.Find("GameArea");
            RectTransform rectTrans = gameAreaObj.GetComponent<RectTransform>();
            float gameWidth = rectTrans.rect.width;
            float gameHeigh = rectTrans.rect.height;
            //获取关卡信息
            int row = levelInfo.row;
            int col = levelInfo.col;
            //根据关卡信息的行列信息,初始化位置
            float spacingW = gameWidth / col / 10;
            float spacingH = gameHeigh / row / 10;
            float cellW = (gameWidth - spacingW * (col + 1)) / col;
            float cellH = (gameHeigh - spacingH * (row + 1)) / row;
            float cellSize = Mathf.Min(cellW,cellH);        //最终求出正方形卡牌尺寸
    
            //求出水平和垂直方向实际空格间隙
            float spacingX = (gameWidth - cellSize * col) / (col + 1);
            float spacingY = (gameHeigh - cellSize * row) / (row + 1);
    
    
            //根据关卡定义中图片素材个数,初始化一个索引下标的列表
             List<int> src_ids = new List<int>(levelInfo.sprites.Length);
            for(int i=0;i< levelInfo.sprites.Length; i++)
            {
                src_ids.Add(i);
            }
    
            //从上面的下标集合中,随机关卡中定义的count数出来
            int[] rand_ids = new int[levelInfo.count];  //卡牌随机的素材下标集合
            for(int i=0;i<levelInfo.count;i++)
            {
                int idx = Random.Range(0,src_ids.Count);
                rand_ids[i] = src_ids[idx];
                src_ids.RemoveAt(idx);        //删除随机过的素材下标,下次循环从剩余的集合中随机
            }
    
            //初始化卡牌id数组,我们卡牌id,可以用数组下标来表示,并且要保证卡牌成对出现
            List<int> cardIds = new List<int>(row * col);
            for(int i = 0; i < row * col / 2; i++)
            {
                if(i<levelInfo.count)
                {
                    cardIds.Add(rand_ids[i]);
                    cardIds.Add(rand_ids[i]);
                }
                else
                {
                    int idx = Random.Range(0, rand_ids.Length);
                    cardIds.Add(idx);
                    cardIds.Add(idx);
                }
            }
    
            //对所有卡牌下标集合进行随机打乱
            for(int i=0;i<row*col;i++)
            {
                int idx = Random.Range(0,cardIds.Count);
                int temp = cardIds[i];        //随机一张牌,跟i对调,进而打乱顺序
                cardIds[i] = cardIds[idx];
                cardIds[idx] = temp;
            }
    
    
    
             int count = row * col;
    
            //创建所有卡牌
            for(int i=0;i<count;i++)
            {
                int row2 = i / col;
                int col2 = i % col;
                GameObject cardObj = Instantiate(carPreb,rectTrans);    //通过预制体创建卡牌对象
                cardObj.name = "Card" + i.ToString();
                RectTransform cardTrans = cardObj.GetComponent<RectTransform>();
                cardTrans.anchoredPosition = new Vector2(spacingX + (spacingX + cellSize) * col2, -spacingY - (spacingY + cellSize) * row2);
                cardTrans.sizeDelta = new Vector2(cellSize, cellSize);
                Card card = cardObj.GetComponent<Card>();
                card.Init(cardIds[i],levelInfo.sprites[cardIds[i]],this);
    
            }
    
        }
    
        //棋盘两个核心AI检测
        public void CheckCard(Card selectCard)
        {
            switch (open_card_num)
            {
                case 0:     //一张牌没翻开时
                    {
                        open_card_num = 1;
                        selectCard1 = selectCard;
                    }
                    break;
                case 1:     //已经翻开一张牌,此时的selectCard,是第二张牌
                    {
                        if(selectCard1 == selectCard)   //实际上不会调用
                        {
                            return  ;   
                        }
                        selectCard2 = selectCard;
                        if(selectCard1.id == selectCard2.id)     //匹配成功
                        {
                            selectCard1.MatchOK();
                            selectCard2.MatchOK();
                            match_ok_num++;
                            if (match_ok_num >= levelInfo.row * levelInfo.col / 2)
                            {
                                //全部匹配成功,比赛胜利结束,进行下一关
                         
                            }
                        }
                        else                                  //匹配失败
                        {
                            selectCard1.MatchFail();
                            selectCard2.MatchFail();
                        }
    
                        open_card_num = 0;
                        selectCard1 = null;
                        selectCard2 = null;
                    }
                    break;
                default:
                    break;
            }
        }
    
    }
    GameManager.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    
    public class Card : MonoBehaviour,IPointerClickHandler {
    
        public GameObject bgObj;
        public Image iconImg;
        public GameObject maskObj;
    
        public enum STATE
        {
            Init,       //进入游戏时,展示几秒钟
            Closed,     //卡牌扣下状态
            Opened,     //点击一张卡牌时,翻开状态
            OK,        //匹配成功状态
            Fail        //匹配失败状态,短暂展示1秒钟,自动切换到扣下状态
        }
    
        public int id;
        GameManager gameMgr;
        STATE m_state;
        float _timer;   
    
        // Use this for initialization
        void Start () {
            SwithState(STATE.Init);
    
        }
        
        // Update is called once per frame
        void Update () {
            _timer += Time.deltaTime;
    
            switch (m_state)
            {
                case STATE.Init:
                    {
                        if (_timer > 5)
                        {
                            SwithState(STATE.Closed);
                        }
                    }
                    break;
                case STATE.Closed:
                    break;
                case STATE.Opened:
                    break;
                case STATE.OK:
                    break;
                case STATE.Fail:
                    {
                        if (_timer > 1)
                        {
                            SwithState(STATE.Closed);
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    
        public void Init(int id,Sprite spr,GameManager manager)
        {
            this.id = id;
            gameMgr = manager;
            //根据卡牌id,设置对应的图片素材
            iconImg.sprite = spr;
        }
    
    
        //卡牌点击事件,系统自动调用
        public void OnPointerClick(PointerEventData eventData)
        {
            //卡牌切换到opened状态
            if (m_state == STATE.Closed)
            {
                SwithState(STATE.Opened);
                gameMgr.CheckCard(this);
            }
        }
    
        //卡牌状态切换
        void SwithState(STATE state)
        {
            _timer = 0;
            m_state = state;
            switch (state)
            {
                case STATE.Init:
                    iconImg.gameObject.SetActive(true);
                    maskObj.SetActive(false);
                    break;
                case STATE.Closed:
                    iconImg.gameObject.SetActive(false);
                    break;
                case STATE.Opened:
                    iconImg.gameObject.SetActive(true);
                    break;
                case STATE.OK:
                    maskObj.SetActive(true);
                    break;
                case STATE.Fail:
                    break;
                default:
                    break;
            }
        }
    
        public void MatchOK()
        {
            SwithState(STATE.OK);
        }
    
        public void MatchFail()
        {
            SwithState(STATE.Fail);
        }
    }
    Card.cs

      棋盘两个核心AI检测

      切换卡牌的状态

       public void MatchOK()
        {
            SwithState(STATE.OK);
        }
    
        public void MatchFail()
        {
            SwithState(STATE.Fail);
        }
     public void CheckCard(Card selectCard)
        {
            switch (open_card_num)
            {
                case 0:     //一张牌没翻开时
                    {
                        open_card_num = 1;
                        selectCard1 = selectCard;
                    }
                    break;
                case 1:     //已经翻开一张牌,此时的selectCard,是第二张牌
                    {
                        if(selectCard1 == selectCard)   //实际上不会调用
                        {
                            return  ;   
                        }
                        selectCard2 = selectCard;
                        if(selectCard1.id == selectCard2.id)     //匹配成功
                        {
                            selectCard1.MatchOK();
                            selectCard2.MatchOK();
                            match_ok_num++;
                            if (match_ok_num >= levelInfo.row * levelInfo.col / 2)
                            {
                                //全部匹配成功,比赛胜利结束,进行下一关
                         
                            }
                        }
                        else                                  //匹配失败
                        {
                            selectCard1.MatchFail();
                            selectCard2.MatchFail();
                        }
    
                        open_card_num = 0;
                        selectCard1 = null;
                        selectCard2 = null;
                    }
                    break;
                default:
                    break;
            }
        }

      防止两次同时点击一张卡牌

                        if(selectCard1 == selectCard)   //实际上不会调用
                        {
                            return  ;   
                        }

      不会调用原因在于

      卡牌点击事件,系统自动调用

        public void OnPointerClick(PointerEventData eventData)
        {
            //卡牌切换到opened状态
            if (m_state == STATE.Closed)
            {
                SwithState(STATE.Opened);
                gameMgr.CheckCard(this);
            }
        }

      卡牌必须要是Close状态才能翻转回来

            if (m_state == STATE.Closed)
            {
                SwithState(STATE.Opened);
                gameMgr.CheckCard(this);
            }

    比赛结束

       成功

        - 提示信息:恭喜过关

        - 【进入下一关】按钮

        - 返回主菜单

      

      失败

        - 提示信息:再接再厉

        - 【重玩本关】按钮

        - 返回主菜单

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    using UnityEngine.UI;
    
    public class PanelResult : MonoBehaviour {
    
        public GameObject winTxtObj;
        public GameObject loseTxtObj;
        public Button nextBtn;
        public Button retryBtn;
        public Button mainmenuBtn;
    
        GameManager gameMgr;
    
        private void Awake()
        {
            nextBtn.onClick.AddListener(()=> { onNextLevelBtn(); });
            retryBtn.onClick.AddListener(() => { OnRetryBtn(); });
            mainmenuBtn.onClick.AddListener(() => { OnMainMenuBtn(); });
    
            gameMgr = GameObject.Find("GameManager").GetComponent<GameManager>();
    
        }
    
        // Use this for initialization
        void Start () {
            
        }
        
        // Update is called once per frame
        void Update () {
            
        }
    
        //进行下一关
        void onNextLevelBtn()
        {
            gameMgr.NextLevel();
        }
    
        //再来一次
        void OnRetryBtn()
        {
            gameMgr.RetryLevel();
        }
    
        void OnMainMenuBtn()
        {
            SceneManager.LoadScene("MainMenu");
        }
    
        //设置比赛结果相关信息显示
        public void MatchResult(bool win)
        {
            winTxtObj.SetActive(win);
            loseTxtObj.SetActive(!win);
            nextBtn.gameObject.SetActive(win);
            retryBtn.gameObject.SetActive(!win);
        }
    }
    PanelResult.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    //用来管理游戏运行状态资源、整体性
    
    public class GameManager : MonoBehaviour {
        public GameObject carPreb;
        public PanelResult resultPanel;
    
        public enum STATE
        {
            Normal,
            Pause,
            About,
            Result
        }
    
        STATE m_state;
    
        private LevelInfo levelInfo;    //本关卡数据信息
        int levelId;
        int open_card_num;          //翻开卡牌的数量
        int match_ok_num;           //匹配成功的卡牌数量
    
        Card selectCard1;           //保存翻开的第一张牌
        Card selectCard2;           //保存翻开的第二张牌
        List<Card> list_cards = new List<Card>();      //保存所有卡牌引用
    
        private void Awake()
        {
            levelInfo = DataMgr.Instance().levelInfo;
            levelId = DataMgr.Instance().levelId;
        }
    
    
        // Use this for initialization
        void Start () {
    
            InitBoard();
        }
        
        // Update is called once per frame
        void Update () {
            
        }
    
        //初始化棋盘
        void InitBoard()
        {
            open_card_num = 0;
            match_ok_num = 0;
            SwitchState(STATE.Normal);
            ClearAllCard();
    
            //求游戏区域的宽高
            GameObject gameAreaObj = GameObject.Find("GameArea");
            RectTransform rectTrans = gameAreaObj.GetComponent<RectTransform>();
            float gameWidth = rectTrans.rect.width;
            float gameHeigh = rectTrans.rect.height;
            //获取关卡信息
            int row = levelInfo.row;
            int col = levelInfo.col;
            //根据关卡信息的行列信息,初始化位置
            float spacingW = gameWidth / col / 10;
            float spacingH = gameHeigh / row / 10;
            float cellW = (gameWidth - spacingW * (col + 1)) / col;
            float cellH = (gameHeigh - spacingH * (row + 1)) / row;
            float cellSize = Mathf.Min(cellW,cellH);        //最终求出正方形卡牌尺寸
    
            //求出水平和垂直方向实际空格间隙
            float spacingX = (gameWidth - cellSize * col) / (col + 1);
            float spacingY = (gameHeigh - cellSize * row) / (row + 1);
    
    
            //根据关卡定义中图片素材个数,初始化一个索引下标的列表
             List<int> src_ids = new List<int>(levelInfo.sprites.Length);
            for(int i=0;i< levelInfo.sprites.Length; i++)
            {
                src_ids.Add(i);
            }
    
            //从上面的下标集合中,随机关卡中定义的count数出来
            int[] rand_ids = new int[levelInfo.count];  //卡牌随机的素材下标集合
            for(int i=0;i<levelInfo.count;i++)
            {
                int idx = Random.Range(0,src_ids.Count);
                rand_ids[i] = src_ids[idx];
                src_ids.RemoveAt(idx);        //删除随机过的素材下标,下次循环从剩余的集合中随机
            }
    
            //初始化卡牌id数组,我们卡牌id,可以用数组下标来表示,并且要保证卡牌成对出现
            List<int> cardIds = new List<int>(row * col);
            for(int i = 0; i < row * col / 2; i++)
            {
                if(i<levelInfo.count)
                {
                    cardIds.Add(rand_ids[i]);
                    cardIds.Add(rand_ids[i]);
                }
                else
                {
                    int idx = Random.Range(0, rand_ids.Length);
                    cardIds.Add(idx);
                    cardIds.Add(idx);
                }
            }
    
            //对所有卡牌下标集合进行随机打乱
            for(int i=0;i<row*col;i++)
            {
                int idx = Random.Range(0,cardIds.Count);
                int temp = cardIds[i];        //随机一张牌,跟i对调,进而打乱顺序
                cardIds[i] = cardIds[idx];
                cardIds[idx] = temp;
            }
    
    
    
             int count = row * col;
    
            //创建所有卡牌
            for(int i=0;i<count;i++)
            {
                int row2 = i / col;
                int col2 = i % col;
                GameObject cardObj = Instantiate(carPreb,rectTrans);    //通过预制体创建卡牌对象
                cardObj.name = "Card" + i.ToString();
                RectTransform cardTrans = cardObj.GetComponent<RectTransform>();
                cardTrans.anchoredPosition = new Vector2(spacingX + (spacingX + cellSize) * col2, -spacingY - (spacingY + cellSize) * row2);
                cardTrans.sizeDelta = new Vector2(cellSize, cellSize);
                Card card = cardObj.GetComponent<Card>();
                card.Init(cardIds[i],levelInfo.sprites[cardIds[i]],this);
                list_cards.Add(card);
            }
    
        }
    
        //棋盘两个核心AI检测
        public void CheckCard(Card selectCard)
        {
            switch (open_card_num)
            {
                case 0:     //一张牌没翻开时
                    {
                        open_card_num = 1;
                        selectCard1 = selectCard;
                    }
                    break;
                case 1:     //已经翻开一张牌,此时的selectCard,是第二张牌
                    {
                        if(selectCard1 == selectCard)   //实际上不会调用
                        {
                            return  ;   
                        }
                         selectCard2 = selectCard;
                        if(selectCard1.id == selectCard2.id)     //匹配成功
                        {
                            selectCard1.MatchOK();
                            selectCard2.MatchOK();
                            match_ok_num++;
                            if (match_ok_num >= levelInfo.row * levelInfo.col / 2)
                            {
                                //全部匹配成功,比赛胜利结束,进行下一关
                                SwitchState(STATE.Result);
                                resultPanel.MatchResult(true);
                            }
                        }
                        else                                  //匹配失败
                        {
                            selectCard1.MatchFail();
                            selectCard2.MatchFail();
                           // SwitchState(STATE.Result);        解开有惊喜
                           //resultPanel.MatchResult(false);    解开有惊喜
                        }
    
                        open_card_num = 0;
                        selectCard1 = null;
                        selectCard2 = null;
                    }
                    break;
                default:
                    break;
            }
        }
    
        public void NextLevel()
        {
            int levelCount = DataMgr.Instance().levelData.levels.Length;
            if (levelId < levelCount)
            {
                levelId++;
                DataMgr.Instance().levelId = levelId;
                levelInfo = DataMgr.Instance().levelData.levels[levelId - 1];
            }
            InitBoard();
        }
    
        public void RetryLevel()
        {
            InitBoard();
        }
    
    
        //销毁所有卡牌,以便重新初始化
        void ClearAllCard()
        {
            if(list_cards.Count == 0)
            {
                return;
            }
            foreach(Card item in list_cards)
            {
                Destroy(item.gameObject);
            }
        }
    
        void SwitchState(STATE state)
        {
            m_state = state;
            switch (state)
            {
                case STATE.Normal:
                    resultPanel.gameObject.SetActive(false);
                    break;
                case STATE.Pause:
                    break;
                case STATE.About:
                    break;
                case STATE.Result:
                    resultPanel.gameObject.SetActive(true);
                    break;
                default:
                    break;
            }
        }
    
    }
    GameManager.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    
    public class Card : MonoBehaviour,IPointerClickHandler {
    
        public GameObject bgObj;
        public Image iconImg;
        public GameObject maskObj;
    
        public enum STATE
        {
            Init,       //进入游戏时,展示几秒钟
            Closed,     //卡牌扣下状态
            Opened,     //点击一张卡牌时,翻开状态
            OK,        //匹配成功状态
            Fail        //匹配失败状态,短暂展示1秒钟,自动切换到扣下状态
        }
    
        public int id;
        GameManager gameMgr;
        STATE m_state;
        float _timer;   
    
        // Use this for initialization
        void Start () {
            SwithState(STATE.Init);
    
        }
        
        // Update is called once per frame
        void Update () {
            _timer += Time.deltaTime;
    
            switch (m_state)
            {
                case STATE.Init:
                    {
                        if (_timer > 5)
                        {
                            SwithState(STATE.Closed);
                        }
                    }
                    break;
                case STATE.Closed:
                    break;
                case STATE.Opened:
                    break;
                case STATE.OK:
                    break;
                case STATE.Fail:
                    {
                        if (_timer > 1)
                        {
                            SwithState(STATE.Closed);
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    
        public void Init(int id,Sprite spr,GameManager manager)
        {
            this.id = id;
            gameMgr = manager;
            //根据卡牌id,设置对应的图片素材
            iconImg.sprite = spr;
        }
    
    
        //卡牌点击事件,系统自动调用
        public void OnPointerClick(PointerEventData eventData)
        {
            //卡牌切换到opened状态
            if (m_state == STATE.Closed)
            {
                SwithState(STATE.Opened);
                gameMgr.CheckCard(this);
            }
        }
    
        //卡牌状态切换
        void SwithState(STATE state)
        {
            _timer = 0;
            m_state = state;
            switch (state)
            {
                case STATE.Init:
                    iconImg.gameObject.SetActive(true);
                    maskObj.SetActive(false);
                    break;
                case STATE.Closed:
                    iconImg.gameObject.SetActive(false);
                    break;
                case STATE.Opened:
                    iconImg.gameObject.SetActive(true);
                    break;
                case STATE.OK:
                    maskObj.SetActive(true);
                    break;
                case STATE.Fail:
                    break;
                default:
                    break;
            }
        }
    
        public void MatchOK()
        {
            SwithState(STATE.OK);
        }
    
        public void MatchFail()
        {
            SwithState(STATE.Fail);
        }
    }
    Card.cs

      创建一个Panel,显示游戏结束时画面场景

      界面中添加三个按钮

      创建PanelResult脚本,挂载到ResultPanel控件上

      脚本中添加五个引用,关联Unity中控件(引用效率高)

    public class PanelResult : MonoBehaviour {
    
        public GameObject winTxtObj;
        public GameObject loseTxtObj;
        public Button nextBtnObj;
        public Button retryBtn;
        public Button mainmenuBtn;
    
    
        // Use this for initialization
        void Start () {
            
        }
        
        // Update is called once per frame
        void Update () {
            
        }
    }

      添加按钮点击事件

        private void Awake()
        {
            nextBtn.onClick.AddListener(()=> { onNextLevelBtn(); });
            retryBtn.onClick.AddListener(() => { OnRetryBtn(); });
            mainmenuBtn.onClick.AddListener(() => { OnMainMenuBtn(); });
    
            gameMgr = GameObject.Find("GameManager").GetComponent<GameManager>();
    
        }
    
     //进行下一关
        void onNextLevelBtn()
        {
            gameMgr.NextLevel();
        }
    
        //再来一次
        void OnRetryBtn()
        {
            gameMgr.RetryLevel();
        }
    
        void OnMainMenuBtn()
        {
            SceneManager.LoadScene("MainMenu");
        }
    
        //设置比赛结果相关信息显示
        public void MatchResult(bool win)
        {
            winTxtObj.SetActive(win);
            loseTxtObj.SetActive(!win);
            nextBtn.gameObject.SetActive(win);
            retryBtn.gameObject.SetActive(!win);
        }

    比赛倒计时

      (设置游戏时间为8s为了方便检测游戏结束后重玩和进入主菜单界面效果)  

      添加四张Image图片放置数字,不断对图片进行刷新实现游戏倒计时

       (时钟与分钟之间的":"用文本来表示  GRB:E2F43F)

      GameManager.cs中添加四张图片、十个数字的引用、时间倒计时常量、时间计时器

        public Image minule1Img;
        public Image minule2Img;
        public Image second1Img;
        public Image second4Img;
        public Sprite[] num_sprites;   //  数字sprite的引用
    
    
        public readonly int MATCH_TIMA = 180;   //时间倒计时

       用来更新比赛倒计时显示

     void UpdateTimeDisplay(int timeRemain)
        {
            System.TimeSpan tspan = new System.TimeSpan(0,0,timeRemain);
            string timeStr = string.Format("{0:00}:{1:00}",tspan.Minutes,tspan.Seconds);
            minule1Img.sprite = num_sprites[int.Parse(timeStr.Substring(0, 1))];    //把第一位字符转换成整数
            minule2Img.sprite = num_sprites[int.Parse(timeStr.Substring(1, 1))];    //把第二位字符转换成整数
            second1Img.sprite = num_sprites[int.Parse(timeStr.Substring(3, 1))];    //把第四位字符转换成整数   跳过的第三位是":"符号
             second2Img.sprite = num_sprites[int.Parse(timeStr.Substring(4, 1))];    //把第五位字符转换成整数
        }

    比赛其他界面交互

       动态改变关卡分数

        void Start () {
    
            InitBoard();
            GameObject.Find("levelTxt").GetComponent<Text>().text = levelId.ToString();
        }

      主菜单按钮上添加脚本

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.SceneManagement;
    
    public class PanelPause : MonoBehaviour {
    
        public void Awake()
        {
            GameObject.Find("ContinueBtn").GetComponent<Button>().onClick.AddListener(()=> { OnContinueBtn(); });
            GameObject.Find("MainMenuBtn").GetComponent<Button>().onClick.AddListener(() => { OnBackMainMenu(); });
        }
    
        void OnContinueBtn()
        {
            gameObject.SetActive(false);
        }
        
        void OnBackMainMenu()
        {
            SceneManager.LoadScene("MainMenu");
        }
    }
    PanelPause.cs

      注册按钮控件

        public void Awake()
        {
            GameObject.Find("ContinueBtn").GetComponent<Button>().onClick.AddListener(()=> { OnContinueBtn(); });
            GameObject.Find("MainMenuBtn").GetComponent<Button>().onClick.AddListener(() => { OnBackMainMenu(); });
        }

      按钮点击事件

        void OnContinueBtn()
        {
            gameObject.SetActive(false);
        }
        
        void OnBackMainMenu()
        {
            SceneManager.LoadScene("MainMenu");
        }

      提示信息界面

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PanelAbout : MonoBehaviour {
    
        // Use this for initialization
        void Start () {
            
        }
        
        // Update is called once per frame
        void Update () {
            if (Input.anyKeyDown)
            {
                gameObject.SetActive(false);
            }
        }
    }
    PanelAbout.cs

      点击界面,提示面板不可见

        void Update () {
            if (Input.anyKeyDown)
            {
                gameObject.SetActive(false);
            }
        }

    记录保存于关卡解锁

      设置比赛结果相关信息显示

     public void MatchResult(bool win)
        {
            winTxtObj.SetActive(win);
            loseTxtObj.SetActive(!win);
            nextBtn.gameObject.SetActive(win);
            retryBtn.gameObject.SetActive(!win);
    
            if (win)
            {
                string level_key = System.Enum.GetName(typeof(THEME_ID), DataMgr.Instance().themeId)+"_level";    //主题名+下划线作为值键
                PlayerPrefs.SetInt(level_key,gameMgr.levelId+1);  //保存当前解锁的关卡编号,实际是当前关卡的下一关
    
            }
        }

      LevelManager.cs关卡初始化

        public int unlock_levelID=1;
    
        public void Awake()
        {
            levelPanelCellPreb = Resources.Load<GameObject>("Prefabs/SelectLevel/LevelPanelCell");
            levelItemCellPreb = Resources.Load("Prefabs/SelectLevel/LevelItemCell") as GameObject;
            levelDescTxt = GameObject.Find("LevelDesc/text").GetComponent<Text>();
    
            GameObject.Find("BackMainMenu").GetComponent<Button>().onClick.AddListener(()=> { OnBackMainMenuBtn(); });
    
            DataMgr.Instance().InitLevelData(DataMgr.Instance().themeId);
            totalCount = DataMgr.Instance().levelData.levels.Length;    //根据关卡数据表的个数,动态设置单元数量
    
    
            string level_key = System.Enum.GetName(typeof(THEME_ID), DataMgr.Instance().themeId) + "_level";
            if(PlayerPrefs.HasKey(level_key))
            {
                unlock_levelID = PlayerPrefs.GetInt(level_key);
            }
            else
            {
                unlock_levelID = 1;         //如果是第一次玩,还没有记录过,给默认解锁第一关
            }
            
        }

    Android发布设置

      Android横向设置

      第一第二个选择按钮

        设置Android从上到下和从下到上竖屏

      取消勾选

      PC版没那么多要求~

    游戏源代码

    程序结构

    data文件夹

      

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class DataMgr {
        private static DataMgr ins = null;
    
        public THEME_ID themeId;
    
        //某一主题所有关卡数据
        public LevelData levelData;
        public int levelId;             //进入游戏前,保存当前选择的关卡id
        public LevelInfo levelInfo;     //当前关卡信息
    
        private DataMgr()
        {
            //将构造函数设置为私有,这样避免外部创建类的实例,只能通过Instance()来获取数据管理类的实例
        }
    
        public static DataMgr Instance()
        {
            if(ins == null)
            { 
                ins = new DataMgr();
            }
            return ins;
        }
    
        public LevelData InitLevelData(THEME_ID id)
        {
            levelData = null;
            switch (id)
            {
                case THEME_ID.Logo:
                    levelData = Resources.Load<LevelData>("Prefabs/data/LevelDataLogo");
                    break;
                case THEME_ID.Student:
                    levelData = Resources.Load<LevelData>("Prefabs/data/LevelDataStudent");
                    break;
                default:
                    levelData = Resources.Load<LevelData>("Prefabs/data/LevelDataLogo");
                    break;
            }
            return levelData; 
        }
    }
    DataMgr.class (数据管理类)
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    //某一关数据结构
    [System.Serializable]
    public class LevelInfo
    {
        public int id;      //关卡id
        public int row;
        public int col;
        public int count;   //本关从指定集合中随机几个素材
        public string desc;     //关卡简要描述
        public Sprite[] sprites;
    }
    
    public class LevelData : MonoBehaviour {
    
        public LevelInfo[] levels;
    }
    LevelData.cs (某一主题关卡数据结构)

    gameplay文件夹

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    
    public class Card : MonoBehaviour,IPointerClickHandler {
    
        public GameObject bgObj;
        public Image iconImg;
        public GameObject maskObj;
    
        public enum STATE
        {
            Init,       //进入游戏时,展示几秒钟
            Closed,     //卡牌扣下状态
            Opened,     //点击一张卡牌时,翻开状态
            OK,        //匹配成功状态
            Fail        //匹配失败状态,短暂展示1秒钟,自动切换到扣下状态
        }
    
        public int id;
        GameManager gameMgr;
        STATE m_state;
        float _timer;   
    
        // Use this for initialization
        void Start () {
            SwithState(STATE.Init);
    
        }
        
        // Update is called once per frame
        void Update () {
    
            if(gameMgr.m_state != GameManager.STATE.Normal)
            {
                return;
            }
    
            _timer += Time.deltaTime;
    
            switch (m_state)
            {
                case STATE.Init:
                    {
                        if (_timer > 5)
                        {
                            SwithState(STATE.Closed);
                        }
                    }
                    break;
                case STATE.Closed:
                    break;
                case STATE.Opened:
                    break;
                case STATE.OK:
                    break;
                case STATE.Fail:
                    {
                        if (_timer > 1)
                        {
                            SwithState(STATE.Closed);
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    
        public void Init(int id,Sprite spr,GameManager manager)
        {
            this.id = id;
            gameMgr = manager;
            //根据卡牌id,设置对应的图片素材
            iconImg.sprite = spr;
        }
    
    
        //卡牌点击事件,系统自动调用
        public void OnPointerClick(PointerEventData eventData)
        {
            //卡牌切换到opened状态
            if (m_state == STATE.Closed)
            {
                SwithState(STATE.Opened);
                gameMgr.CheckCard(this);
            }
        }
    
        //卡牌状态切换
        void SwithState(STATE state)
        {
            _timer = 0;
            m_state = state;
            switch (state)
            {
                case STATE.Init:
                    iconImg.gameObject.SetActive(true);
                    maskObj.SetActive(false);
                    break;
                case STATE.Closed:
                    iconImg.gameObject.SetActive(false);
                    break;
                case STATE.Opened:
                    iconImg.gameObject.SetActive(true);
                    break;
                case STATE.OK:
                    maskObj.SetActive(true);
                    break;
                case STATE.Fail:
                    break;
                default:
                    break;
            }
        }
    
        public void MatchOK()
        {
            SwithState(STATE.OK);
        }
    
        public void MatchFail()
        {
            SwithState(STATE.Fail);
        }
    }
    Card.cs (管理单张游戏卡牌)
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    //用来管理游戏运行状态资源、整体性
    
    public class GameManager : MonoBehaviour {
        public GameObject carPreb;
        public PanelResult resultPanel;
    
        public GameObject pausePanel;
        public GameObject aboutPanel;
    
        public Image minule1Img;
        public Image minule2Img;
        public Image second1Img;
        public Image second2Img;
        public Sprite[] num_sprites;   //  数字sprite的引用
    
    
        public readonly int MATCH_TIMA = 75;   //时间倒计时
    
        public enum STATE
        {
            Normal,
            Pause,
            About,
            Result
        }
    
        public STATE m_state;
    
        private LevelInfo levelInfo;    //本关卡数据信息
    
        [HideInInspector]
        public int levelId;
        int open_card_num;          //翻开卡牌的数量
        int match_ok_num;           //匹配成功的卡牌数量
    
        Card selectCard1;           //保存翻开的第一张牌
        Card selectCard2;           //保存翻开的第二张牌
        List<Card> list_cards = new List<Card>();      //保存所有卡牌引用
        float _timer;
    
    
        private void Awake()
        {
            levelInfo = DataMgr.Instance().levelInfo;
            levelId = DataMgr.Instance().levelId;
    
            GameObject.Find("PanseBtn").GetComponent<Button>().onClick.AddListener(() => { OnPauseBtn(); });
            GameObject.Find("AudioBtn").GetComponent<Button>().onClick.AddListener(() => { OnAudioBtn(); });
            GameObject.Find("AboutBtn").GetComponent<Button>().onClick.AddListener(() => { OnAboutBtn(); });
        }
    
    
        // Use this for initialization
        void Start() {
    
            InitBoard();
            GameObject.Find("levelTxt").GetComponent<Text>().text = levelId.ToString();
        }
    
        // Update is called once per frame
        void Update() {
    
            switch (m_state)
            {
                case STATE.Normal:
                    {
                        _timer += Time.deltaTime;
                        int timeRemain = (int)(MATCH_TIMA - _timer);
    
                        if (timeRemain < 0)     //比赛失败
                        {
                            SwitchState(STATE.Result);
                            resultPanel.MatchResult(false);
                        }
                        else
                        {
                            UpdateTimeDisplay(timeRemain);      //更新比赛倒计时
                        }
                    }
                    break;
                case STATE.Pause:
                    break;
                case STATE.About:
                    break;
                case STATE.Result:
                    break;
                default:
                    break;
            }
    
        }
    
        //初始化棋盘
        void InitBoard()
        {
            open_card_num = 0;
            match_ok_num = 0;
            SwitchState(STATE.Normal);
            ClearAllCard();
    
            //求游戏区域的宽高
            GameObject gameAreaObj = GameObject.Find("GameArea");
            RectTransform rectTrans = gameAreaObj.GetComponent<RectTransform>();
            float gameWidth = rectTrans.rect.width;
            float gameHeigh = rectTrans.rect.height;
            //获取关卡信息
            int row = levelInfo.row;
            int col = levelInfo.col;
            //根据关卡信息的行列信息,初始化位置
            float spacingW = gameWidth / col / 10;
            float spacingH = gameHeigh / row / 10;
            float cellW = (gameWidth - spacingW * (col + 1)) / col;
            float cellH = (gameHeigh - spacingH * (row + 1)) / row;
            float cellSize = Mathf.Min(cellW, cellH);        //最终求出正方形卡牌尺寸
    
            //求出水平和垂直方向实际空格间隙
            float spacingX = (gameWidth - cellSize * col) / (col + 1);
            float spacingY = (gameHeigh - cellSize * row) / (row + 1);
    
    
            //根据关卡定义中图片素材个数,初始化一个索引下标的列表
            List<int> src_ids = new List<int>(levelInfo.sprites.Length);
            for (int i = 0; i < levelInfo.sprites.Length; i++)
            {
                src_ids.Add(i);
            }
    
            //从上面的下标集合中,随机关卡中定义的count数出来
            int[] rand_ids = new int[levelInfo.count];  //卡牌随机的素材下标集合
            for (int i = 0; i < levelInfo.count; i++)
            {
                int idx = Random.Range(0, src_ids.Count);
                rand_ids[i] = src_ids[idx];
                src_ids.RemoveAt(idx);        //删除随机过的素材下标,下次循环从剩余的集合中随机
            }
    
            //初始化卡牌id数组,我们卡牌id,可以用数组下标来表示,并且要保证卡牌成对出现
            List<int> cardIds = new List<int>(row * col);
            for (int i = 0; i < row * col / 2; i++)
            {
                if (i < levelInfo.count)
                {
                    cardIds.Add(rand_ids[i]);
                    cardIds.Add(rand_ids[i]);
                }
                else
                {
                    int idx = Random.Range(0, rand_ids.Length);
                    cardIds.Add(idx);
                    cardIds.Add(idx);
                }
            }
    
            //对所有卡牌下标集合进行随机打乱
            for (int i = 0; i < row * col; i++)
            {
                int idx = Random.Range(0, cardIds.Count);
                int temp = cardIds[i];        //随机一张牌,跟i对调,进而打乱顺序
                cardIds[i] = cardIds[idx];
                cardIds[idx] = temp;
            }
    
    
    
            int count = row * col;
    
            //创建所有卡牌
            for (int i = 0; i < count; i++)
            {
                int row2 = i / col;
                int col2 = i % col;
                GameObject cardObj = Instantiate(carPreb, rectTrans);    //通过预制体创建卡牌对象
                cardObj.name = "Card" + i.ToString();
                RectTransform cardTrans = cardObj.GetComponent<RectTransform>();
                cardTrans.anchoredPosition = new Vector2(spacingX + (spacingX + cellSize) * col2, -spacingY - (spacingY + cellSize) * row2);
                cardTrans.sizeDelta = new Vector2(cellSize, cellSize);
                Card card = cardObj.GetComponent<Card>();
                card.Init(cardIds[i], levelInfo.sprites[cardIds[i]], this);
                list_cards.Add(card);
            }
    
        }
    
        //棋盘两个核心AI检测
        public void CheckCard(Card selectCard)
        {
            switch (open_card_num)
            {
                case 0:     //一张牌没翻开时
                    {
                        open_card_num = 1;
                        selectCard1 = selectCard;
                    }
                    break;
                case 1:     //已经翻开一张牌,此时的selectCard,是第二张牌
                    {
                        if (selectCard1 == selectCard)   //实际上不会调用
                        {
                            return;
                        }
                        selectCard2 = selectCard;
                        if (selectCard1.id == selectCard2.id)     //匹配成功
                        {
                            selectCard1.MatchOK();
                            selectCard2.MatchOK();
                            match_ok_num++;
                            if (match_ok_num >= levelInfo.row * levelInfo.col / 2)
                            {
                                //全部匹配成功,比赛胜利结束,进行下一关
                                SwitchState(STATE.Result);
                                resultPanel.MatchResult(true);
                            }
                        }
                        else                                  //匹配失败
                        {
                            selectCard1.MatchFail();
                            selectCard2.MatchFail();
                            // SwitchState(STATE.Result);        解开有惊喜
                            //resultPanel.MatchResult(false);    解开有惊喜
                        }
    
                        open_card_num = 0;
                        selectCard1 = null;
                        selectCard2 = null;
                    }
                    break;
                default:
                    break;
            }
        }
    
        public void NextLevel()
        {
            int levelCount = DataMgr.Instance().levelData.levels.Length;
            if (levelId < levelCount)
            {
                levelId++;
                DataMgr.Instance().levelId = levelId;
                levelInfo = DataMgr.Instance().levelData.levels[levelId - 1];
            }
            InitBoard();
        }
    
        public void RetryLevel()
        {
            InitBoard();
        }
    
    
        //销毁所有卡牌,以便重新初始化
        void ClearAllCard()
        {
            if (list_cards.Count == 0)
            {
                return;
            }
            foreach (Card item in list_cards)
            {
                Destroy(item.gameObject);
            }
        }
    
        void SwitchState(STATE state)
        {
            m_state = state;
            _timer = 0;
            switch (state)
            {
                case STATE.Normal:
                    resultPanel.gameObject.SetActive(false);
                    pausePanel.SetActive(false);
                    aboutPanel.SetActive(false);
                    break;
                case STATE.Pause:
                    pausePanel.SetActive(true);
                    break;
                case STATE.About:
                    aboutPanel.SetActive(true);
                    break;
                case STATE.Result:
                    resultPanel.gameObject.SetActive(true);
                    break;
                default:
                    break;
            }
        }
    
        //用来更新比赛倒计时显示
        void UpdateTimeDisplay(int timeRemain)
        {
            System.TimeSpan tspan = new System.TimeSpan(0, 0, timeRemain);
            string timeStr = string.Format("{0:00}:{1:00}", tspan.Minutes, tspan.Seconds);
            minule1Img.sprite = num_sprites[int.Parse(timeStr.Substring(0, 1))];    //把第一位字符转换成整数
            minule2Img.sprite = num_sprites[int.Parse(timeStr.Substring(1, 1))];    //把第二位字符转换成整数
            second1Img.sprite = num_sprites[int.Parse(timeStr.Substring(3, 1))];    //把第四位字符转换成整数   跳过的第三位是":"符号
            second2Img.sprite = num_sprites[int.Parse(timeStr.Substring(4, 1))];    //把第五位字符转换成整数
        }
    
        //暂停按钮,弹出暂停界面panel
        void OnPauseBtn()
        {
            SwitchState(STATE.Pause);
        }
    
        void OnAudioBtn()
        {
            //声音开关
        }
    
        void OnAboutBtn()
        {
            SwitchState(STATE.About);
        }
    }
    GameManager.cs (游戏管理器)

    Panel文件夹

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PanelAbout : MonoBehaviour {
    
        // Use this for initialization
        void Start () {
            
        }
        
        // Update is called once per frame
        void Update () {
            if (Input.anyKeyDown)
            {
                gameObject.SetActive(false);
            }
        }
    }
    PanelAbout.cs (管理游戏状态下信息提示)
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.SceneManagement;
    
    public class PanelPause : MonoBehaviour {
    
        public void Awake()
        {
            GameObject.Find("ContinueBtn").GetComponent<Button>().onClick.AddListener(()=> { OnContinueBtn(); });
            GameObject.Find("MainMenuBtn").GetComponent<Button>().onClick.AddListener(() => { OnBackMainMenu(); });
        }
    
        void OnContinueBtn()
        {
            gameObject.SetActive(false);
        }
        
        void OnBackMainMenu()
        {
            SceneManager.LoadScene("MainMenu");
        }
    }
    PanelPause.cs (管理游戏状态下主菜单)
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    using UnityEngine.UI;
    
    public class PanelResult : MonoBehaviour {
    
        public GameObject winTxtObj;
        public GameObject loseTxtObj;
        public Button nextBtn;
        public Button retryBtn;
        public Button mainmenuBtn;
    
        GameManager gameMgr;
    
        private void Awake()
        {
    
            nextBtn.onClick.AddListener(()=> { onNextLevelBtn(); });
            retryBtn.onClick.AddListener(() => { OnRetryBtn(); });
            mainmenuBtn.onClick.AddListener(() => { OnMainMenuBtn(); });
    
            gameMgr = GameObject.Find("GameManager").GetComponent<GameManager>();
    
        }
    
        // Use this for initialization
        void Start () {
            
        }
        
        // Update is called once per frame
        void Update () {
            
        }
    
        //进行下一关
        void onNextLevelBtn()
        {
            gameMgr.NextLevel();
        }
    
        //再来一次
        void OnRetryBtn()
        {
            gameMgr.RetryLevel();
        }
    
        void OnMainMenuBtn()
        {
            SceneManager.LoadScene("MainMenu");
        }
    
        //设置比赛结果相关信息显示
        public void MatchResult(bool win)
        {
            winTxtObj.SetActive(win);
            loseTxtObj.SetActive(!win);
            nextBtn.gameObject.SetActive(win);
            retryBtn.gameObject.SetActive(!win);
    
            if (win)
            {
                string level_key = System.Enum.GetName(typeof(THEME_ID), DataMgr.Instance().themeId)+"_level";    //主题名+下划线作为值键
                PlayerPrefs.SetInt(level_key,gameMgr.levelId+1);  //保存当前解锁的关卡编号,实际是当前关卡的下一关
    
            }
        }
    }
    PanelResult.cs (设置比赛结果相关信息显示)

    scene文件夹

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    using UnityEngine.UI;
    
    
    public enum THEME_ID
    {
        Logo,
        Student
    }
    
    public class Scene_MainMenu : MonoBehaviour {
    
        // Use this for initialization
        void Start () {
            GameObject.Find("LogoBtn").GetComponent<Button>().onClick.AddListener(()=>{ OnClickThemeBtn(THEME_ID.Logo); });
            GameObject.Find("StudentBtn").GetComponent<Button>().onClick.AddListener(() => { OnClickThemeBtn(THEME_ID.Student); });
            GameObject.Find("CloseBtn").GetComponent<Button>().onClick.AddListener(() => { OnCloseApp(); });
        }
        
        // Update is called once per frame
        void Update () {
           
        }
    
        void OnClickThemeBtn(THEME_ID theme)
        {
            SceneManager.LoadScene("SelectLevel");
            DataMgr.Instance().themeId = theme;
        }
    
        //退出程序
        void OnCloseApp()
        {
            Application.Quit();
        }
     
    }
    Scene_MainMenu.cs (管理游戏主菜单场景)
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    
    public class Scene_Start : MonoBehaviour {
    
        float _timer;
        GameObject anyKeyObj;
    
        // Use this for initialization
        void Start () {
            _timer = 0;
            anyKeyObj = GameObject.Find("anykeyTxt");
        }
        
        // Update is called once per frame
        void Update () {
    
            _timer += Time.deltaTime;
    
            if (_timer % 0.5f > 0.25f)
            {
                anyKeyObj.SetActive(true);
            }
            else
            {
                anyKeyObj.SetActive(false);
            }
    
    
            if (_timer>5||Input.anyKeyDown)
            {
                GoToMainMenu();
            }
        }
    
            void GoToMainMenu()
            {
                SceneManager.LoadScene("MainMenu");
            }
    }
    Scene_Start.cs (管理游戏开始时场景)

    SelectLevel文件夹

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    using UnityEngine.SceneManagement;
    
    
    //选关界面,每一个关卡按钮单元
    public class LevelItemCell : MonoBehaviour ,IPointerEnterHandler,IPointerExitHandler,
            IPointerDownHandler,IPointerUpHandler,IPointerClickHandler{
        public RectTransform numTrans;
        public GameObject LockObj;
        public GameObject pressObj;
    
        //[HideInInspector]
    
        public int id;      //每个单元对应的关卡id(从1开始)
        public LevelManager lvlMgr;
    
        LevelInfo levelInfo;
        bool isLock;        
    
        //点击按钮,跳转到游戏界面
        public void OnPointerClick(PointerEventData eventData)
        {
            if (isLock)
            {
                return;
            }
            DataMgr.Instance().levelId = id;
            DataMgr.Instance().levelInfo = levelInfo;
            SceneManager.LoadScene("Gameplay");
        }
    
        public void OnPointerDown(PointerEventData eventData)
        {
            pressObj.SetActive(true);
        }
    
        //当鼠标进入本单元矩形区域,显示当前关卡描述
        public void OnPointerEnter(PointerEventData eventData)
        {
            lvlMgr.SetLevelDesc(levelInfo.desc);
    
        }
    
        public void OnPointerExit(PointerEventData eventData)
        {
            lvlMgr.SetLevelDesc("关卡信息");
        }
    
        public void OnPointerUp(PointerEventData eventData)
        {
            pressObj.SetActive(false);
        }
    
        private void Awake()
        {
            LockObj.SetActive(false);
            pressObj.SetActive(false);
        }
    
        // Use this for initialization
        void Start () {
    
            //根据解锁关卡记录,设置关卡是否锁定
            if (lvlMgr.unlock_levelID < id)
            {
                LockObj.SetActive(true);
                isLock = true;
            }
    
            float scale = 2;
            //初始化关卡数字显示
            if (id < 10)
            {
                //完全用代码动态创建一个Image对象,并作为num的子节点
                GameObject obj = new GameObject("num1",typeof(Image));
                RectTransform rtf = obj.GetComponent<RectTransform>();
                rtf.SetParent(numTrans);
                //设置数字
                Image img = obj.GetComponent<Image>();
                img.sprite = lvlMgr.spr_nums[id];
                img.SetNativeSize();    //图片原始尺寸
                rtf.localScale = new Vector3(2,2,1);
                rtf.localPosition = Vector3.zero;
    
            }
            else if (id<100)
            {
                //十位数
                GameObject obj = new GameObject("num1", typeof(Image));
                RectTransform rtf = obj.GetComponent<RectTransform>();
                rtf.SetParent(numTrans);
                //设置数字
                Image img = obj.GetComponent<Image>();
                img.sprite = lvlMgr.spr_nums[id/10];
                img.SetNativeSize();    //图片原始尺寸
                rtf.localScale = new Vector3(2, 2, 1);
                rtf.localPosition = new Vector3(-scale * rtf.rect.width/2-1,0,0);
    
                //个位数
                GameObject obj2 = new GameObject("num2", typeof(Image));
                RectTransform rtf2 = obj2.GetComponent<RectTransform>();
                rtf2.SetParent(numTrans);
                //设置数字
                Image img2 = obj2.GetComponent<Image>();
                img2.sprite = lvlMgr.spr_nums[id % 10];
                img2.SetNativeSize();    //图片原始尺寸
                rtf2.localScale = new Vector3(2, 2, 1);
                rtf2.localPosition = new Vector3(scale * rtf2.rect.width / 2 + 1, 0, 0);
            }
            levelInfo = DataMgr.Instance().levelData.levels[id - 1];
        }
        
        // Update is called once per frame
        void Update () {
            
        }
    }
    LevelItemCell.cs (选关界面,每一个关卡按钮单元)
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using DG.Tweening;
    using UnityEngine.SceneManagement;
    
    //用来管理所有关卡按钮
    //根据我们关卡数据定义,判断一共多少个关卡按钮。LevelManager来创建LevelPanelCell表格单元,LevelPanelCell表格单元是LevelItemCell
    public class LevelManager : MonoBehaviour
    {
    
        int totalCount = 0; //临时测试,一共18关
        readonly int ITEM_COUNT_PAGE = 15;  //每一页显示15个关卡
        readonly float PANEL_SPACE = 10f;
        readonly float MOVE_TIME = 0.5f;
    
        public RectTransform contenTrans;
        public Sprite[] spr_nums;
    
      
    
        float panelCellOffset;
        int pageCount;
    
        GameObject levelPanelCellPreb;
        GameObject levelItemCellPreb;
        Text levelDescTxt;
    
        float pointerDownTimeBak;
        float pointerDownX;
    
        int pageIdx;
        [HideInInspector]
        public int unlock_levelID=1;
    
        public void Awake()
        {
            levelPanelCellPreb = Resources.Load<GameObject>("Prefabs/SelectLevel/LevelPanelCell");
            levelItemCellPreb = Resources.Load("Prefabs/SelectLevel/LevelItemCell") as GameObject;
            levelDescTxt = GameObject.Find("LevelDesc/text").GetComponent<Text>();
    
            GameObject.Find("BackMainMenu").GetComponent<Button>().onClick.AddListener(()=> { OnBackMainMenuBtn(); });
    
            DataMgr.Instance().InitLevelData(DataMgr.Instance().themeId);
            totalCount = DataMgr.Instance().levelData.levels.Length;    //根据关卡数据表的个数,动态设置单元数量
    
    
            string level_key = System.Enum.GetName(typeof(THEME_ID), DataMgr.Instance().themeId) + "_level";
            if(PlayerPrefs.HasKey(level_key))
            {
                unlock_levelID = PlayerPrefs.GetInt(level_key);
            }
            else
            {
                unlock_levelID = 1;         //如果是第一次玩,还没有记录过,给默认解锁第一关
            }
            
        }
    
        // Use this for initialization
        void Start()
        {
            //计算panel的偏移
            panelCellOffset = contenTrans.rect.width + PANEL_SPACE;
            //计算出一共需要多少页
            pageCount = Mathf.CeilToInt((float)totalCount / ITEM_COUNT_PAGE);
            //当前显示的第几页表格panel,从0开始
            pageIdx = 0;
    
            for (int i = 0; i < pageCount; i++)
            {
                CreateLevelPanclCell(i);
            }
        }
    
        // Update is called once per frame
        void Update()
        {
            //按下时记录鼠标当前位置
            if (Input.GetMouseButtonDown(0))
            {
                pointerDownTimeBak = Time.time;
                pointerDownX = Input.mousePosition.x;
            }
    
            if (Input.GetMouseButtonUp(0))
            {
                //模拟滑动事件,假定很短时间的滑动
                if (Time.time - pointerDownTimeBak < 0.5f)
                {
                    float offsetX = Input.mousePosition.x - pointerDownX;
                    //向左滑动鼠标,并超过一定距离
                    if (offsetX < -200 && pageIdx < pageCount - 1)
                    {
                        //向左滑动鼠标,并超过一段距离
                        pageIdx++;
                        //执行所有表格面板向左平滑滑动
                        //0.5秒对自身左边叠加量,向左移动一段距离
                        contenTrans.DOBlendableLocalMoveBy(new Vector3(-panelCellOffset, 0, 0), MOVE_TIME);
    
                    }
                    else if (offsetX > 200 && pageIdx > 0)
                    {
                        //向右滑动鼠标,并超过一段距离
                        pageIdx--;
                        //执行所有表格面板向右平滑滑动
                        //0.5秒对自身左边叠加量,向右移动一段距离
                        contenTrans.DOBlendableLocalMoveBy(new Vector3(panelCellOffset, 0, 0), MOVE_TIME);
                    }
                }
            }
        }
    
        //创建表格panel,从0开始编号
        void CreateLevelPanclCell(int pageInx)
        {
            GameObject panelObj = Instantiate(levelPanelCellPreb, contenTrans);
            RectTransform panelTrans = panelObj.GetComponent<RectTransform>();
            panelTrans.anchoredPosition = new Vector2(panelCellOffset * pageInx, 0);
    
            //确定本业 中具有的关卡元素个数
            int startId = ITEM_COUNT_PAGE * pageInx;
            //本业需要显示按钮的个数
             int count = totalCount - startId;
    
            if (count > ITEM_COUNT_PAGE)
            {
                count = ITEM_COUNT_PAGE;
            }
    
            //创建本页中所有关卡按钮
            for (int i = 0; i < count; i++)
            {
                //创建每一个关卡的按钮单元
                GameObject itemObj = Instantiate(levelItemCellPreb, panelTrans);
    
                //这一段cell相关调用,实在Start()之前执行的
                LevelItemCell cell = itemObj.GetComponent<LevelItemCell>();
                cell.id = startId + i + 1;      //设置每个单元的关卡编号
                cell.lvlMgr = this;
                itemObj.name = cell.id.ToString();
    
            }
    
        }
    
        //设置关卡描述
        public void SetLevelDesc(string content)
        {
            levelDescTxt.text = content;
        }
    
        void OnBackMainMenuBtn()
        {
            SceneManager.LoadScene("MainMenu");
        }
    }
    LevelManager.cs (用来管理所有关卡按钮)
    (如需转载学习,请标明出处)
  • 相关阅读:
    .net core相关博客
    通过几个Hello World感受.NET Core全新的开发体验
    ASP.NET Core 介绍
    ASP.NET MVC4企业级实战目录
    ASP.NET MVC4入门到精通系列目录汇总
    HTTP详解
    壮哉大微软,.Net人的春天来了,你准备好了嘛!
    简析 .NET Core 构成体系
    .Net Core[译文]
    OI再见
  • 原文地址:https://www.cnblogs.com/1138720556Gary/p/9521264.html
Copyright © 2020-2023  润新知