基本信息
源码名称:WPF 2D游戏第一集
源码大小:2.62M
文件格式:.rar
开发语言:C#
更新时间:2015-06-26
   友情提示:(无需注册或充值,赞助后即可获取资源下载链接)

     嘿,亲!知识可是无价之宝呢,但咱这精心整理的资料也耗费了不少心血呀。小小地破费一下,绝对物超所值哦!如有下载和支付问题,请联系我们QQ(微信同号):813200300

本次赞助数额为: 2 元 
   源码介绍



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.IO;
using QX.Game.PathFinder;
using System.Windows.Media.Animation;
using WPFGameTutorial.Controls;
using WPFGameTutorial.Logic;

namespace WPFGameTutorial {

    public partial class Window20 : Window {

        public Window20() {
            InitializeComponent();
            ResizeMode = ResizeMode.CanMinimize; //设置窗口不能最大化
            InitSpirit();//初始化主角
            InitMask(); //初始化地图遮罩层
            InitMap(); //初始化地图
            InitMatrix(); //初始化障碍物
            //注册界面刷新线程
            CompositionTarget.Rendering  = new EventHandler(Timer_Tick);
        }

        QXSpirit Spirit = new QXSpirit();
        private void InitSpirit() {
            Spirit.X = 300;
            Spirit.Y = 400;
            Spirit.Timer.Interval = TimeSpan.FromMilliseconds(150);
            //设置角色身体及装备
            Spirit.Equipment[0] = 0;
            Spirit.Equipment[1] = 1;
            Spirit.EachActionFrameRange = new int[] { 5, 8, 7, 6, 8 }; //这5个数字在第十七节中讲了多次
            Spirit.DirectionFrameNum = 34; //每个方向行上有34列(第十七节中有说明)
            Spirit.TotalWidth = 5100;
            Spirit.TotalHeight = 1200;
            Spirit.CenterX = 75;
            Spirit.CenterY = 110;
            //加载角色图片源(具体参数意思可以到QXSpirit中了解)
            Spirit.Source = Super.EquipPart(Spirit.Equipment, Spirit.DirectionNum, Spirit.DirectionFrameNum, Spirit.TotalWidth, Spirit.TotalHeight, Spirit.SingleWidth, Spirit.SingleHeight);
            Carrier.Children.Add(Spirit);
        }

        //创建遮罩层
        Image Mask = new Image();
        private void InitMask() {
            Mask.Width = 202;
            Mask.Height = 395;
            Mask.Source = new BitmapImage((new Uri(@"Map\Mask3.png", UriKind.Relative)));
            Mask.Opacity = 0.7;
            Carrier.Children.Add(Mask);
            Canvas.SetZIndex(Mask, 612);
        }

        Image Map = new Image();
        private void InitMap() {
            Map.Width = 1750;
            Map.Height = 1440;
            Map.Source = new BitmapImage((new Uri(@"Map\Map4.jpg", UriKind.Relative)));
            Carrier.Children.Add(Map);
            Canvas.SetLeft(Map, -320);
            Canvas.SetTop(Map, -200);
            Map.SetValue(Canvas.ZIndexProperty, -1);
        }

        Rectangle rect;
        private void InitMatrix() {
            for (int y = 0; y < Matrix.GetUpperBound(1); y  ) {
                for (int x = 0; x < Matrix.GetUpperBound(0); x  ) {
                    //默认值可以通过在矩阵中用1表示
                    Matrix[x, y] = 1;
                }
            }
            //构建障碍物
            for (int y = 60; y <= 68; y  ) {
                for (int x = 80; x <= 100; x  ) {
                    //障碍物在矩阵中用0表示
                    Matrix[x, y] = 0;
                    //rect = new Rectangle();
                    ////目前暂时不新创一个自定义控件,而把坐标储存在Tag属性中
                    //rect.Tag = x   ","   y;
                    //rect.Fill = new SolidColorBrush(Colors.GreenYellow);
                    //rect.Opacity = 0.3;
                    //rect.Stroke = new SolidColorBrush(Colors.Gray);
                    //rect.Width = GridSize;
                    //rect.Height = GridSize;
                    //Carrier.Children.Add(rect);
                    //Canvas.SetZIndex(rect, 10001);
                }
            }
        }

        int UnitMoveCost = 70; //移动一个单元格距离所需要的时间(毫秒)
        int Scrollspeed = 5; //定义地图滚动速度
        //游戏窗口刷新主线程间隔事件
        private void Timer_Tick(object sender, EventArgs e) {
            //窗口中的所有对象物体位置时时改变
            AllMove();
            //判断主角是否移动到了目标,如果是则动作切换成停止
            if (ArriveTarget()) {
                Spirit.Action = Actions.Stop;
            } else if (!Spirit.IsAStarMoving && WillCollide()) {
                //在寻路移动模式中,主角100%会饶过障碍物的,
                //因此只有在非寻路模式中才需要时时判断主角是否将要碰撞障碍物
                AStarMoveTo(Spirit.Destination);
                Spirit.IsAStarMoving = true;
            }
        }

        //判断是否将要碰撞到障碍物(障碍物预测法)
        private bool WillCollide() {
            switch ((int)Spirit.Direction) {
                case 0:
                    return Matrix[(int)(Spirit.X / GridSize), (int)(Spirit.Y / GridSize) - 1] == 0 ? true : false;
                case 1:
                    return Matrix[(int)(Spirit.X / GridSize)   1, (int)(Spirit.Y / GridSize) - 1] == 0 ? true : false;
                case 2:
                    return Matrix[(int)(Spirit.X / GridSize)   1, (int)(Spirit.Y / GridSize)] == 0 ? true : false;
                case 3:
                    return Matrix[(int)(Spirit.X / GridSize)   1, (int)(Spirit.Y / GridSize)   1] == 0 ? true : false;
                case 4:
                    return Matrix[(int)(Spirit.X / GridSize), (int)(Spirit.Y / GridSize)   1] == 0 ? true : false;
                case 5:
                    return Matrix[(int)(Spirit.X / GridSize) - 1, (int)(Spirit.Y / GridSize)   1] == 0 ? true : false;
                case 6:
                    return Matrix[(int)(Spirit.X / GridSize) - 1, (int)(Spirit.Y / GridSize)] == 0 ? true : false;
                case 7:
                    return Matrix[(int)(Spirit.X / GridSize) - 1, (int)(Spirit.Y / GridSize) - 1] == 0 ? true : false;
                default:
                    return true;
            }
        }

        //全体对象进行相对移动
        private void AllMove() {
            double MapLeft = Canvas.GetLeft(Map);
            double MapTop = Canvas.GetTop(Map);
            //鼠标进入地图边缘引导地图移动
            switch (GetMouseArea()) {
                case 0:
                    if (MapTop < 0) {
                        Canvas.SetTop(Map, Canvas.GetTop(Map)   Scrollspeed);
                    }
                    break;
                case 1:
                    if (MapTop < 0) {
                        Canvas.SetTop(Map, Canvas.GetTop(Map)   Scrollspeed);
                    }
                    if (Map.Width   MapLeft > this.ActualWidth) {
                        Canvas.SetLeft(Map, Canvas.GetLeft(Map) - Scrollspeed);
                    }
                    break;
                case 2:
                    if (Map.Width   MapLeft > this.ActualWidth) {
                        Canvas.SetLeft(Map, Canvas.GetLeft(Map) - Scrollspeed);
                    }
                    break;
                case 3:
                    if (Map.Width   MapLeft > this.ActualWidth) {
                        Canvas.SetLeft(Map, Canvas.GetLeft(Map) - Scrollspeed);
                    }
                    if (Map.Height   MapTop > this.ActualHeight) {
                        Canvas.SetTop(Map, Canvas.GetTop(Map) - Scrollspeed);
                    }
                    break;
                case 4:
                    if (Map.Height   MapTop > this.ActualHeight) {
                        Canvas.SetTop(Map, Canvas.GetTop(Map) - Scrollspeed);
                    }
                    break;
                case 5:
                    if (Map.Height   MapTop > this.ActualHeight) {
                        Canvas.SetTop(Map, Canvas.GetTop(Map) - Scrollspeed);
                    }
                    if (MapLeft < 0) {
                        Canvas.SetLeft(Map, Canvas.GetLeft(Map)   Scrollspeed);
                    }
                    break;
                case 6:
                    if (MapLeft < 0) {
                        Canvas.SetLeft(Map, Canvas.GetLeft(Map)   Scrollspeed);
                    }
                    break;
                case 7:
                    if (MapTop < 0) {
                        Canvas.SetTop(Map, Canvas.GetTop(Map)   Scrollspeed);
                    }
                    if (MapLeft < 0) {
                        Canvas.SetLeft(Map, Canvas.GetLeft(Map)   Scrollspeed);
                    }
                    break;
            }
            //遮罩层跟随移动
            Canvas.SetLeft(Mask, MapLeft   793);
            Canvas.SetTop(Mask, MapTop   217);
            //主角跟随地图同时移动
            Canvas.SetLeft(Spirit, Spirit.X - Spirit.CenterX   MapLeft);
            Canvas.SetTop(Spirit, Spirit.Y - Spirit.CenterY   MapTop);
            Canvas.SetZIndex(Spirit, (int)Spirit.Y); //时时的更新它的层次(画家算法)
            //所有障碍物实体同样跟随移动(实际中不需要显示出来,这里只为了测试)
            foreach (UIElement uie in Carrier.Children) {
                if (uie is Rectangle) {
                    Rectangle r = uie as Rectangle;
                    Point p = GetPointFromTag(r.Tag);
                    Canvas.SetLeft(r, MapLeft   p.X * GridSize);
                    Canvas.SetTop(r, MapTop   p.Y * GridSize);
                }
            }
        }
        
        //判断是否移动到目的地
        private bool ArriveTarget() {
            return (storyboard != null && storyboard.GetCurrentProgress() == 1) ? true : false;
        }

        //从方块障碍物的Tag属性中分离出它的坐标Point
        private Point GetPointFromTag(object tag) {
            string[] str = tag.ToString().Split(new char[] { ',' });
            return new Point(Convert.ToDouble(str[0]), Convert.ToDouble(str[1]));
        }

        //根据鼠标的位置获取鼠标所处的区域代号
        //0代表正上方区域(即12点位置)然后其他7个区域按顺时针依次为1,2,3,4,5,6,7
        int distance = 80; //定义距离边缘多少即开始牵引地图
        private int GetMouseArea() {
            Point MousePosition = Mouse.GetPosition(Carrier); //获取鼠标当前处于窗口中的位置
            int result = -1;
            //如果鼠标未超出窗口
            if (MousePosition.X >= 0 && MousePosition.Y >= 0) {
                //根据8种情况返回8个数字
                if (MousePosition.X >= 190 && MousePosition.X <= 570) {
                    if (MousePosition.Y <= distance) {
                        result = 0;
                    } else if (MousePosition.Y >= 500 - distance) {
                        result = 4;
                    }
                } else if (MousePosition.Y >= 125 && MousePosition.Y <= 375) {
                    if (MousePosition.X <= distance) {
                        result = 6;
                    } else if (MousePosition.X >= 760 - distance) {
                        result = 2;
                    }
                } else if ((MousePosition.X < 190 && MousePosition.Y <= distance) || (MousePosition.Y < 125 && MousePosition.X <= distance)) {
                    result = 7;
                } else if ((MousePosition.X > 570 && MousePosition.Y <= distance) || (MousePosition.Y < 125 && MousePosition.X >= 760 - distance)) {
                    result = 1;
                } else if ((MousePosition.X > 570 && MousePosition.Y >= 500 - distance) || (MousePosition.Y > 375 && MousePosition.X >= 760 - distance)) {
                    result = 3;
                } else if ((MousePosition.X < 190 && MousePosition.Y >= 500 - distance) || (MousePosition.Y > 375 && MousePosition.X <= distance)) {
                    result = 5;
                }
            }
            return result;
        }

        Storyboard storyboard; //创建移动动画故事板
        //直线移动
        private void NormalMoveTo(Point p) {
            //总的移动花费
            double totalcost = Math.Sqrt(Math.Pow(p.X - Spirit.X, 2)   Math.Pow(p.Y - Spirit.Y, 2)) / GridSize * UnitMoveCost;
            //创建移动动画
            storyboard = new Storyboard();
            //创建X轴方向属性动画
            DoubleAnimation doubleAnimation = new DoubleAnimation(
              Spirit.X,
              p.X,
              new Duration(TimeSpan.FromMilliseconds(totalcost))
            );
            Storyboard.SetTarget(doubleAnimation, Spirit);
            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("X"));
            storyboard.Children.Add(doubleAnimation);
            //创建Y轴方向属性动画
            doubleAnimation = new DoubleAnimation(
              Spirit.Y,
              p.Y,
              new Duration(TimeSpan.FromMilliseconds(totalcost))
            );
            Storyboard.SetTarget(doubleAnimation, Spirit);
            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Y"));
            storyboard.Children.Add(doubleAnimation);
            //创建主角朝向属性动画
            double direction = Super.GetDirectionByTan(p.X, p.Y, Spirit.X, Spirit.Y);
            doubleAnimation = new DoubleAnimation(
              direction,
              direction,
              new Duration(TimeSpan.FromMilliseconds(totalcost))
            );
            Storyboard.SetTarget(doubleAnimation, Spirit);
            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Direction"));
            storyboard.Children.Add(doubleAnimation);
            //动画播放
            storyboard.Begin();
        }

        //A*移动
        IPathFinder PathFinder = null;
        byte[,] Matrix = new byte[1024, 1024]; //地图寻路用二维矩阵
        double GridSize = 10; //单位格子大小
        System.Drawing.Point Start = System.Drawing.Point.Empty; //移动起点坐标
        System.Drawing.Point End = System.Drawing.Point.Empty; //移动终点坐标
        private void AStarMoveTo(Point p) {
            //进行坐标系缩小
            int start_x = (int)(Spirit.X / GridSize);
            int start_y = (int)(Spirit.Y / GridSize);
            Start = new System.Drawing.Point(start_x, start_y); //设置起点坐标
            int end_x = (int)(p.X / GridSize);
            int end_y = (int)(p.Y / GridSize);
            End = new System.Drawing.Point(end_x, end_y); //设置终点坐标

            if (Start == End) {
                //MessageBox.Show("点到自己脚底啦!");
            } else {
                PathFinder = new PathFinderFast(Matrix);
                PathFinder.Formula = HeuristicFormula.Manhattan; //使用我个人觉得最快的曼哈顿A*算法
                List<PathFinderNode> path = PathFinder.FindPath(Start, End); //开始寻径

                if (path == null) {
                    //MessageBox.Show("路径不存在!");
                } else {
                    Point[] framePosition = new Point[path.Count]; //定义关键帧坐标集
                    for (int i = path.Count - 1; i >= 0; i--) {
                        //从起点开始以GridSize为单位,顺序填充关键帧坐标集,并进行坐标系放大
                        framePosition[path.Count - 1 - i] = new Point(path[i].X, path[i].Y);
                    }
                    storyboard = new Storyboard();
                    //创建X轴方向逐帧动画
                    DoubleAnimationUsingKeyFrames keyFramesAnimationX = new DoubleAnimationUsingKeyFrames();
                    //总共花费时间 = path.Count * UnitMoveCost
                    keyFramesAnimationX.Duration = new Duration(TimeSpan.FromMilliseconds(path.Count * UnitMoveCost));
                    Storyboard.SetTarget(keyFramesAnimationX, Spirit);
                    Storyboard.SetTargetProperty(keyFramesAnimationX, new PropertyPath("X"));
                    //创建Y轴方向逐帧动画
                    DoubleAnimationUsingKeyFrames keyFramesAnimationY = new DoubleAnimationUsingKeyFrames();
                    keyFramesAnimationY.Duration = new Duration(TimeSpan.FromMilliseconds(path.Count * UnitMoveCost));
                    Storyboard.SetTarget(keyFramesAnimationY, Spirit);
                    Storyboard.SetTargetProperty(keyFramesAnimationY, new PropertyPath("Y"));
                    //创建朝向动画
                    DoubleAnimationUsingKeyFrames keyFramesAnimationDirection = new DoubleAnimationUsingKeyFrames();
                    keyFramesAnimationDirection.Duration = new Duration(TimeSpan.FromMilliseconds(path.Count * UnitMoveCost));
                    Storyboard.SetTarget(keyFramesAnimationDirection, Spirit);
                    Storyboard.SetTargetProperty(keyFramesAnimationDirection, new PropertyPath("Direction"));
                    for (int i = 0; i < framePosition.Count(); i  ) {
                        //加入X轴方向的匀速关键帧
                        LinearDoubleKeyFrame keyFrame = new LinearDoubleKeyFrame();
                        //平滑衔接动画(将寻路坐标系中的坐标放大回地图坐标系中的坐标)
                        if (i == 0) {
                            keyFrame.Value = Spirit.X;
                        } else if (i == framePosition.GetUpperBound(0)) {
                            keyFrame.Value = Spirit.Destination.X;
                        } else {
                            keyFrame.Value = framePosition[i].X * GridSize   GridSize / 2; //  GridSize / 2为偏移处理
                        }
                        keyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(UnitMoveCost * i));
                        keyFramesAnimationX.KeyFrames.Add(keyFrame);
                        //加入X轴方向的匀速关键帧
                        keyFrame = new LinearDoubleKeyFrame();
                        if (i == 0) {
                            keyFrame.Value = Spirit.Y;
                        } else if (i == framePosition.GetUpperBound(0)) {
                            keyFrame.Value = Spirit.Destination.Y;
                        } else {
                            keyFrame.Value = framePosition[i].Y * GridSize   GridSize / 2; //  GridSize / 2偏移处理
                        }
                        keyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(UnitMoveCost * i));
                        keyFramesAnimationY.KeyFrames.Add(keyFrame);
                        //加入朝向匀速关键帧
                        keyFrame = new LinearDoubleKeyFrame();
                        keyFrame.Value = i == framePosition.GetUpperBound(0)
                            ? Super.GetDirectionByTan(framePosition[i].X, framePosition[i].Y, framePosition[i - 1].X, framePosition[i - 1].Y)
                            : Super.GetDirectionByTan(framePosition[i   1].X, framePosition[i   1].Y, framePosition[i].X, framePosition[i].Y)
                        ;
                        keyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(UnitMoveCost * i));
                        keyFramesAnimationDirection.KeyFrames.Add(keyFrame);
                    }
                    storyboard.Children.Add(keyFramesAnimationX);
                    storyboard.Children.Add(keyFramesAnimationY);
                    storyboard.Children.Add(keyFramesAnimationDirection);
                    //故事板动画开始
                    storyboard.Begin();
                    //------------------------
                    //用白色点记录移动轨迹(此段代码只做测试用,真实使用时请注释掉,否则将严重影响系统性能)
                    //------------------------
                    //for (int i = path.Count - 1; i >= 0; i--) {
                    //    rect = new Rectangle();
                    //    rect.Tag = path[i].X   ","   path[i].Y;
                    //    rect.Fill = new SolidColorBrush(Colors.Snow);
                    //    rect.Stroke = new SolidColorBrush(Colors.Silver);
                    //    rect.StrokeThickness = 2;
                    //    rect.Width = 8;
                    //    rect.Height = 8;
                    //    rect.RadiusX = 10;
                    //    rect.RadiusY = 10;
                    //    Carrier.Children.Add(rect);
                    //}
                }
            }
        }

        private void Carrier_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
            Point p = e.GetPosition(Map); //点击的地方在Map中的坐标点
            //假如点击的地点不是障碍物
            if (Matrix[(int)(p.X / GridSize), (int)(p.Y / GridSize)] != 0) {
                Spirit.Destination = p; //设置主角的最终移动目的地
                Spirit.Action = Actions.Run; //主角动作切换成跑步状态
                Spirit.IsAStarMoving = false; //非寻路模式
                NormalMoveTo(p); //两点间建立直线移动
            }
        }

        //换装
        private void ChangeEquipment(object sender, RoutedEventArgs e) {
            Spirit.Equipment[0] = Convert.ToInt32(comboBox1.SelectionBoxItem.ToString());
            Spirit.Equipment[1] = Convert.ToInt32(comboBox2.SelectionBoxItem.ToString());
            Spirit.Source = Super.EquipPart(Spirit.Equipment, Spirit.DirectionNum, Spirit.DirectionFrameNum, Spirit.TotalWidth, Spirit.TotalHeight, Spirit.SingleWidth, Spirit.SingleHeight);
        }
    }
}