zoukankan      html  css  js  c++  java
  • x01.Game.MapEditor: 地图编辑器

    1.游戏编程,需要一个地图编辑器。站在前人肩上,自己写一个,倒也不难。其效果图如下:

               

      只需从左下的 Tiles 面板中选择一个 Tile,在右边的面板中绘制即可。保存为同名的两个文件 file.bmp, file.xml。打开时选择 file.xml 文件。

    2.界面设计不详述,可在效果图上点击右键,将其另存为桌面上作为参照。其完整代码如下:

    MainForm
        public partial class MainForm : Form, IMessageFilter
        {
            int paletteColumes = 5, paletteSelectedIndex = 0;
            readonly int mapSize = 100; //for map tiles
            int mouseX = 0, mouseY = 0, boxCol = 0, boxRow = 0;
    
            Tile[] tiles;
            Bitmap bmpMap, bmpTile;
            Graphics graphMap, graphTile;
            BoxInfo boxSelected;  // editing selected box in the map
    
            public MainForm()
            {
                InitializeComponent();
    
                Application.AddMessageFilter(this);
    
                tiles = new Tile[mapSize * mapSize];
    
                bmpMap = new Bitmap(picMap.Size.Width, picMap.Size.Height);
                picMap.Image = bmpMap;
                graphMap = Graphics.FromImage(bmpMap);
    
                bmpTile = new Bitmap(picSelected.Size.Width, picSelected.Size.Height);
                picSelected.Image = bmpTile;
                graphTile = Graphics.FromImage(bmpTile);
    
                // Init Events
                picMap.MouseClick += new MouseEventHandler(picMap_MouseClick);
                picMap.MouseMove += new MouseEventHandler(picMap_MouseMove);
                picPalette.MouseClick += new MouseEventHandler(picPalette_MouseClick);
    
                dlgOpen.Filter = "XML Files(*.xml)|*.xml|All Files(*.*)|*.*";
                miNew.Click += new EventHandler(miNew_Click);
                miOpen.Click += new EventHandler(miOpen_Click);
                miSave.Click += new EventHandler(miSave_Click);
                miExit.Click += (a, b) => Close();
    
                radioEditMode.CheckedChanged += new EventHandler(radioEditMode_CheckedChanged);
            }
    
            void radioEditMode_CheckedChanged(object sender, EventArgs e)
            {
                if (radioEditMode.Checked == false)
                {
                    int i = boxSelected.Index;
                    tiles[i].TileId = Convert.ToInt32(txtTileId.Text);
                    tiles[i].Data1 = txtData1.Text;
                    tiles[i].Data2 = txtData2.Text;
                    tiles[i].Data3 = txtData3.Text;
                    tiles[i].Data4 = txtData4.Text;
                    tiles[i].Collision = chkCollision.Checked;
                    tiles[i].Portal = chkPortal.Checked;
                    tiles[i].PortalX = Convert.ToInt32(txtPortalX.Text);
                    tiles[i].PortalY = Convert.ToInt32(txtPortalY.Text);
                    tiles[i].PortalFile = txtPortalFile.Text;
    
                    paletteSelectedIndex = tiles[i].TileId;
                    SetSelectedTile();
    
                    boxCol = boxSelected.Col;
                    boxRow = boxSelected.Row;
                    DrawSelectedTile();
                }
            }
    
            void picPalette_MouseClick(object sender, MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Left)
                {
                    paletteSelectedIndex = e.X / 33 + e.Y / 33 * paletteColumes;
                    SetSelectedTile();
                }
            }
    
            void miNew_Click(object sender, EventArgs e)
            {
                for (int i = 0; i < mapSize * mapSize; i++)
                {
                    tiles[i].TileId = 0;
                    tiles[i].Data1 = string.Empty;
                    tiles[i].Data2 = string.Empty;
                    tiles[i].Data3 = string.Empty;
                    tiles[i].Data4 = string.Empty;
                    tiles[i].Collision = false;
                    tiles[i].Portal = false;
                    tiles[i].PortalFile = string.Empty;
                    tiles[i].PortalX = 0;
                    tiles[i].PortalY = 0;
                }
                RedrawMap();
            }
            void miSave_Click(object sender, EventArgs e)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("<?xml version=\"1.0\" standalone=\"yes\"?>");
                sb.AppendLine("<tiles>");
                for (int i = 0; i < mapSize * mapSize; i++)
                {
    
                    sb.AppendLine(" <tile>");
                    sb.AppendLine("  <tileId>" + tiles[i].TileId.ToString() + "</tileId>");
                    sb.AppendLine("  <data1>" + tiles[i].Data1 + "</data1>");
                    sb.AppendLine("  <data2>" + tiles[i].Data2 + "</data2>");
                    sb.AppendLine("  <data3>" + tiles[i].Data3 + "</data3>");
                    sb.AppendLine("  <data4>" + tiles[i].Data4 + "</data4>");
                    sb.AppendLine("  <collision>" + (tiles[i].Collision ? "true" : "false") + "</collision>");
                    sb.AppendLine("  <portal>" + (tiles[i].Portal ? "true" : "false") + "</portal>");
                    sb.AppendLine("  <portalX>" + tiles[i].PortalX.ToString() + "</portalX>");
                    sb.AppendLine("  <portalY>" + tiles[i].PortalY.ToString() + "</portalY>");
                    sb.AppendLine("  <portalFile>" + tiles[i].PortalFile + "</portalFile>");
                    sb.AppendLine(" </tile>");
                }
                sb.AppendLine("</tiles>");
    
                if (dlgSave.ShowDialog() == DialogResult.OK)
                {
                    File.WriteAllText(dlgSave.FileName + ".xml", sb.ToString());
                    bmpMap.Save(dlgSave.FileName + ".bmp", ImageFormat.Bmp);
                }
            }
            void miOpen_Click(object sender, EventArgs e)
            {
                string file = string.Empty;
                if (dlgOpen.ShowDialog() == DialogResult.OK)
                {
                    file = dlgOpen.FileName;
                }
    
                try
                {
                    XmlDocument doc = new XmlDocument();
                    doc.Load(file);
                    XmlNodeList nodes = doc.GetElementsByTagName("tile");
    
                    int i = 0;
                    foreach (XmlElement node in nodes)
                    {
                        tiles[i].TileId = Convert.ToInt32(node.GetElementsByTagName("tileId")[0].InnerText);
                        tiles[i].Data1 = node.GetElementsByTagName("data1")[0].InnerText;
                        tiles[i].Data2 = node.GetElementsByTagName("data2")[0].InnerText;
                        tiles[i].Data3 = node.GetElementsByTagName("data3")[0].InnerText;
                        tiles[i].Data4 = node.GetElementsByTagName("data4")[0].InnerText;
                        tiles[i].Collision = Convert.ToBoolean(node.GetElementsByTagName("collision")[0].InnerText);
                        tiles[i].Portal = Convert.ToBoolean(node.GetElementsByTagName("portal")[0].InnerText);
                        tiles[i].PortalFile = node.GetElementsByTagName("portalFile")[0].InnerText;
                        tiles[i].PortalX = Convert.ToInt32(node.GetElementsByTagName("portalX")[0].InnerText);
                        tiles[i].PortalY = Convert.ToInt32(node.GetElementsByTagName("portalY")[0].InnerText);
                        i++;
                    }
    
                    RedrawMap();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
    
            void picMap_MouseMove(object sender, MouseEventArgs e)
            {
                boxCol = e.X / 32;
                boxRow = e.Y / 32;
                mouseX = e.X;
                mouseY = e.Y;
    
                lblCursor.Text = "Map Cursor: x,y = " + e.X.ToString() + "," + e.Y.ToString();
                if (radioDrawMode.Checked)
                {
                    Tile tile = tiles[boxRow * mapSize + boxCol];
                    txtTileId.Text = tile.TileId.ToString();
                    txtData1.Text = tile.Data1;
                    txtData2.Text = tile.Data2;
                    txtData3.Text = tile.Data3;
                    txtData4.Text = tile.Data4;
                    chkCollision.Checked = tile.Collision;
                    chkPortal.Checked = tile.Portal;
                    txtPortalX.Text = tile.PortalX.ToString();
                    txtPortalY.Text = tile.PortalY.ToString();
                    txtPortalFile.Text = tile.PortalFile;
    
                    picMap_MouseClick(sender, e);
                }
            }
            /// <summary>
            /// 如是 Draw Mode,鼠标左键绘制 Tile 到 map 上,右键清除;
            /// 否则,绘制 box 到 map 上。
            /// </summary>
            void picMap_MouseClick(object sender, MouseEventArgs e)
            {
                switch (e.Button)
                {
                    case MouseButtons.Left:
                        if (radioDrawMode.Checked)
                        {
                            DrawSelectedTile();
                        }
                        else
                        {
                            //show selected tile for editing
                            boxSelected.Col = boxCol;
                            boxSelected.Row = boxRow;
                            boxSelected.Index = boxRow * mapSize + boxCol;
    
                            Tile tile = tiles[boxSelected.Index];
                            txtTileId.Text = tile.TileId.ToString();
                            txtData1.Text = tile.Data1;
                            txtData2.Text = tile.Data2;
                            txtData3.Text = tile.Data3;
                            txtData4.Text = tile.Data4;
                            chkPortal.Checked = tile.Portal;
                            chkCollision.Checked = tile.Collision;
                            txtPortalX.Text = tile.PortalX.ToString();
                            txtPortalY.Text = tile.PortalY.ToString();
                            txtPortalFile.Text = tile.PortalFile;
    
                            DrawSelectedBox();
                        }
                        break;
                    case MouseButtons.Right:
                        if (radioDrawMode.Checked)
                        {
                            DrawTile(boxCol, boxRow, 0);    // erase
                        }
                        break;
                }
            }
            void DrawSelectedTile()
            {
                DrawTile(boxCol, boxRow, paletteSelectedIndex);
            }
            void DrawSelectedBox()
            {
                // Erase selected tile with old.
                //DrawTile(boxSelected.Col, boxSelected.Row, tiles[boxSelected.OldIndex].TileId);
    
                // Remember current tile
                //boxSelected.OldIndex = boxSelected.Index;
    
                int x = boxCol * 32;
                int y = boxRow * 32;
                Pen pen = new Pen(Color.DarkMagenta, 2);
                Rectangle rect = new Rectangle(x + 1, y + 1, 30, 30);
                graphMap.DrawRectangle(pen, rect);
    
                picMap.Image = bmpMap;
            }
    
    
            //[DllImport("user32.dll")]
            //public static extern IntPtr WindowFromPoint(Point point);
            //[DllImport("user32.dll")]
            //public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
            // Handle MouseWheel Message.
            public bool PreFilterMessage(ref Message m)
            {
                if (m.Msg == WinMessages.WM_MOUSEWHEEL)  //WM_MOUSEWHEEL = 0x020A
                {
                    Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
                    IntPtr hWnd = User32.WindowFromPoint(pos);
                    if (hWnd != IntPtr.Zero && hWnd != m.HWnd && Control.FromHandle(hWnd) != null)
                    {
                        User32.SendMessage(hWnd, m.Msg, m.WParam, m.LParam);
                        return true;
                    }
                }
                return false;
            }
            void SetSelectedTile()
            {
                int x = (paletteSelectedIndex % paletteColumes) * 33;
                int y = (paletteSelectedIndex / paletteColumes) * 33;
                var src = new Rectangle(x, y, 32, 32);
                var dest = new Rectangle(0, 0, 32, 32);
                graphTile.DrawImage(picPalette.Image, dest, src, GraphicsUnit.Pixel);
                picSelected.Image = bmpTile;
            }
            /// <summary>
            /// 在 picMap 中按指定的行、列绘制所选的 tile.
            /// </summary>
            void DrawTile(int col, int row, int tileId)
            {
                tiles[row * mapSize + col].TileId = tileId;
    
                int srcX = (tileId % paletteColumes) * 33;
                int srcY = (tileId / paletteColumes) * 33;
                int destX = col * 32;
    
                int destY = row * 32;
                var src = new Rectangle(srcX, srcY, 32, 32);
                var dest = new Rectangle(destX, destY, 32, 32);
                graphMap.DrawImage(picPalette.Image, dest, src, GraphicsUnit.Pixel);
    
                picMap.Image = bmpMap;
            }
            void RedrawMap()
            {
                for (int i = 0; i < mapSize * mapSize; i++)
                {
                    int col = i % mapSize;
                    int row = i / mapSize;
                    int tileId = tiles[i].TileId;
                    DrawTile(col, row, tileId);
                }
            }
        }
    
        struct Tile
        {
            public int TileId;  // equal palette index
            public string Data1, Data2, Data3, Data4;
            public bool Portal, Collision;
            public int PortalX, PortalY;
            public string PortalFile;
        }
    
        struct BoxInfo
        {
            public int Index, Col, Row; // all in the map
        }

    3.Picture 放在 Panel 中,使其有滚动效果。为方便操作,添加了鼠标滚轮的消息处理。即代码中的 IMessageFilter 接口实现。其中,用到两个Win32 API,见注释。实际使用,需将注释及 User32 前缀去掉,WM_* 也需用实际值替换。
    4.Tiles 选择面板用到的资源如下:

              

      同样可通过右键保存到桌面,以方便观看使用。

  • 相关阅读:
    java集合
    struts2的OGNL表达式
    struts2 result type
    struts2在Action中访问WEB资源
    03异或^
    02自加自减运算机制
    原码,补码,反码
    Java基础50题test10—自由落体
    Java基础50题test9—求完数
    Java基础50题test8—输入数字求和
  • 原文地址:https://www.cnblogs.com/china_x01/p/2499297.html
Copyright © 2011-2022 走看看