• WPF游戏摘记地图编辑器(1)


    一、前言

    最近看了这么多的博客文章,发现些博文的好处,情不自禁也准备写点,不是什么知识分享,就自己那点墨水,我知道,怕拿出来还误人子弟呢,而且都是别人的东西呢,也就不借花献佛了,呵呵:)先这个WPF游戏系列主要1:是给自己巩固巩固知识,学海无涯啊,怎么学都学不完呢,那就把已经学会的好好整理整理;2:做个学习笔记,以后相关知识点查找起来也方便呢。嗯差不多了,先救这个目的吧,下面进入正题了哦:)

    ----------------------------------------------------华丽的分割线---------------------------------------------------------

    今天的笔记主题是:地图编辑器,给他个红色加粗,醒目啊,有木有。

    二、需求

    作为一款正真的游戏,地图编辑器很重要啊,有木有。本地图编辑器主要作用是实现游戏里面地图的逻辑数组,怎么说呢,简单点吧,我举个例子先哦。大家都知道游戏里面的地图我们看到的是一张图片,可是机器哪管你什么图片怎么漂亮啊,怎么华丽啊,他不管,他只知道数据。所以跟这个死板的家伙交流就不用多少辞藻了,直接把,我就这么告诉他,我就指着一个数组说,这是一张很华丽,很浪漫的地图,然后她就相信了。。。呵呵,开个玩笑先。也就是我们可以用一个数组来表示地图的数据结构,然后我们规定1是通的,0时不通,当然你也可以用其他数字或者字母啊,没事的,只要你不嫌麻烦,你的机器也不嫌麻烦的。

    简单的,代码不不给你了,挺占地方的,听听就行,不明白看源码吧。 原理很简单,但是有个问题,如果图片的数据很少,想五子棋的地图,直接在地图数据上编辑还是挺轻松的,但是我们眼光放大点,像某些网游的地图,很大、很多种,像某些竞技类游戏,类似LOL啊,就一张,很大,试想像,在一大堆0、1的数组上编辑有效的地图数据。。。哦,想想就头大了,不是我多说,看到那么庞大的数字,你想死的心都有。所以地图编辑器应声而出。呼,终于始出来啊:)本地图编辑器的作用是可编辑任何地图,只要你是图片,然后直接在图片上面创障碍物,进而设置开始点和终点进行自动寻路(是A*算法哦,莫心动)模拟人物运动,验证无误后,导出障碍物数据,接下来你就可以直接使用该障碍物数据构建完整的游戏。另外,还可以导入上次构建的障碍物数据进行再次增改,那样就可以应付大型的复杂的地图了,很人性呢有木有。

    二。原理

    先看程序首页吧:

    然后就是原理了,先小题一下,我是用两个Grid来布个小局的。左边是两个ScrollViewer,因为ScrollViewer可以有横、竖滑竿。给底层的ScrollViewer的Content添加个Image来显示地图图片,

    Xaml:

    <ScrollViewer Grid.Row="0" Grid.Column="0"  HorizontalAlignment="Stretch"  Name="MapscrollViewer" VerticalAlignment="Stretch" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" >

                <ScrollViewer.Content>

                    <Image Name="Map"></Image>

                </ScrollViewer.Content>

            </ScrollViewer>

    后台:

    知识点1:用OpenFileDialog导入文件的方法

    OpenFileDialog loadMap = new OpenFileDialog()

                {

                    CheckFileExists = true,

                    CheckPathExists = true,

                    Multiselect = false,

                    Filter = "图像文件(*.jpg,*.png)|*.jpg;*.png",

     

                };

                loadMap.FileOk += new System.ComponentModel.CancelEventHandler(loadMap_FileOk);

                loadMap.ShowDialog();

     

    void loadMap_FileOk(object sender, System.ComponentModel.CancelEventArgs e)

            {

                mapName = (sender as OpenFileDialog).FileName;

                Map.Source = new BitmapImage(new Uri((sender as OpenFileDialog).FileName, UriKind.Absolute));

              

            }

    上面一层是逻辑层,往其content里面动态添加(就是写代码了)一个Grid,通过往这个Grid里面添加ColumnDefinition和RowDefinition实现网格,使Grid的ShowGridLines为True还是使网格显示出来。

    知识点二:Grid做网格的用法

    grid = new Grid()

                {

                    ShowGridLines = IsShowGrid.IsChecked.Value,

                    Width = width,

                    Height = height,

                };

               

                int gridwidth ;

                if (!int.TryParse(gridWidth.Text,out gridwidth))

                {

                    MessageBox.Show("请?输º?入¨?数ºy字Á?!ê?");

                    return;

                }          

                for (int x = 0; x < grid.Width/gridwidth; x++)

                {

                    ColumnDefinition col = new ColumnDefinition()

                    {

                        Width = new GridLength(gridwidth),

                    };

                    grid.ColumnDefinitions.Add(col);

                }

                int gridheight = int.Parse(gridHeight.Text);

                if (!int.TryParse(gridHeight.Text,out gridheight))

                {

                    MessageBox.Show("请?输º?入¨?数ºy字Á?!ê?");

                    return;

                }

                for (int i = 0; i < grid.Height/gridheight; i++)

                {

                    RowDefinition row = new RowDefinition()

                    {

                        Height = new GridLength(gridheight),

                    };

                    grid.RowDefinitions.Add(row);

                }

    ShowGridLines可是个好属性啊,设为True就能将本来用来布局的RowDefinitions和ColumnDefinitions都显示出来。

    最后是两个ScrollViewer绑在一起共进退,

    知识点3:两个ScrollViewer的绑定

    private void ObstructionViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)

            {

                ScrollViewer scrollviewer = sender as ScrollViewer;

                MapscrollViewer.ScrollToVerticalOffset(scrollviewer.VerticalOffset);

                MapscrollViewer.ScrollToHorizontalOffset(scrollviewer.HorizontalOffset);

            }

    这样,你就可以在上面那个ScrollViewer也就是ObstructionViewer注册个点击事件,初始化个地图数据数组,

    Matrix = new byte[256, 256];

                for (int i = 0; i < Matrix.GetUpperBound(1); i++)

                {

                    for (int x = 0; x < Matrix.GetUpperBound(0); x++)

                    {

                        Matrix[x,i] = 1;

                    }

                }

    通过点击设置数组的值,

    Point p = e.GetPosition(ObstructionViewer);

    SetObstructionMatrix((int)p.X / gridwidth, (int)p.Y / gridheight, (byte)0);

    并在上面画个矩形显示出来。

    Rectangle rect = new Rectangle()

                    {

                        Width = gridwidth,

                        Height = gridheight,

                        Fill = new SolidColorBrush(Colors.White),

                    };

                    grid.Children.Add(rect);

                    grid.RegisterName("rect" + x + "_" + y, rect);

                    rect.SetValue(Grid.ColumnProperty, x);

                    rect.SetValue(Grid.RowProperty, y);

    知识点4:UiElement的注册和管理

    grid.RegisterName("rect" + x + "_" + y, rect);

    通过向Grid注册个名字,就可以用这个名字来管理了,

    Rectangle rect = grid.FindName("rect" + x + "_" + y) as Rectangle;

                    grid.UnregisterName("rect" + x + "_" + y);

                    grid.Children.Remove(rect);

    我这里用来取消方块,很好用,但是这个注册并不是靠Grid来管理的,所以你要全部清除注册不能靠注销Grid来实现,我是手动实现的,

    for (int y = 0; y < Matrix.GetUpperBound(1); y++)

                    {

                        for (int x = 0; x < Matrix.GetUpperBound(0); x++)

                        {

                            if (Matrix[x,y]==0)

                            {

                                grid.UnregisterName("rect" + x + "_" + y);

                            }

                        }

                    }

    知识点5:A*算法的使用

    我这里是用来某位大神封装好的算法,所以只要调用就行。先导入引用,

    初始化,

    IPathFinder pathFinder;

            string start, end;

    写了个方法来调用,使用A*算法得到路径点集并画个方块显示一条龙服务,

    /// <summary>

            /// 利¤?用®?A*寻¡ã路¡¤测a试º?障?碍ã-物?层?的Ì?可¨¦用®?性?

            /// </summary>

            private void FindRoadTest()

            {

                //无T效¡ì性?判D断?

                if (grid==null||start==""||end=="")

                {

                    return;

                }

                //得Ì?到Ì?起e点Ì? ,ê?终?点Ì?

                string[] str = start.Split('_');

                int start_x = Convert.ToInt32(str[1]);

                int start_y = Convert.ToInt32(str[2]);

                str = end.Split('_');

                int end_x = Convert.ToInt32(str[1]);

                int end_y = Convert.ToInt32(str[2]);

                //进?入¨?正y文?

                pathFinder = new PathFinderFast(Matrix);

               

                List<PathFinderNode> path=pathFinder.FindPath(new System.Drawing.Point(start_x,start_y),new System.Drawing.Point(end_x,end_y));

     

                if (path==null)

                {

                    MessageBox.Show("路¡¤径?不?存ä?在¨²!ê?");

                }

                else

                {

                    //路¡¤径?存ä?在¨²

                    for (int i = 0; i < path.Count; i++)

                    {

                        PathFinderNode node = path.ElementAt(i);

     

                        Rectangle rect = new Rectangle();

                        rect = new Rectangle()

                        {

                            Width = gridwidth,

                            Height = gridheight,

                            RadiusX = 5,

                            RadiusY = 5,

                            Fill=new SolidColorBrush(Colors.Red),

                        };

                        grid.Children.Add(rect);

                       

                        rect.SetValue(Grid.ColumnProperty, node.X);

                        rect.SetValue(Grid.RowProperty, node.Y);

                    }

                }

            }

    知识点6,Linq的用法(一些)

    下面介绍一些LInq在我的程序的用法,挺简单的,但是很好用。

    导入xml文件,

    XElement myEle = XElement.Load("Output.xml");

    得到自身或者任意子节点,

    XElement myRoot = myEle.DescendantsAndSelf("Items").Single();

    创建个新的XElement,并附属性和值,放入MyRoot并保持的指定路径,

    XElement newEle = new XElement("Item");

    newEle.SetAttributeValue("ID", mapName);

    myRoot.Add(newEle);

    myEle.Save(savepath);

    小结

    其他的自己看源码,自己理解好了。源码

  • 相关阅读:
    gdb typeid 详解
    make报错
    期末作业验收
    个人作业——软件工程实践总结作业
    原型设计(结对第一次)
    团队展示(团队)
    第二次作业——个人项目实战(sudoku)
    软件工程实践第一次作业--准备
    C++第一次课堂作业 circle
    第四次作业 计算器第二部分(未完)
  • 原文地址:https://www.cnblogs.com/haichao/p/2598614.html
Copyright © 2020-2023  润新知