在好例子网,分享、交流、成长!
您当前所在位置:首页C# 开发实例C#语言基础 → WPF 2D游戏第一集

WPF 2D游戏第一集

C#语言基础

下载此实例
  • 开发语言:C#
  • 实例大小:2.62M
  • 下载次数:77
  • 浏览次数:1171
  • 发布时间:2015-06-26
  • 实例类别:C#语言基础
  • 发 布 人:99个女友
  • 文件格式:.rar
  • 所需积分: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);
        }
    }
}

实例下载地址

WPF 2D游戏第一集

不能下载?内容有错? 点击这里报错 + 投诉 + 提问

好例子网口号:伸出你的我的手 — 分享

网友评论

发表评论

(您的评论需要经过审核才能显示)

查看所有0条评论>>

小贴士

感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。

  • 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
  • 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
  • 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
  • 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。

关于好例子网

本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明

;
报警