实例介绍
【实例截图】
【核心代码】
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); } } }
标签: 适合初学者图像处理
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论