rexian

咨询电话:023-6276-4481

联系方式

电 话:023-6276-4481

邮箱:broiling@qq.com

地址:重庆市南岸区亚太商谷6幢25-2

当前位置:网站首页 > 技术文章 > C#(WPF)实现拳皇(一)

C#(WPF)实现拳皇(一)

编辑:pansiqin 发表时间:2018-04-20 12:24:44
pansiqin

这个游戏还算比较大的,所以我打算分几篇文章来介绍。本节先介绍基础的P1的实现。其实对游戏有所了解的都知道格斗游戏算是游戏类型中比较难编写的,无论是逻辑还是复杂的技能控制还有碰撞检测都是比较复杂的,所以我尽量做到完美。

[csharp] view plain copy

  1. <Canvas Name="MyCanvas" ></Canvas>  

首先我们在主界面选取的布局是Canvas的布局,为什么呢,因为这个布局在我们家在图片资源的时候是非常方便的,可以准确的控制位置,便于我们进行属性动画的制作。(如果这里不懂可以先自己百度学习WPF的布局学习,其中Grid,Canvas,StackPanel,DockPanel等都是比较重要的,后面我会更新相关的文章)。然后定义一个Image的对象当作P1:


下面我们就来看如何进行主角的加载,我们知道在一般的格斗游戏中,角色都不是静止的站立的,都是会晃动的,也就以为着我们必须加载成动画的样子。

下面我们来学习在WPF中的动画是怎么实现的:

       1.时间容器的方式(TimeLine可能更准确的翻译是时间线,但是我更喜欢时间容器的翻译)

因为这种方式是规定一个时间段,这就是时间容器的容量,然后把动作加入进这个时间容器,最后再把这个时间容器加载进入就可以实现动画效果了,这种一般是实现属性动画。什么叫做属性动画呢,首先我们知道每个对象都有各种的属性,比如说个按钮的大小(这就叫做属性),按钮的位置(这就叫做属性),按钮的颜色等等。所以属性动画就是在一个规定的时间内动态的实现对象属性变化的动画。

[csharp] view plain copy

  1. public partial class MainWindow : Window  

  2.    {  

  3.        Rectangle rect;  

  4.        public MainWindow()  

  5.        {  

  6.            InitializeComponent();  

  7.            rect = new Rectangle();  

  8.            rect.Stroke = Brushes.Black;  

  9.            rect.Fill = Brushes.Red;  

  10.            //这两句一定要有,虽然没有在默认的情况下是加载到(0,0)但是没有这两句设置这个属性,在下面  

  11.            rect.SetValue(Canvas.LeftProperty,0D);  

  12.            rect.SetValue(Canvas.TopProperty,0D);  

  13.            rect.Height = 100;  

  14.            rect.Width = 100;  

  15.            MyCanvas.Children.Add(rect);  

  16.        }  

  17.   

  18.        private void MyCanvas_MouseDown(object sender, MouseButtonEventArgs e)  

  19.        {  

  20.            Point MoveTO = new Point();  

  21.            MoveTO = e.GetPosition(MyCanvas);  

  22.   

  23.            //故事画板,上面可以同时装载多个时间容器  

  24.            Storyboard MyStory = new Storyboard();  

  25.            //X轴的移动  

  26.            DoubleAnimation MyXAnimation = new DoubleAnimation(MoveTO.X, TimeSpan.FromMilliseconds(2000));  

  27.            Storyboard.SetTargetProperty(MyXAnimation, new PropertyPath(Canvas.LeftProperty));  

  28.            MyStory.Children.Add(MyXAnimation);  

  29.            MyStory.Begin(rect);  

  30.            //Y轴的移动  

  31.            DoubleAnimation MyYAnimation = new DoubleAnimation(MoveTO.Y, TimeSpan.FromMilliseconds(2000));  

  32.            Storyboard.SetTargetProperty(MyYAnimation, new PropertyPath(Canvas.TopProperty));  

  33.            MyStory.Children.Add(MyYAnimation);  

  34.            MyStory.Begin(rect);  

  35.        }  

这段代码是实现鼠标点击方块就动画的移动到点击的位置,但是如果你只是这样写你会发现一个问题,只在你点击方块的内部会产生移动而在点击外面是没有效果的,为什么呢?因为我们加入Canvas的时候,如果不对其进行操作是只认为只有当前控件占领的区域有效。解决办法有:

1.在Xaml中加入一个无效的背景色那么就可以实现效果了。

[csharp] view plain copy

  1. <Canvas Name="MyCanvas" Background="White" MouseDown="MyCanvas_MouseDown"/>  

2.那就不用Canvas中的鼠标点击函数,而用窗体的鼠标点击函数。这两种方法的实现效果都是一样的,当然属性动画是不止DoubleAnimation的还有其他的属性,比如PointAnimation等(不过一般都可以用DoubleAnimation来组合),想要深入了解可以上微软的官网看相关的文档(当然我后续也会更新)。

       以上的动画效果我们学会了的话,那我们就可以完成主角的走动了,没错,很简单吧!主角的走动只不过是图片的位置的移动罢了,和上面的矩形是一个效果。但是光有角色的走动好似不行的,我们还需要在走动的时候不停的实现画面的走动效果,还有技能效果。那么下面我们来介绍第二种动画产生的方法。

       2.定时器产生的动画。

在WPF中定时器有Timer和DispatcherTimer两种定时器,但是建议最好使用DispatcherTimer这个定时器。如果学过可视化编程并且进行过计时器使用的应该都知道是个什么东西。顾名思义就是在一个规定的时间内不停的触发一个动作,在WPF里面就是在规定的时间间隔调用一个函数,完成一个规定的动作。

[csharp] view plain copy

  1. public MainWindow()  

  2.  {  

  3.      InitializeComponent();  

  4.      Spirit = new Image();  

  5.      Canvas.SetLeft(Spirit,0D);  

  6.      Canvas.SetBottom(Spirit,150D);  

  7.      MyCanvas.Children.Add(Spirit);  

  8.      ResourceAdd();                                                                     

  9.      

  10.      //站立的计时器  

  11.      DispatcherTimer StandTimer = new DispatcherTimer();  

  12.      StandTimer.Interval = TimeSpan.FromMilliseconds(80);  

  13.      StandTimer.Tick += new EventHandler(StandTimer_Tick);  

  14.      StandTimer.IsEnabled = true;  

  15.      StandTimer.Start();  

计时器如果要不停的关停开启的话我建议在加载函数或者这个函数里面申请,或者申请为全局变量。因为这样可以避免我们在其他函数里面不停的申请,防止造成不可控制的错误,这样我们只需要设置其IsEnable属性或者调用Stop()函数即可控制计时器的关停和开启。

[csharp] view plain copy

  1. private void StandTimer_Tick(Object sender,EventArgs s)  

  2.        {  

  3.            if (!Is_Using_Skill)  

  4.            {  

  5.                switch (Go_Type)  

  6.                {  

  7.                    case 0:                                                                           //站立  

  8.                        {  

  9.                            for (int i = 0; i < Stand_Total_Count; i++)  

  10.                            {  

  11.                                if (i == Stand_Real_Count)  

  12.                                {  

  13.                                    Spirit.Source = Stand[i];  

  14.                                    Stand_Real_Count++;  

  15.                                    if (Stand_Real_Count == Stand_Total_Count)  

  16. &l