Hi,之前有同学说要我把源码发出来,那我就把半成品源码的链接放在每篇文件的最后,有兴趣的话可以查阅参考,有问题可以跟我私信,也可以关注我的个人公众号,互相交流嘛。当然,代码也是在不断的持续改进中~

上期我们实现了叫地主功能,不过遗留了一个小功能:叫地主完成以后,要显示地主的3张牌,这期首先弥补这块的功能;

接着我们要进入开发出牌逻辑的开发阶段,好了,废话不多说,继续我们斗地主开发之旅~

地主牌的显示

我们在玩家界面的顶部中间位置,放置一个新的GameObject,命名为BidCards,用来记录3张地主牌的显示位置。

所以我们重构了CardManager中的发牌方法,在给地主发牌同时,生成地主牌的实例,放在BidCards相应位置:

    /// <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 - ).Take() //如果是抢地主牌,取最后3张
: cardNames.Take(cardNames.Length - ); //如果首次发牌 //计算每张地主牌的位置
int cardIndex = ;
var width = (bidCards.GetComponent<RectTransform>().sizeDelta.x - ) / ;
var centerBidPos = Vector3.zero;
var leftBidPos = centerBidPos - Vector3.left * width;
var rightBidPos = centerBidPos + Vector3.left * width;
List<Vector3> bidPoss = new List<Vector3> { leftBidPos, centerBidPos, rightBidPos };
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( / dealCardSpeed); //如果给地主发牌
if (ifForBid)
{
//显示地主牌
var bidcard = Instantiate(cardPrefab, bidCards.transform.TransformPoint(bidPoss[cardIndex]), Quaternion.identity, bidCards.transform);
bidcard.GetComponent<Card>().InitImage(new CardInfo(cardName));
bidcard.GetComponent<RectTransform>().localScale = Vector3.one * 0.3f;
}
else
{
//下一个需要发牌者
SetNextPlayer();
} cardIndex++;
} //隐藏牌堆
heapPos.gameObject.SetActive(false);
playerHeapPos[].gameObject.SetActive(false); //发普通牌
if (!ifForBid)
{
//显示玩家手牌
ShowPlayerSelfCards();
StartBiding();
}
//发地主牌
else
{
if (Players[bankerIndex] is PlayerSelf)
{
//显示玩家手牌
ShowPlayerSelfCards();
}
StartFollowing();
}
}

好的,我们地主牌显示已经没有问题了,接下来,我们要实现出牌回合逻辑

出牌回合功能实现

出牌回合其实跟叫地主回合类似,也是可以抽象出3种方法:进入出牌阶段、出牌、不出(比较进入叫地主阶段、叫地主、不叫地主);

因此,我们参照叫地主的逻辑,再实现出牌逻辑:

调整Player基类

添加开始出牌ToFollowing、出牌ForFollow、不出NotFollow:

  • ToFollowing:进入自己回合,关闭其他人的倒计时,进入自己的倒计时阶段;
  • ForFollow:关闭自己的倒计时,然后将选择的牌添加到出牌区域,跳出自己回合;
  • NotFollow:关闭自己的倒计时,跳出自己回合;
    /// <summary>
/// 开始出牌
/// </summary>
public virtual void ToFollowing()
{
isMyTerm = true; //关闭倒计时
StopCountDown(CountDownTypes.Follow); //开始倒计时
StartCountDown(CountDownTypes.Follow);
}
/// <summary>
/// 出牌
/// </summary>
public void ForFollow()
{
//关闭倒计时
StopCountDown(CountDownTypes.Follow); //选择的牌,添加到出牌区域
var selectedCards = cardInfos.Where(s => s.isSelected).ToList();
var offset = ;
for (int i = ; i < selectedCards.Count(); i++)
{
var card = Instantiate(prefabSmall, smallCardPos.position + Vector3.right * offset * i, Quaternion.identity, smallCardPos.transform);
card.GetComponent<RectTransform>().localScale = Vector3.one * 0.3f;
card.GetComponent<Image>().sprite = Resources.Load("Images/Cards/" + selectedCards[i].cardName, typeof(Sprite)) as Sprite;
card.transform.SetAsLastSibling(); smallCards.Add(card);
}
cardInfos = cardInfos.Where(s => !s.isSelected).ToList(); CardManager._instance.ForFollow();
isMyTerm = false;
}
/// <summary>
/// 不出
/// </summary>
public void NotFollow()
{
//关闭倒计时
StopCountDown(CountDownTypes.Follow); CardManager._instance.NotFollow();
isMyTerm = false;
}
/// <summary>
/// 销毁出牌对象
/// </summary>
public void DropAllSmallCards()
{
smallCards.ForEach(Destroy);
smallCards.Clear();
}

调整PlayerSelf类

实现ToFollowing:

调用基类的ToFollowing,并显示出牌按钮以供玩家选择

    /// <summary>
/// 开始出牌
/// </summary>
public override void ToFollowing()
{
base.ToFollowing();
CardManager._instance.SetFollowButtonActive(true);
}

调整PlayerOther类

模拟出牌,随机选择除手牌中的一张

    void Update()
{
//如果当前是自己回合,模拟对手叫牌
if (isMyTerm)
{
if (CardManager._instance.cardManagerState == CardManagerStates.Bid)
{
if (Input.GetKeyDown(KeyCode.Q)) //叫牌
{
ForBid();
}
if (Input.GetKeyDown(KeyCode.W)) //不叫
{
NotBid();
}
}
if (CardManager._instance.cardManagerState == CardManagerStates.Playing)
{
if (Input.GetKeyDown(KeyCode.Q)) //出牌
{
var rd1 = Random.Range(, cardInfos.Count);
cardInfos[rd1].isSelected = true; ForFollow();
}
if (Input.GetKeyDown(KeyCode.W)) //不出
{
NotFollow();
}
}
}
}

调整CardManager

实现卡牌管理对玩家出牌的控制:

  • 发完地主牌以后,开始出牌阶段,由地主先出牌;
  • 玩家选择出牌后,将上轮玩家的出牌堆清空,并将选择的牌添加到自己的出牌堆,轮转到下个玩家;
  • 玩家选择不出牌,将上轮玩家的出牌堆清空,轮转到下个玩家;
    /// <summary>
/// 开始出牌阶段
/// </summary>
private void StartFollowing()
{
cardManagerState = CardManagerStates.Playing;
//地主先出牌
Players[bankerIndex].ToFollowing();
}
/// <summary>
/// 玩家出牌
/// </summary>
public void ForFollow()
{
SetFollowButtonActive(false); //上轮玩家出牌清空
Players[(termCurrentIndex + Players.Length - ) % ].DropAllSmallCards();
if (Players[termCurrentIndex] is PlayerSelf)
ShowPlayerSelfCards(); SetNextPlayer();
Players[termCurrentIndex].ToFollowing();
}
/// <summary>
/// 玩家不出
/// </summary>
public void NotFollow()
{
SetFollowButtonActive(false); //上轮玩家出牌清空
Players[(termCurrentIndex + Players.Length - ) % ].DropAllSmallCards(); SetNextPlayer();
Players[termCurrentIndex].ToFollowing();
}

代码整理

现在我们的代码具有一定的规模了,为了方便更好的管理,把现有的代码重新整理一下,并进行功能分类,比如:

    

总结

嗯,今天到此为止,我们再来测试验证下,当然,目前只是实现了出牌的功能,没有对牌力进行校验和出牌的控制,对手玩家随机模拟出牌,尚未加入AI。我们以后逐步去实现~来看看这期的效果吧~

资源

项目源码

Unity3D手机斗地主游戏开发实战(03)_地主牌显示和出牌逻辑(不定期更新中~~~)的更多相关文章

  1. Unity3D手机斗地主游戏开发实战(04)_出牌判断大小(已完结)

    之前我们实现了叫地主.玩家和电脑自动出牌主要功能,但是还有个问题,出牌的时候,没有有效性检查和比较牌力大小.比如说,出牌3,4,5,目前是可以出牌的,然后下家可以出任何牌如3,6,9. 问题1:出牌检 ...

  2. Unity3D手机斗地主游戏开发实战(04)_出牌判断大小

    之前我们实现了叫地主.玩家和电脑自动出牌主要功能,但是还有个问题,出牌的时候,没有有效性检查和比较牌力大小.比如说,出牌3,4,5,目前是可以出牌的,然后下家可以出任何牌如3,6,9. 问题1:出牌检 ...

  3. Unity3D手机斗地主游戏开发实战(01)_发牌功能实现

    园子荒废多年,闲来无事,用Unity3D来尝试做一个简单的小游戏,一方面是对最近研究的Unity3D有点总结,一方面跟广大的园友相互学习和提高.话不多说,进入正题~ 一.创建项目 1.创建Unity2 ...

  4. Unity3D手机斗地主游戏开发实战(02)_叫地主功能实现(不定期更新中~~~)

    目录 Unity3D手机斗地主游戏开发实战(01)_发牌功能实现 Unity3D手机斗地主游戏开发实战(02)_叫地主功能实现 一.大体思路 前面我们实现了点击开始游戏按钮,系统依次给玩家发牌的逻辑和 ...

  5. Unity3D手机斗地主游戏开发实战(02)_叫地主功能实现

    大体思路 前面我们实现了点击开始游戏按钮,系统依次给玩家发牌的逻辑和动画,并展示当前的手牌.这期我们继续实现接下来的功能--叫地主. 1.首先这两天,学习了DOTween,这是一个强大的Unity动画 ...

  6. 【转】 [Unity3D]手机3D游戏开发:场景切换与数据存储(PlayerPrefs 类的介绍与使用)

    http://blog.csdn.net/pleasecallmewhy/article/details/8543181 在Unity中的数据存储和iOS中字典的存储基本相同,是通过关键字实现数据存储 ...

  7. (转)火溶CEO王伟峰:Unity3D手机网游开发

    今天看到这篇文章,感觉很不错,尤其是那句“Unity3D的坑我觉得最严重的坑就是没有懂3D的程序员,把Unity当成Office用”. 转自http://blog.csdn.net/wwwang891 ...

  8. 手机3D游戏开发:自定义Joystick的相关设置和脚本源码

    Joystick在手游开发中非常常见,也就是在手机屏幕上的虚拟操纵杆,但是Unity3D自带的Joystick贴图比较原始,所以经常有使用自定义贴图的需求. 下面就来演示一下如何实现自定义JoySti ...

  9. cocos2d-x游戏开发实战原创视频讲座系列1之2048游戏开发

     cocos2d-x游戏开发实战原创视频讲座系列1之2048游戏开发 的产生 视持续更新中.... 视频存放地址例如以下:http://ipd.pps.tv/user/1058663622     ...

随机推荐

  1. .NetCore之下载文件

    本篇将和大家分享的丝.NetCore下载文件,常见的下载有两种:A标签直接指向下载文件地址和post或get请求后台输出文件流的方式,本篇也将围绕这两种来分享:如果对您有好的帮助,请多多支持. 允许站 ...

  2. Redis学习——Redis持久化之RDB备份方式保存数据

    从这一个介绍里面知道,redis比memcache作为缓存数据库强大的地方,一个是支持的数据类型比较多,另一个就是redis持久化功能. 下面就介绍Redis的持久化之RDB! 一:什么是redis的 ...

  3. IE9总是弹出“ICBC Anti-Phishing class” 加载项是否要启用还是不启用的提示

    解决方法: 后来在通过查询,发现 IcbcDaemon.exe 进程是写在系统服务中的,我们可以在系统的服务管理工具中停止该服务: 1.单击开始,在搜索框中输入 services.msc ,按下回车键 ...

  4. cnblog排版

    记录一些自己写博客中的排版技巧 一.标题 红色部分代码用在标题的CSS样式中 <p style="background: gray; font-size: 18px; font-fam ...

  5. localStorage存值取值以及存取JSON,以及基于html5 localStorage的购物车

    localStorage.setItem("key","value");//存储变量名为key,值为value的变量 localStorage.key = &q ...

  6. 让asp.net网站支持多语言,使用资源文件

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="test.aspx.cs&quo ...

  7. 在SQL中用正则表达式替换html标签(2)

    由于数据库的一个表字段中多包含html标签,现在需要修改数据库的字段把html标签都替换掉.当然我可以通过写一个程序去修改,那毕竟有点麻烦.直接在查询分析器中执行,但是MS SQL Server并没有 ...

  8. Mysql安装后打开MySQL Command Line Client闪退解决方法

    1.开始菜单下;Mysql--->mysql server 5.6-->mysql command line Client ---右击,选择属性 2.在属性下查看目标位置: 3.将安装目录 ...

  9. 学习总结---BGP协议

    一.可以在自治域内使用BGP作为域内协议吗? 为什么?它和OSPF的关键差异是什么? 1.BGP的全称是边界网关协议,用于自治域间的路由传递,它不像OSPF协议,其重点不在于路由的计算,而在于路由的控 ...

  10. 使用Jquery.cookie.js操作cookie

    query.cookie.js是一个基于jquery的插件,点击下载! 创建一个会话cookie: $.cookie(‘cookieName’,'cookieValue’); 注:当没有指明cooki ...