基于Unity3D技术的纸牌消除游戏

基于Unity3D技术的纸牌消除游戏

1 项目的创建和资源的导入

在Project下创建好需要的四个文件夹,其中Resources文件夹是用来存放A-K和大小王正面纸牌资源,Textture文件夹用来存放带有Restart、END、Level 1、Level 2、Level3字样的纸牌反面图片,无字样纸牌反面图片和背景图片资源,注意的是将这些图片导入时,需要将它们的Texture Type属性改为Sprite 2D and UI。Script文件夹下包含两个c#脚本文件,一个是游戏的主入口脚本文件,另一个是控制纸牌翻转脚本文件。效果如下图所示:
图3-1项目创建和资源导入

2 关卡选择按钮的创建

2.1创建游戏的UI

创建Canvas画布,添加三个Panel节点(Panel节点相当于一张image图片),分别为关卡选择界面Panel_start、纸牌翻转界面Panel_card、游戏结束界面Panel_over。在Panel_start节点下添加三个Button按钮,分别对应游戏关卡一二三,然后将三张纸牌关卡背景图分别导入Button节点的image属性。效果如下图所示:
基于Unity3D技术的纸牌消除游戏_第1张图片
图3-2创建游戏UI
基于Unity3D技术的纸牌消除游戏_第2张图片
图3-3关卡按钮效果

2.2在GameMain脚本文件中对关卡按钮添加功能,主要代码如下

public class GameMain : MonoBehaviour {
	public Button btn_level1;//声明Button节点
	public Button btn_level2;
public Button btn_level3;
public Transform panelStart;//声明Panel节点
	public Transform panelCard;
public Transform panelOver;
void Start () {			//分别对三个Button进行事件监听
		btn_level1.onClick.AddListener (() => {
			panelStart.gameObject.SetActive(false);
			panelCard.gameObject.SetActive(true);
			LoadLevelCard(2, 3);
		});	
		btn_level2.onClick.AddListener (() => {
			panelStart.gameObject.SetActive(false);
			panelCard.gameObject.SetActive(true);
			LoadLevelCard(2, 4);
		});	
		btn_level3.onClick.AddListener (() => {
			panelStart.gameObject.SetActive(false);
			panelCard.gameObject.SetActive(true);
			LoadLevelCard(2, 5);
		});
}

3 翻牌功能及界面

3.1Grid视图创建和说明

在Panel_card节点下新建一个Panel节点并添加Grid Layout Group组件,并合理调整好padding、cell size、spacing等属性值,在Panel节点下添加image节点,将纸牌图片导入image,并调整好尺寸大小。
基于Unity3D技术的纸牌消除游戏_第3张图片
图3-4Grid Layout Group组件

3.2纸牌预制体

通过在GameMain脚本文件中添加代码实现纸牌预制体效果,即每个关卡优美地展示出多少行多少列的纸牌,主要代码及注释和效果图如下:

viod Start(){	//向纸牌加载函数传参,第一个参数代表行数,第二个代表列数
LoadLevelCard(2, 3);
LoadLevelCard(2, 4);
LoadLevelCard(2, 5);
}
void LoadLevelCard(int row, int col)
	{
		Sprite[] sps = Resources.LoadAll<Sprite>("");   //加载所有卡牌图片
        int totalCount = row * col / 2;          //计算需要加载卡牌的数量
        //计算随机加载卡牌的索引
		List<Sprite> spsList = new List<Sprite>();
		for (int i = 0; i < sps.Length; ++i) {
			spsList.Add(sps[i]);
		}
		List<Sprite> needShowCardList = new List<Sprite>();
		while (totalCount > 0) {
			int radom = Random.Range(0, spsList.Count);
			needShowCardList.Add (spsList [radom]);
			needShowCardList.Add (spsList [radom]);
			spsList.RemoveAt (radom);
			totalCount--;
		}
        //显示纸牌到UI上
		Transform contentRoot = panelCard.Find ("Panel");
		GameObject itemTemplate = contentRoot.GetChild (0).gameObject;
		//高等级通关后在玩低等级要销毁对象,且解除关联
		for (int i = 1; i < contentRoot.childCount; ++i) {
			GameObject itemTemp = contentRoot.GetChild (i).gameObject;
		Sprite ss = itemTemp.transform.Find 				 ("Image_front").GetComponent<Image> ().sprite;
			Debug.Log (i + "," + ss.name);
			itemTemp.transform.SetParent (null);
			Destroy (itemTemp);
		}
		int normal_index = 0;
		while(needShowCardList.Count > 0){
			int index = Random.Range(0, needShowCardList.Count);
			GameObject itemObject = null;
			if (normal_index < contentRoot.childCount) {
				itemObject = contentRoot.GetChild (normal_index).gameObject;
			} else {
				itemObject = GameObject.Instantiate<GameObject> (itemTemplate);
				itemObject.transform.SetParent (contentRoot, false);
			}
			itemObject.transform.Find("Image_front").GetComponent<Image> ().sprite = needShowCardList [index];
			CardFlipAnimation cardAnimal = itemObject.GetComponent<CardFlipAnimation> ();
			cardAnimal.SetDefaultState ();
			needShowCardList.RemoveAt (index);
			++normal_index;
		}
		GridLayoutGroup glg = contentRoot.GetComponent<GridLayoutGroup> ();
		float panelWidth = col * glg.cellSize.x + glg.padding.left + glg.padding.right + (col - 1) * glg.spacing.x;
		float panelHeight = row * glg.cellSize.y + glg.padding.top + glg.padding.bottom + (row - 1) * glg.spacing.y;
		contentRoot.GetComponent<RectTransform> ().sizeDelta = new Vector2 (panelWidth, panelHeight);
	}

基于Unity3D技术的纸牌消除游戏_第4张图片
图3-5 Level 1
基于Unity3D技术的纸牌消除游戏_第5张图片
图3-6 Level 2
基于Unity3D技术的纸牌消除游戏_第6张图片
图3-7 Level 3

3.3翻牌效果实现

在纸牌翻转界面Panel_card下添加Panel节点,然后在Panel节点下添加新节点并命名为Card_item,其中包括纸牌正反面即Image_front和Image_back,在关掉Image_front和Image_back的Raycast Target参数(控制一张图片是否响应鼠标点击事件)后,将控制纸牌翻转脚本文件CardFilpAnimation导入Card_item中,然后在CardFilpAnimation中添加实现纸牌翻转功能的代码。
主要代码及注释如下:

IEnumerator FlipCardToFront() //翻转纸牌背面从0度到90度
{
	cardFront.gameObject.SetActive (false);
	cardBack.gameObject.SetActive (true);
	cardBack.rotation = Quaternion.identity;
	while (cardBack.rotation.eulerAngles.y < 90) {
		cardBack.rotation *= Quaternion.Euler (0, Time.deltaTime*90*(1f / flip_duration), 0);
		if (cardBack.rotation.eulerAngles.y > 90) {
			cardBack.rotation = Quaternion.Euler (0, 90, 0);
		}
		yield return new WaitForFixedUpdate ();
	}
    //接着翻转正面从90度到0度
	cardFront.gameObject.SetActive (true);
	cardBack.gameObject.SetActive (false);
	cardFront.rotation = Quaternion.Euler (0, 90, 0);
	while (cardFront.rotation.eulerAngles.y > 0) {
		cardFront.rotation *= Quaternion.Euler (0, -Time.deltaTime*90*(1f / flip_duration), 0);
		if (cardFront.rotation.eulerAngles.y > 90) {
			cardFront.rotation = Quaternion.Euler (0, 0, 0);
		}
		yield return new WaitForFixedUpdate ();
	}
	isFront = true;//标记纸牌在正面
	Camera.main.gameObject.GetComponent<GameMain> ().checkGameOver ();
}
IEnumerator FlipCardToBack()//翻转纸牌正面从0度到90度
{
	cardFront.gameObject.SetActive (true);
	cardBack.gameObject.SetActive (false);
	cardFront.rotation = Quaternion.identity;
	while (cardFront.rotation.eulerAngles.y < 90) {
		cardFront.rotation *= Quaternion.Euler (0, Time.deltaTime*90*(1f / flip_duration), 0);
		if (cardFront.rotation.eulerAngles.y > 90) {
			cardFront.rotation = Quaternion.Euler (0, 90, 0);
		}
		yield return new WaitForFixedUpdate ();
	}
    //接着翻转背面从90度到0度
    cardFront.gameObject.SetActive (false);
	cardBack.gameObject.SetActive (true);
	cardBack.rotation = Quaternion.Euler (0, 90, 0);
	while (cardBack.rotation.eulerAngles.y > 0) {
		cardBack.rotation *= Quaternion.Euler (0, -Time.deltaTime*90*(1f / flip_duration), 0);
		if (cardBack.rotation.eulerAngles.y > 90) {
			cardBack.rotation = Quaternion.Euler (0, 0, 0);
		}
		yield return new WaitForFixedUpdate ();
	}
	isFront = false;//标记纸牌在反面
}

然后在GameMain脚本文件中改变卡牌初始化的方法,则会随机翻转出不同纸牌,实现代码如下:

itemObject.transform.Find("Image_front").GetComponent<Image> ().sprite = needShowCardList [index]

3.4游戏胜利功能的实现

胜利判断实现算法:

a先判断出当前翻转纸牌的数量;
b如果小于两张继续翻转,如果等于两张,接着判断两张纸牌的数字或字母是否相等,若相等进行消除,若不等两张纸牌返回背面;
c直到所有纸牌被消除完,游戏胜利。
对于a、b过程,在GameMain脚本文件中添加纸牌消除与否的代码如下:

  //通过全局搜索找到所有纸牌
	CardFlipAnimation[] allCards = 	GameObject.FindObjectsOfType<CardFlipAnimation> ();

	if (allCards != null && allCards.Length > 0) {
	List<CardFlipAnimation> cardInFront = new List<CardFlipAnimation> ();//用来存放正面纸牌的数量和内容
	for (int i = 0; i < allCards.Length; ++i) {
		CardFlipAnimation cardTemp = allCards [i];
		if (cardTemp.isFront && !cardTemp.isOver) {
				cardInFront.Add (cardTemp);
				}
		if (cardInFront.Count >= 2) {
		//当正面纸牌数量大于等于2,获取纸牌的名字并判断是否相同
			string cardImageName1 = cardInFront[0].GetCardImageName ();
			string cardImageName2 = cardInFront[1].GetCardImageName ();
					if (cardImageName1 == cardImageName2) {
						cardInFront [0].MatchSuccess ();
						cardInFront [1].MatchSuccess ();
					} 
else {
						cardInFront [0].MatchFailed ();
						cardInFront [1].MatchFailed ();
					}
并在控制纸牌翻转CardFilpAnimation脚本文件中调用和实现上述方法:
Camera.main.gameObject.GetComponent<GameMain> ().checkGameOver ();
public string GetCardImageName()
	{
		return cardFront.GetComponent<Image> ().sprite.name;
	}
	public void MatchSuccess()//匹配成功,将两张纸牌的正反面均关闭掉
	{
		isOver = true;
		cardFront.gameObject.SetActive (false);
		cardBack.gameObject.SetActive (false);
	}
	public void MatchFailed(){  //匹配失败,将两张纸牌翻转回背面
		StartCoroutine (FlipCardToBack ());
	}
对于c过程,判断所有纸牌是否消除完毕,代码如下:
public void ToGameOverPage()//如果所有纸牌消除完,仅保留panelOver节点
	{
		panelStart.gameObject.SetActive(false);
		panelCard.gameObject.SetActive(false);
		panelOver.gameObject.SetActive(true);
	}
allCards = GameObject.FindObjectsOfType<CardFlipAnimation> ();
					bool AllOver = true;
					for(int j = 0; j < allCards.Length;++j){
						if (!allCards [j].isOver) {
							AllOver = false;
						}
					}
					if (AllOver) {
						ToGameOverPage ();
					}
					break;

游戏胜利后的跳转界面:

在Panel_over节点下添加end和restart节点,并分别将带END和Restart字样的纸牌背面图片导入,然后编写脚本文件实现跳转界面的功能,效果图和主要代码如下:
基于Unity3D技术的纸牌消除游戏_第7张图片
图3-8 游戏胜利后的跳转界面

btn_over.onClick.AddListener (() => {//END选择按钮,离开游戏
			#if UNITY_EDITOR
			UnityEditor.EditorApplication.isPlaying = false;
			#else
			Application.Quit();
			#endif
		});
btn_restart.onClick.AddListener (() => {
//restart按钮,重新开始游戏,仅打开panelStart节点
			panelStart.gameObject.SetActive(true);
			panelCard.gameObject.SetActive(false);
			panelOver.gameObject.SetActive(false);
		});
public void SetDefaultState()
	{
		isFront = false;
		isOver = false;
		if (cardFront != null) {
			cardFront.gameObject.SetActive (false);
			cardFront.rotation = Quaternion.identity;
		}
		if (cardBack != null) {
			cardBack.gameObject.SetActive (true);
			cardBack.rotation = Quaternion.identity;
		}
	}

4 优化和改进

  • 4.1提高游戏效率

开始每一关卡游戏的时候,可以让所有的纸牌显示一段时间,让玩家瞬时记忆一会,以增加游戏效率和可操作性。

  • 4.2增加翻拍次数统计功能

增加翻拍次数改进功能可防止玩家胡乱点击,已达到点击次数最少而获胜的效果。

  • 4.3音效功能

纸牌翻转、纸牌消除和游戏胜利时刻都可以增添音效,以增加游戏的趣味性。

纸牌消除游戏压缩包:(Unity软件打开)
链接:https://pan.baidu.com/s/1FEzlxGv2dwJBtHZ-gjC_9A
提取码:angu

你可能感兴趣的:(c#,游戏,unity)