Unity3D手机斗地主游戏开发实战(02)_叫地主功能实现
2017-11-02 12:53
686 查看
大体思路
前面我们实现了点击开始游戏按钮,系统依次给玩家发牌的逻辑和动画,并展示当前的手牌。这期我们继续实现接下来的功能--叫地主。1.首先这两天,学习了DOTween,这是一个强大的Unity动画插件,大家可以参考:DOTween官方文档,个人感觉DOTween还是比较好用的。
好的,我们先来重构一下动画部分的代码(没有绝对牛逼的架构和设计,项目过程中不要不断的持续改进嘛);先把之前ITween相关引用从项目中删除,然后导入DOTween插件。
相关动画代码改造示例如下:
//移动动画,动画结束后自动销毁 var tween = cover.transform.DOMove(playerHeapPos[termCurrentIndex].position, 0.3f); tween.OnComplete(() => Destroy(cover));
怎么样,比之前简洁多了吧,而且之前ITween好像不太好用,处理自动销毁时,跟协程点冲突(可能我自己用的方式不对),现在改用DOTween,一点问题也没有~官网上也有这几个动画插件的性能比较,相对来说DOTween表现还是很不错的。
2.再来说说具体的设计思路
刚开始觉得叫地主逻辑挺简单,不就是分2次发牌嘛,第一次发51张,后面谁叫到地主再发3张就好了嘛,但其实实现的过程中,发现没有那么简单,需要注意的细节挺多:
a.发牌逻辑调整:因为发牌是按照当前玩家顺序,依次发牌,相当一个箭头一直指向当前回合玩家,发完51张牌后,箭头又开始指向开始发牌的玩家;这时候,需要判断首次发牌结束,由当前回合玩家开始叫牌;
b.当前玩家进入叫牌阶段时,触发倒计时,倒计时内如果玩家选择叫牌,则箭头保持不变,然后开始继续给当前玩家发3张剩余的牌;
c.倒计时内如果玩家选择不叫,则箭头继续指向下个玩家,下个玩家开始叫牌,回到分支b;
d.倒计时内玩家如果没有任何选择,结束后默认不叫,回到分支c;
e.如果3个玩家都没叫,则流局,重新开局(本期未实现,很容易,大家后面可以自己去尝试实现);
f.可以选择叫3分、2分、1分(将来需要实现,设计开发提前考虑)
h.考虑到玩家自己和对手叫牌逻辑不一样,自己的话,通过界面点击触发,对手暂时监听按键触发(后期改智能AI判断),比如按下Q叫牌,按下W不叫;
i.倒计时设计,叫牌的时候,需要显示玩家面前的计时器,计时结束后触发不叫,其他情况下隐藏;
j.玩家只有自己回合才能叫地主,必须做限制;
玩家类调整
Player作为玩家的基类,我们需要增加ToBiding(开始叫地主),ForBid(抢地主),NotBid(不抢地主),来控制玩家在叫地主过程中的公共逻辑。ToBiding:转到自己回合,并设置倒计时;
ForBid:跳出增加回合,停止倒计时,并调用卡牌管理类中的抢地主功能;
ForBid:跳出增加回合,停止倒计时,并调用卡牌管理类中的不抢地主功能;
然后,倒计时这块,添加一个协程Considerating,专门处理倒计时控件显示,标识玩家正在考虑中;
using System;
using System.Collections;
using System.IO;
using System.Linq;
using DG.Tweening;
using UnityEngine;
/// <summary>
/// 卡牌管理
/// </summary>
public class CardManager : MonoBehaviour
{
public static CardManager _instance; //单例
public float dealCardSpeed = 20; //发牌速度
public Player[] Players; //玩家的集合
public GameObject coverPrefab; //背面排预制件
public Transform heapPos; //牌堆位置
public Transform[] playerHeapPos; //玩家牌堆位置
public CardManagerStates cardManagerState;
private string[] cardNames; //所有牌集合
private int termStartIndex; //回合开始玩家索引
private int termCurrentIndex; //回合当前玩家索引
private int bankerIndex; //当前地主索引
private GameObject bidBtns;
void Awake()
{
_instance = this;
cardNames = GetCardNames();
bidBtns = GameObject.Find("BidBtns");
bidBtns.SetActive(false);
}
/// <summary>
/// 洗牌
/// </summary>
public void ShuffleCards()
{
//进入洗牌阶段
cardManagerState = CardManagerStates.ShuffleCards;
cardNames = cardNames.OrderBy(c => Guid.NewGuid()).ToArray();
}
/// <summary>
/// 开始发牌
/// </summary>
public IEnumerator DealCards()
{
//进入发牌阶段
cardManagerState = CardManagerStates.DealCards;
termCurrentIndex = termStartIndex;
yield return DealHeapCards(false);
}
/// <summary>
/// 发牌堆上的牌(如果现在不是抢地主阶段,发普通牌,如果是,发地主牌)
/// </summary>
/// <returns></returns>
private IEnumerator DealHeapCards(bool ifForBid)
{
//显示牌堆
heapPos.gameObject.SetActive(true);
playerHeapPos.ToList().ForEach(s => { s.gameObject.SetActive(true); });
var cardNamesNeeded = ifForBid
? cardNames.Skip(cardNames.Length - 3).Take(3) //如果是抢地主牌,取最后3张
: cardNames.Take(cardNames.Length - 3); //如果首次发牌
foreach (var cardName in cardNamesNeeded)
{
//给当前玩家发一张牌
Players[termCurrentIndex].AddCard(cardName);
var cover = Instantiate(coverPrefab, heapPos.position, Quaternion.identity, heapPos.transform);
cover.GetComponent<RectTransform>().localScale = Vector3.one;
//移动动画,动画结束后自动销毁 var tween = cover.transform.DOMove(playerHeapPos[termCurrentIndex].position, 0.3f); tween.OnComplete(() => Destroy(cover));
yield return new WaitForSeconds(1 / dealCardSpeed);
//下一个需要发牌者
if (!ifForBid)
SetNextPlayer();
}
//隐藏牌堆
heapPos.gameObject.SetActive(false);
playerHeapPos[0].gameObject.SetActive(false);
//发普通牌
if (!ifForBid)
{
//显示玩家手牌
ShowPlayerSelfCards();
StartBiding();
}
//发地主牌
else
{
if (Players[bankerIndex] is PlayerSelf)
{
//显示玩家手牌
ShowPlayerSelfCards();
}
cardManagerState = CardManagerStates.Playing;
}
}
/// <summary>
/// 开始抢地主
/// </summary>
private void StartBiding()
{
cardManagerState = CardManagerStates.Bid;
Players[termCurrentIndex].ToBiding();
}
/// <summary>
/// 显示玩家手牌
/// </summary>
private void ShowPlayerSelfCards()
{
Players.ToList().ForEach(s =>
{
var player0 = s as PlayerSelf;
if (player0 != null)
{
player0.GenerateAllCards();
}
});
}
/// <summary>
/// 清空牌局
/// </summary>
public void ClearCards()
{
//清空所有玩家卡牌
Players.ToList().ForEach(s => s.DropCards());
//显示玩家手牌
Players.ToList().ForEach(s =>
{
var player0 = s as PlayerSelf;
if (player0 != null)
{
player0.DestroyAllCards();
}
});
}
/// <summary>
/// 叫地主
/// </summary>
public void ForBid()
{
//设置当前地主
bankerIndex = termCurrentIndex;
//给地主发剩下的3张牌
SetBidButtonActive(false);
StartCoroutine(DealHeapCards(true));
}
/// <summary>
/// 不叫
/// </summary>
public void NotBid()
{
SetBidButtonActive(false);
SetNextPlayer();
Players[termCurrentIndex].ToBiding();
}
/// <summary>
/// 控制叫地主按钮是否显示
/// </summary>
/// <param name="isActive"></param>
public void SetBidButtonActive(bool isActive)
{
bidBtns.SetActive(isActive);
}
/// <summary>
/// 设置下一轮开始玩家
/// </summary>
public void SetNextTerm()
{
termStartIndex = (termStartIndex + 1) % Players.Length;
}
/// <summary>
/// 设置下个回合玩家
/// </summary>
/// <returns></returns>
public void SetNextPlayer()
{
termCurrentIndex = (termCurrentIndex + 1) % Players.Length;
}
private string[] GetCardNames()
{
//路径
string fullPath = "Assets/Resources/Images/Cards/";
if (Directory.Exists(fullPath))
{
DirectoryInfo direction = new DirectoryInfo(fullPath);
FileInfo[] files = direction.GetFiles("*.png", SearchOption.AllDirectories);
return files.Select(s => Path.GetFileNameWithoutExtension(s.Name)).ToArray();
}
return null;
}
//开始新回合
public void OnStartTermClick()
{
ClearCards();
ShuffleCards();
StartCoroutine(DealCards());
}
}
View Code
总结
至此,我们【叫地主】功能大体完成了,来试试效果吧~资源
项目源码相关文章推荐
- Unity3D手机斗地主游戏开发实战(01)_发牌功能实现
- Unity3D手机斗地主游戏开发实战(03)_地主牌显示和出牌逻辑
- Unity3D手机斗地主游戏开发实战(03)_地主牌显示和出牌逻辑(不定期更新中~~~)
- Unity3D游戏开发之游戏读/存档功能在Unity3D中的实现
- Unity3D手机斗地主游戏开发实战(04)_出牌判断大小
- Unity3D游戏开发之游戏读/存档功能在Unity3D中的实现
- Unity3D游戏开发之游戏读/存档功能在Unity3D中的实现
- Unity3D游戏开发之游戏读/存档功能在Unity3D中的实现
- Extjs上传附件实战开发,实现批量上传及在线预览功能(一)
- Extjs上传附件实战开发,实现批量上传及在线预览功能(二)
- [Unity3D]手机3D游戏开发:如何实现最高分的存储与显示(七)----使用Game ID避免数据重复输入
- (转)【Android游戏开发十六】Android Gesture之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!
- [Unity3D]手机3D游戏开发:如何实现最高分的存储与显示(二)----使用GUI.Box显示文字
- 项目开发实战 jQuery+php+mysql实现数据上传功能
- [Unity3D]手机3D游戏开发:如何实现最高分的存储与显示(八)----用TouchScreenKeyboard弹出键盘
- 【Android游戏开发十六】Android Gesture之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!
- [Unity3D]手机3D游戏开发:如何实现最高分的存储与显示(四)----使用PlayerPrefs存储数据到本地
- 项目开发实战 jQuery+php+mysql实现数据上传功能
- 项目开发实战 jQuery+php+mysql实现数据上传功能(补充!!!)
- 实现游戏开发中的屏幕滚动功能