斗地主文本

本文档详细解析了斗地主游戏的源码,包括创建扑克牌、洗牌、发牌、判断叫地主逻辑、电脑玩家随机叫分、合法牌型判断以及电脑玩家的出牌与跟牌策略。通过代码分析,展示了游戏中关键算法的实现。
摘要由CSDN通过智能技术生成

斗地主源码下载

链接:https://pan.baidu.com/s/1b_ADdWrLE8di1SSlFfuYPQ  密码:uavm


1创建一副扑克牌,写代码首先创建一张牌的类。如下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

class Poker : public Sprite  

{  

    public:  

        Poker();  

        ~Poker();  

        static Poker* create(const char *pszFileName, const CCRect& rect);  

        virtual void onEnter();  

        virtual void onExit();  

        virtual bool onTouchBegan(CCTouch *pTouch, CCEvent *pEvent);  

        virtual void onTouchMoved(CCTouch *pTouch, CCEvent *pEvent);  

        virtual void onTouchEnded(CCTouch *pTouch, CCEvent *pEvent);  

        virtual void onTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);  

        void showFront();//显示正面  

        void showLast();//显示背面  

        Poker* copy();//拷贝  

        void setTouchPriority(int num);  

        void SelectPkLuTou();//如果选择了牌就露出头  

        void SelectPkSuoTou();//如果选择了牌就缩头  

    private:  

        CC_SYNTHESIZE(bool,m_isSelect,Select);//是否已选  

        CC_SYNTHESIZE(GameScene*,m_gameMain,GameMain);  

        CC_SYNTHESIZE(bool,m_isDianJi,DianJi);//是否能被点击  

        CC_SYNTHESIZE(int,m_huaSe,HuaSe);//花色  

        CC_SYNTHESIZE(int,m_num,Num);//牌值  

        EventListenerTouchOneByOne* touchListener;  

};


然后我们用这个类写了一个函数来生成一张牌,该函数如下(位于源码GameScene中):

1

2

3

4

5

6

7

8

9

10

11

Poker* GameScene::selectPoker(int huaSe,int num){  

    Poker* pk;  

    if(huaSe != Gui)  

        pk = Poker::create("poker.png",CCRect(num*pkWidth,huaSe*pkHeight,pkWidth,pkHeight));  

    else  

        pk = Poker::create("poker.png",CCRect((num-XiaoGui)*pkWidth,huaSe*pkHeight,pkWidth,pkHeight));  

    pk->setHuaSe(huaSe);  

    pk->setNum(num);   牌值

    pk->setGameMain(this);  

    return pk;  

}



2接下来我们就用来创建一副扑克牌了,请看代码(在GameScene文件中)GameScene

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

bool GameScene::createPokers(){  

    bool isRet = false;  

    do   

    {  

        Size size = Director::sharedDirector()->getVisibleSize();  

        Poker* pk;  

        //创建52个除大鬼小鬼外的牌  

        for (int i=0; i<4; ++i)  

        {  

            for (int j=0; j<13; ++j)  

            {  

                pk = selectPoker(i,j);  

                pk->setPosition(ccp(size.width/2/*+j*20*/,size.height/2/*-i*20*/));  

                pk->showLast();  

                this->addChild(pk);  

                this->m_arrPokers->addObject(pk);  

            }  

        }  

        //创建小鬼  

        pk = selectPoker(Gui,XiaoGui);  

        pk->setPosition(ccp(size.width/2,size.height/2/*-4*20*/));  

        pk->showLast();  

        this->addChild(pk);  

        this->m_arrPokers->addObject(pk);  

        //创建大鬼  

        pk = selectPoker(Gui,DaGui);  

        pk->setPosition(ccp(size.width/2/*+20*/,size.height/2/*-4*20*/));  

        pk->showLast();  

        this->addChild(pk);  

        this->m_arrPokers->addObject(pk);  

        isRet = true;  

    } while (0);  

    return isRet;  

}

3洗牌

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次,这样就把原先顺序打乱了。

牌洗完之后,下面就该一个一个向玩家发牌了,请看下面代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

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_isSend的变量了,这个变量就是指发给某一个玩家的牌动画是否完成。我们再来看一下MovePk()的代码就有些明白了:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

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;  

}

4

头文件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

class Player : public CCObject  

{  

public:  

    Player();  

    ~Player();  

    void updatePkWeiZhi();//设置牌的位置  

       

private:  

    CC_SYNTHESIZE(bool,m_isDiZhu,IsDiZhu);//是否为地主  

    CC_SYNTHESIZE(bool,m_isCall,Call);//是否已叫地主  

    CC_SYNTHESIZE(int,m_iCallNum,CallNum);//叫地主的分数  

    CC_SYNTHESIZE(CCArray*,m_arrPk,ArrPk);//手里拥有的扑克牌  

    CC_SYNTHESIZE(CCPoint,m_point,Point);//牌在桌面的初始位置  

    CC_SYNTHESIZE(int,m_iPlayerClass,PlayerClass);//玩家种类:0为玩家,1为电脑,2为显示的三张牌,3为玩家要出的牌,4为电脑1要出的牌,5为电脑2要出的牌  

    std::vector<PaiXing> m_vecPX;//保存牌型  

    CC_SYNTHESIZE(bool,m_isOutPk,IsOutPk);//玩家是否出牌true: false:不出  

};

源文件

1

2

3

void Player::updatePkWeiZhi(){  

    CCSize size = CCDirector::sharedDirector()->getVisibleSize();  

    int x,y;

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

    //计算玩家牌和出的牌的初始位置  

    if(m_iPlayerClass == 0 || m_iPlayerClass == 3)  

    {  

        x = size.width/2-((m_arrPk->count()-1)*pkJianJu+pkWidth)/2;  

        y = m_point.y;  

    }  

    else if(m_iPlayerClass == 1 || m_iPlayerClass == 4 || m_iPlayerClass == 5)  

    {  

        x = m_point.x;  

        y = m_point.y;  

    }  

    else if(m_iPlayerClass == 2)  

    {  

        x = size.width/2-(m_arrPk->count()*pkWidth+(m_arrPk->count()-1)*pkJianJu)/2;  

        y = m_point.y;  

    }  

    int num = 0;  

    CCObject* object;  

    //对牌进行排序  

    if(m_iPlayerClass != 3 && m_iPlayerClass != 4 && m_iPlayerClass != 5)  

        for(int i=0; m_arrPk->count()!=0 && i<m_arrPk->count()-1; ++i)  

        {  

            for(int j=0; j<m_arrPk->count()-1-i; ++j)  

            {  

                Poker* pk1 = (Poker*)m_arrPk->objectAtIndex(j);  

                Poker* pk2 = (Poker*)m_arrPk->objectAtIndex(j+1);  

                if(pk1->getNum() < pk2->getNum())  

                    m_arrPk->exchangeObject(pk1,pk2);  

            }  

        }  

    //更新位置  

    CCARRAY_FOREACH(m_arrPk,object){  

        Poker* pk = (Poker*)object;  

        if (m_iPlayerClass == 0 || m_iPlayerClass == 3)  

        {  

            pk->showFront();  

            pk->setPosition(ccp(x+num*pkJianJu+pkWidth/2,y));  

        }  

        else if(m_iPlayerClass == 1 || m_iPlayerClass == 4 || m_iPlayerClass == 5)  

        {  

            pk->showFront();  

            if(m_iPlayerClass == 1)  

                pk->showLast();  

            pk->setPosition(ccp(x,y-num*pkJianJu));  

        }  

        else if(m_iPlayerClass == 2)  

        {  

            pk->setPosition(ccp(x+num*pkJianJu+num*pkWidth+pkWidth/2,y));  

        }  

        ++num;  

    }  

    //改变牌的z值或牌的触摸优先  

    int i=m_arrPk->count()-1;  

    CCARRAY_FOREACH(m_arrPk,object){  

        Poker* pk = (Poker*)object;  

        //改变z  

        if (m_iPlayerClass == 1 || m_iPlayerClass == 4 || m_iPlayerClass == 5)  

            pk->setZOrder(size.height - pk->getPositionY());  

        if (m_iPlayerClass == 0 || m_iPlayerClass == 3)  

            pk->setZOrder(pk->getPositionX());  

        //改变优先级  

    /*  Poker* pk1 = (Poker *)m_arrPk->objectAtIndex(i--); 

        pk->setTouchPriority(pk1->getPositionX());*/  

    }  

}

这个类最主要的是 updatePkWeiZhi(),它是为了把玩家手中的牌从大到小排序并居中显示。请注意最后一块代码改变牌的z值或牌的触摸优先级,为什么要这么做呢?这是因为牌的顺序换了之后,底下的牌有的会覆盖到另一个牌之上,改变触摸优先级也是同理。


发完牌,下面就该叫地主了,首先从玩家(人)开始叫地主,下一回合所有玩家(包括电脑玩家)按逆时针顺序叫地主。我们来看一下叫地主的模块:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

void GameScene::Call(float dt){  

    //是否都叫过地主  

    if(!m_player->getCall() || !m_npcOne->getCall() || !m_npcTwo->getCall())  

    {  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值