[原创]一步一步用C#编写三国杀(三):设计流程

原创文章,转载请保留作者署名!

 

前面已经说了牌堆的设计,那么现在就正式进入流程,满足我们在(一)中所说的需求。

 

由于在(二)中已经说了要维护扩展,因此对于之前定义的Scene,则需要定义一个所选择的扩展包,代码如下:

 

ExpandedBlockStart.gif 扩展包
         private   readonly  IPackage[] selectedPackages;

        
///   <summary>
        
///  初始化新的 <see cref="Scene"/> 类的实例。
        
///   </summary>
        
///   <param name="packages"> 所要加载的包。 </param>
         public  Scene(IEnumerable < IPackage >  packages)
        {
            players[currentToken].HasToken 
=   true ;
            selectedPackages 
=  packages.ToArray();
        }

 

 

由于玩家是轮动的,因此设定一个令牌,只有持有令牌的玩家才能行动。

 

private   int  currentToken;

 

 

那么定义一个Start方法,开始游戏循环。

 

首先要根据选择的扩展包生成游戏牌堆。对于游戏牌堆,由于我们之前已经定义好了牌堆基类,因此实现就比较简单了,将扩展包中的游戏牌载入并洗牌即可。

 

ExpandedBlockStart.gif 游戏牌堆
     ///   <summary>
    
///  表示游戏牌牌堆。
    
///   </summary>
     public   sealed   class  GameCardHeap : CardHeap < GameCard >
    {
        
///   <summary>
        
///  初始化新的 <see cref="GameCardHeap"/> 类的实例。
        
///   </summary>
        
///   <param name="packages"> 所要加载的扩展包。 </param>
         public  GameCardHeap(IEnumerable < IPackage >  packages)
        {
            
foreach  (var package  in  packages)
            {
                ((List
< GameCard > ) Items).AddRange(package.GameCards);
            }
            Items.Shuffle();
        }
    }

 

 回头看我们上面的Start方法,在牌堆创建后,就进入了流程循环,还是直接来代码吧,注释都写的蛮清楚的

 

ExpandedBlockStart.gif 流程循环
         ///   <summary>
        
///  开始游戏。
        
///   </summary>
         public   void  Start()
        {
            Player currentPlayer;
            GameCardHeap heap 
=   new  GameCardHeap(selectedPackages);   //  创建牌堆

            
while ( true )
            {
                currentPlayer 
=  players[currentToken];   //  设置当前有令牌的玩家

                
//  摸牌阶段
                GameCard[] newCards  =  heap.Pop( 2 true );
                currentPlayer.Draw(newCards);

                
//  出牌阶段
                 while (currentPlayer.HasPlayableCard)
                {
                    
//  NOTE:为了简单,先实现只杀下家,并只使用杀、闪、桃
                     int  nextToken  =  currentToken  ==  players.Length  -   1   ?   0  : currentToken  +   1 ;
                    currentPlayer.Play(players[nextToken], currentPlayer.FirstPlayableCard);

                    
if  (IsGameEnds())
                        
goto  label;
                }

                
//  弃牌阶段
                
//  NOTE:为了简单,先实现只弃从头开始的牌到当前体力值
                 int  disCardCount  =  currentPlayer.HandCards.Length  -  currentPlayer.Hp;
                
if  (disCardCount  >   0 )
                {
                    GameCard[] removeCards 
=  currentPlayer.HandCards.Take(disCardCount).ToArray();
                    currentPlayer.Discard(removeCards);
                }

                
//  将令牌给下一个人
                GiveTokenToNext();
            }
            label:
            Console.WriteLine(
" 游戏结束! " );
        }

 

 

这里使用了一个死循环,但在游戏结束的时候使用goto语句跳出循环。所涉及到的一些方法如下:

 

ExpandedBlockStart.gif 一些辅助方法
         private   void  GiveTokenToNext()
        {
            
if  (currentToken  ==  players.Length  -   1 )
                currentToken 
=   0 ;
            
else
                currentToken
++ ;

            players[currentToken].HasToken 
=   true ;
        }

        
private   bool  IsGameEnds()
        {
            
return  players.Any(p  =>  p.IsDead) ;   //  如果选择到IsDead的Player,游戏结束
        }

 

 

注意,流程的设计中,由于玩家是在游戏逻辑边界内的,因此采用了主动的做法来进行设计。这样对于程序来说,我只要去考虑玩家的摸牌、出牌和弃牌所引起的各种变化即可。

转载于:https://www.cnblogs.com/gamix/archive/2010/08/04/sanguo_development_3.html

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值