zoukankan      html  css  js  c++  java
  • 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;
                }
            }
        }
  • 相关阅读:
    MATLAB仿真学习笔记(一)
    SolidWorks学习笔记(一)
    机械制造技术学习笔记(七)
    基于MATLAB的多功能语音处理器
    MATLAB图形界面设计(下)
    36、如何避免僵尸进程?
    37、局部性原理你知道吗?主要有哪两大局部性原理?各自是什么?
    35、 守护进程、僵尸进程和孤儿进程
    32、什么是快表,你知道多少关于快表的知识?
    30、终端退出,终端运行的进程会怎样?31、如何让进程后台运行
  • 原文地址:https://www.cnblogs.com/chengchen/p/1699958.html
Copyright © 2011-2022 走看看