c# 构架WPF 纸牌游戏(斗地主3)

   玩过Win7的纸牌游戏的朋友,一定对于游戏中的发牌动画记忆深刻,现在我们自己来实现这个动画过程。提到发牌动画,90%的程序员肯定会想到利用位置(Location)的变化来刷新界面,可能需要启用一些线程或者计时器之类的。但是朋友们,不要忘了,我们是在WPF环境中,这个天生就是和Flash抗衡的东东,怎么会用那么OUT的方法来实现呢。
   回想一下WPF的动画我们一般是怎么制作的,当然缺少不了Blend工具,但是Blend工具生成的都是一些前台的xaml标记语言。这些动画都是被HardCode的,显然这不符合我们的需求,我们希望通过C#代码在后台控制所有显示的纸牌。在WPF框架中,负责动画的类叫做Storyboard,一个StroyBord对象中可以包含多个TimeLine的动画对象,例如,我们比较熟悉的:DoubleAnimation就是用于线性移动的。

DoubleAnimation myAnimation = new DoubleAnimation()//声明一个DoubleAnimation 对象
{
     From 
= form,    //从xx坐标
     To = to,    //移动到xx坐标
     Duration = new Duration(spendTime),//移动所需要的时间
     BeginTime = beginTime //这个动画定义的时间
};
Storyboard.SetTargetName(myAnimation, "...controlname...");//将这个动画赋到那个控件上(参数为控件名称)
Storyboard.SetTargetProperty(myAnimation, new PropertyPath("....."));
//设置该控件的PropertyPath。这个值可以通过Blend生成的xaml获取到。(随便用Blend生成一个动画,然后看看xaml是怎么写的。可以参考MSDN。这里就不展开说了。)

  上面这段代码只有一个StroyBord,只要设置好BeginTime,那么在StroyBord中增加多个这样的动画,便可以顺利连接起来。

  大家要注意的是,如果在同一StroyBord中,对同一控件的不同属性进行了动画设置,那么系统就会自动同时执行这两个动画设置,例如:一段动画设置了横向移动,另外一端动画设置了纵向移动,那么系统会将这两种移动方式合并起来,就是沿着横向和纵向构成角度的1/2斜线处移动。

 //创建发牌动画,留三张牌作为底牌
Storyboard story = new Storyboard();         
for (int i = 0; i < 51; i++)
{
     CardAnimation animation 
= new CardAnimation(this, m_CardBaseCollection[i].Card);
     animation.CardIndex 
= i;
     PlayerCardInfo player 
= new PlayerCardInfo();
     player.CardBase 
= m_CardBaseCollection[i];
     PlayerHelper.AddToPlayer(i, player);
     animation.MoveCard(player.Location.X, player.Location.Y, TimeSpan.FromSeconds(GameOptions.DealSpeed 
* i),story );   
}
story.Begin(
this);//最后再运行所有串起来的动画。

animation.MoveCard(...)是用于设置移动动画的起始位置,和结束位置的,我们来看看代码:

        public void MoveCard(double toX, double toY, TimeSpan beginTime,Storyboard  story )
        {
            story.Children.Add(GetMoveAnimation(toX,beginTime, m_PropertyChainXArray));
//GetMoveAnimation是自己封装的,就是前面提到的DoubleAnimation生成的对象,这里就不展开来说了
            story.Children.Add(GetMoveAnimation(toY,beginTime, m_PropertyChainYArray));
        }

上面的代码并没有解释每张扑克移动的位置是如何计算出来的,animation.MoveCard(...)就直接传入了扑克的位置。
很显然,扑克的位置在PlayerHelper.AddToPlayer(i, player);进行了计算。
我的思想是这样的,i=0 到 51之间的循环中,只要判断 i % 3(取余数)便可以获得当前的这张牌属于哪一家,如果属于自己别忘了将牌翻转过来,至少要让自己看到才行。(还记得上节中提到的SetCard方法吗。)我们来看这个核心类的写法:

PlayerHelper代码
   public class PlayerHelper
    {

        
private static int m_CardCount = 0;

        
/// <summary>
        
/// 牌之间的间隔
        
/// </summary>
        private static int CardSpace
        {
            
get { return 25; }
        }

        
private static  Point LeftPlayerFirstLocation
        {
            
get { return new Point(-400-150); }
        }

        
private static Point RightPlayerFirstLocation
        {
            
get { return new Point(400,-150); }
        }

        
private static Point MiddlePlayerFirstLocation
        {
            
get { return new Point(-200300); }
        }

        
private static List<PlayerCardInfo> m_LeftPlayerCollection = new List<PlayerCardInfo>();

        
public static List<PlayerCardInfo> LeftPlayerCollection
        {
            
get { return PlayerHelper.m_LeftPlayerCollection; }
            
set { PlayerHelper.m_LeftPlayerCollection = value; }
        }

        
private static List<PlayerCardInfo> m_RihgtPlayerCollection = new List<PlayerCardInfo>();

        
public static List<PlayerCardInfo> RihgtPlayerCollection
        {
            
get { return PlayerHelper.m_RihgtPlayerCollection; }
            
set { PlayerHelper.m_RihgtPlayerCollection = value; }
        }

        
private static List<PlayerCardInfo> m_MiddlePlayerCollection = new List<PlayerCardInfo>();

        
public static List<PlayerCardInfo> MiddlePlayerCollection
        {
            
get { return PlayerHelper.m_MiddlePlayerCollection; }
            
set { PlayerHelper.m_MiddlePlayerCollection = value; }
        }

        
public static void ClearPlayerCard()
        {
            m_LeftPlayerCollection.Clear();
            m_RihgtPlayerCollection.Clear();
            m_MiddlePlayerCollection.Clear();
            m_CardCount 
= 0;
        }
       
        
public static void AddToPlayer(int i,PlayerCardInfo player)
        {
            
switch (i % 3)
            {
                
case 0:
                    m_LeftPlayerCollection.Add(player);
                    player.CardPlayer 
= CardPlayer.LeftPlayer;
                    player.Location 
= new Point(LeftPlayerFirstLocation.X, LeftPlayerFirstLocation.Y + CardSpace * m_CardCount);                  
                    
break;
                
case 1:
                    m_MiddlePlayerCollection.Add(player);
                    player.CardPlayer 
= CardPlayer.MiddlePlayer;
                    player.Location 
= new Point(MiddlePlayerFirstLocation.X + CardSpace * m_CardCount, MiddlePlayerFirstLocation.Y);
                    player.CardBase.SetCard();
                    break;
                
case 2:
                    m_RihgtPlayerCollection.Add(player);
                    player.CardPlayer 
= CardPlayer.RihgtPlayer;
                    player.Location 
= new Point(RightPlayerFirstLocation.X, RightPlayerFirstLocation.Y + CardSpace * m_CardCount);
                    m_CardCount
++;
                    
break;
            }
        }
    }

 

 

 

posted on 2010-03-29 19:48  程晨  阅读(2400)  评论(0编辑  收藏  举报

导航