Cocos2d-x制作《单机斗地主》源码解剖2:洗牌和发牌

2015年03月24日 08:35 1 点赞 0 评论 更新于 2025-11-21 18:21

在第一讲里,我们创建了一副有顺序的扑克牌。现在,我们需要将这副牌打乱,在游戏中,这一操作俗称“洗牌”。

洗牌实现

以下是实现洗牌功能的代码:

bool GameScene::xiPai() {
bool isRet = false;
do {
for (int i = 0; i < 54; ++i) {
Poker* pk1 = (Poker*)m_arrPokers->randomObject();
Poker* pk2 = (Poker*)m_arrPokers->randomObject();
m_arrPokers->exchangeObject(pk1, pk2);
}
isRet = true;
} while (0);
return isRet;
}

上述代码的逻辑较为简单,通过循环 54 次,每次随机从牌堆中选取两张牌并交换它们的位置,以此将原先有序的牌堆打乱。

发牌实现

牌洗完之后,接下来就需要一张一张地向玩家发牌。以下是发牌功能的代码:

void GameScene::SendPk() {
Poker* pk;
if (m_iSendPk < 51 && m_isSend) { // 前51张牌发给玩家
pk = (Poker*)m_arrPokers->objectAtIndex(m_iSendPk);
if (m_iSendPk % 3 == 0) { // 给玩家发牌
MovePk(m_player, pk);
} else if (m_iSendPk % 3 == 1) { // 给电脑1发牌
MovePk(m_npcOne, pk);
} else if (m_iSendPk % 3 == 2) { // 给电脑2发牌
MovePk(m_npcTwo, pk);
}
++m_iSendPk;
m_isSend = false;
} else if (m_iSendPk > 50 && m_iSendPk < 54 && m_isSend) { // 留下三张地主牌
pk = (Poker*)m_arrPokers->objectAtIndex(m_iSendPk);
pk->showFront();
MovePk(m_Three, pk);
++m_iSendPk;
m_isSend = false;
} else if (m_iSendPk > 53) { // 牌发完分析电脑玩家的牌型
FenChaiNpcPai(m_npcOne);
FenChaiNpcPai(m_npcTwo);
m_iSendPk = 0;
m_iState = 1;
}
}

在这段代码中,我们使用 m_iSendPk 作为发牌的索引,根据不同的条件进行发牌操作:

  • m_iSendPk 小于 51 且 m_isSendtrue 时,将前 51 张牌依次发给玩家、电脑 1 和电脑 2。
  • m_iSendPk 大于 50 且小于 54 且 m_isSendtrue 时,将剩下的三张牌作为地主牌。
  • m_iSendPk 大于 53 时,牌发完,调用 FenChaiNpcPai 函数分析电脑玩家的牌型,并重置发牌索引和游戏状态。

这里的 m_isSend 变量用于指示发给某一个玩家的牌动画是否完成。接下来,我们看一下 MovePk() 函数的代码:

void GameScene::MovePk(Player* play, Poker* pk) {
CCMoveTo* move;
CCCallFuncND* func;
float time = 0.05;
play->getArrPk()->addObject(pk); // 从一副牌中选择pk这张牌
move = CCMoveTo::create(time, play->getPoint());
func = CCCallFuncND::create(this, callfuncND_selector(GameScene::func), play);
CCSequence* sequence = CCSequence::create(move, func, NULL);
pk->runAction(sequence);
}

void GameScene::func(CCNode* pSender, void* pData) {
Player* play = (Player*)pData;
play->updatePkWeiZhi(); // 整理一个玩家手中的牌
m_isSend = true;
}

MovePk 函数用于将一张牌移动到指定玩家的位置。具体步骤如下:

  1. 将牌添加到玩家的牌堆中。
  2. 创建一个移动动作 CCMoveTo,将牌移动到玩家的指定位置。
  3. 创建一个回调函数 CCCallFuncND,在移动动作完成后调用 func 函数。
  4. 创建一个动作序列 CCSequence,将移动动作和回调函数组合起来,并让牌执行该动作序列。

func 函数中,调用 play->updatePkWeiZhi() 函数整理玩家手中的牌,并将 m_isSend 变量设置为 true,表示发给该玩家的牌动画已完成。

关于 play->updatePkWeiZhi() 函数的具体实现,我们将在下一篇文章中进行详细解释。

作者信息

boke

boke

共发布了 3994 篇文章