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

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

 

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

 

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

 

扩展包
        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方法,开始游戏循环。

 

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

 

游戏牌堆
    /// <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方法,在牌堆创建后,就进入了流程循环,还是直接来代码吧,注释都写的蛮清楚的

 

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

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

                
// 摸牌阶段
                GameCard[] newCards = heap.Pop(2true);
                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语句跳出循环。所涉及到的一些方法如下:

 

一些辅助方法
        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,游戏结束
        }

 

 

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

posted @ 2010-08-04 00:13    阅读(4889)  评论(6编辑  收藏