欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-01-25 08:23:22
...

基于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技术的纸牌消除游戏
图3-2创建游戏UI
基于Unity3D技术的纸牌消除游戏
图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-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技术的纸牌消除游戏
图3-5 Level 1
基于Unity3D技术的纸牌消除游戏
图3-6 Level 2
基于Unity3D技术的纸牌消除游戏
图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技术的纸牌消除游戏
图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

上一篇: karaf学习 (2)

下一篇: