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(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; } } }
枚举卡牌状态
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; } } }
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); } }
棋盘两个核心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); } }
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; } } }
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); } }
创建一个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"); } }
注册按钮控件
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); } } }
点击界面,提示面板不可见
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; } }
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; }
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); } }
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); } }
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); } } }
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"); } }
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); //保存当前解锁的关卡编号,实际是当前关卡的下一关 } } }
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(); } }
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"); } }
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 () { } }
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"); } }