<p>
一个卡片消除小游戏,主要是用来熟悉unity的基本用法,功能比较简单,完成了随机发牌以及卡牌对比消除功能~
</p>
--
一、代码的主体思路:
代码包括两块:
- 用来做初始化模板的卡牌
这里包括卡牌自身的属性字段,以及使用方法,包括:卡牌的序号(id),卡背,设置卡牌的方法(SetCard),卡牌点击方法(OnMouseDown),卡背消失方法(SetBack)。 - 游戏中,用来负责卡牌发送,点击判断等处理的卡牌管理代码。
这是用来对整个游戏做管理的代码,包括:卡牌的数量(CARD_NUMBER),所有卡牌的ID,以及所有卡牌的图片(sprite)和卡牌之间的间隔(offsetX,offsetY);
方法包括:卡牌序号的随机初始化(ArrayInit),接收卡牌方法(ReceiveCard),卡牌比较方法(Macth)
<pre>
上面是整体代码的结构,下面会根据自己开发的思路一步一步完成。
</pre>
二、开发步骤:
- 1.先把需要的卡牌拖入到hierarchy中,并且将卡背作为卡牌的子对象:
完成后记得把卡背的z轴坐标调整为-2,让卡背在前。
- 2.完成卡牌模板后,给卡片添加script组件Card,以及碰撞组件(collider 2d):
<pre>
这里先实现基本功能,卡背,卡牌的ID,卡牌点击方法(先完成点点击卡背消失)
</pre>
private int id; //卡片的序号id
public GameObject cardBack; //卡背对象,在unity拖拽赋值
//鼠标点击事件需要在对象上添加collider组件
void OnMouseDown()
{
cardBack.SetActive(false);
}
- 3.有了模板卡牌后,可以完成卡牌的随机分发功能了:
为了完成随机分发,需要用到卡牌的设置方法还有随机数组:
//首先在卡牌的script组件中,添加卡牌的设置方法SetCard,有两个参数,一个是id,一个是sprite
public void SetCard(int id, Sprite fruit)
{
this.id = id;
this.GetComponent<SpriteRenderer>().sprite = fruit;
}
然后在hierarchy中创建一个空对象,用来挂CardManage脚本,来负责整个游戏的处理:
//设置卡牌的数量,和精灵的数量,精灵用拖拽赋值;
private const int CARD_NUMBER = 10;
int[] cardId=new int[CARD_NUMBER];
public Sprite[] fruitSprites=new Sprite[5];
//在CardManage中写上生成随机数组的方法
void ArrayInit(int[] array)
{
//给数组每一个元素赋值,分别为0,0,1,1,2,2,3,3,4,4,5,5
for (int i = 0; i < array.Length; i++)
{
array[i] = i/2;
}
//对有了初值的数组做乱序处理,从最后一个元素往前和随机的元素调换位置。
int swap, temp;
for (int i = array.Length-1; i > 0; i--)
{
swap = Random.Range(0, i);
temp = array[swap];
array[swap] = array[i];
array[i] = temp;
}
}
完成之后再CardManage中的Star方法中,开始生成随机卡牌:
//声明初始的卡牌和后续用到的实例化的卡牌对象
public Card oriCard;
private Card cloneCard;
//每张卡牌的间隔
private int offsetX = 2;
private int offsetY = 2;
// Use this for initialization
void Start()
{
//给oriCard赋值并且记录初始卡牌的位置信息(startpoz)
oriCard = GameObject.Find("Card").GetComponent<Card>();
Vector3 startPoz = oriCard.transform.position;
ArrayInit(cardId);
//通过for循环给所有的卡牌赋值并设置位置
for (int i = 0; i < CARD_NUMBER; i++)
{
if (i == 0)
{
cloneCard = oriCard;
}
else
{
cloneCard = Instantiate(oriCard);//实例化卡牌
}
//通过setCard方法设置每张卡牌的精灵。
cloneCard.SetCard(cardId[i], fruitSprites[cardId[i]]);
//设置每张卡牌的位置
cloneCard.transform.position = new Vector3(startPoz.x + offsetX * (i % 5), startPoz.y - offsetY * (i / 5), startPoz.z);
}
}
- 4.随机卡牌生成完成之后,就是对点击的卡牌进行比较,这个功能也是在CardManage中完成:
这个功能分为两个步骤:
a,首先是接收鼠标点击了的卡牌;
b,对存储了的卡牌进行比较(这里可以通过卡牌的ID来进行比较)。
//接收鼠标点击的卡牌,这个在CardManage中完成:
//声明两个空对象用来接收点击的卡牌
public Card first = null;
public Card second = null;
//接收方法
public void ReceiveCard(Card card)
{
if(first==null)
{
first = card;
}
else
{
second = card;
//开启一个协程,当两张卡牌进行比较的时候,如果不一致,延迟执行卡背恢复的操作。
StartCoroutine(Macth(first, second));
}
}
//写好接收的方法后,在Card中,进行调用:
//首先实例化CardManage中的脚本
CardManage manage;
private void Awake()
{
manage = GameObject.Find("CardManage").GetComponent<CardManage>();
}
//然后在鼠标点击事件调用接收方法:
//鼠标点击事件要记得加collider
void OnMouseDown()
{
//接收的条件为,当第二个接收的卡牌对象为空,并且该次点击的卡牌是没有被点击过的。
if(manage.second==null&&cardBack.activeSelf)
{
cardBack.SetActive(false);
manage.ReceiveCard(this);
}
}
完成接收后,可以进行比较了,这里用到了:
设置卡背消失方法,这个是在Card中实现.
比较方法,这个是在CardManage中实现,
//设置卡背方法
public void SetBack(bool isTurn)
{
cardBack.SetActive(isTurn);
}
//比较方法,由开启了协程,所以需要返回IEnumerator类型的方法
IEnumerator Macth(Card fir,Card sec)
{
if(fir.GetId!=sec.GetId)
{
//程序执行到这里的时候会等待1秒后在执行
yield return new WaitForSeconds(1);
fir.SetBack(true);
sec.SetBack(true);
}
//比较完毕后,清空接受的卡牌
first = null;
second = null;
}
- 5.游戏结束
当卡牌全部翻转过来的时候,则结束游戏。
//结束的思路是,首先设置一个判定值,每成功比较出一对,加1,当判定值达到了,则结束。
//判定值,从0开始计数
int index = 0;
//游戏胜利时条件
int end = CARD_NUMBER / 2;
//在比较方法中添加一个判断,当成功时,index+1;
IEnumerator Macth(Card fir,Card sec)
{
if (fir.GetId == sec.GetId)
{
index++;
}
}
//最后在Update方法中,实时进行判断是否满足胜利条件。
void Update () {
if(index==end)
{
print("游戏胜利~");
index = 0;
}
}
写到这里主体的功能也就完成啦,有兴趣的话可以增加更多的关卡。