c# 构架WPF 纸牌游戏(斗地主3)
玩过Win7的纸牌游戏的朋友,一定对于游戏中的发牌动画记忆深刻,现在我们自己来实现这个动画过程。提到发牌动画,90%的程序员肯定会想到利用位置(Location)的变化来刷新界面,可能需要启用一些线程或者计时器之类的。但是朋友们,不要忘了,我们是在WPF环境中,这个天生就是和Flash抗衡的东东,怎么会用那么OUT的方法来实现呢。
回想一下WPF的动画我们一般是怎么制作的,当然缺少不了Blend工具,但是Blend工具生成的都是一些前台的xaml标记语言。这些动画都是被HardCode的,显然这不符合我们的需求,我们希望通过C#代码在后台控制所有显示的纸牌。在WPF框架中,负责动画的类叫做Storyboard,一个StroyBord对象中可以包含多个TimeLine的动画对象,例如,我们比较熟悉的:DoubleAnimation就是用于线性移动的。
{
From = form, //从xx坐标
To = to, //移动到xx坐标
Duration = new Duration(spendTime),//移动所需要的时间
BeginTime = beginTime //这个动画定义的时间
};
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(...)是用于设置移动动画的起始位置,和结束位置的,我们来看看代码:
{
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方法吗。)我们来看这个核心类的写法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
{
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(-200, 300); }
}
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;
}
}
}