首页 > 代码库 > 兵棋系列2----兵棋游戏中地图滑动和委托消息

兵棋系列2----兵棋游戏中地图滑动和委托消息

  前几天写了一个六边形阵列的算法,今天周末比较闲,下午没事就做了做兵棋的地图操作,一点一点的做吧,总会做好,毕竟我也经常玩各种棋,对做一个这类型的小游戏非常感兴趣。

 

     首先来解释下,下面要出现代码的操作。如上图,当鼠标指针移动到地图的四个边时,地图会自动左右上下滑动(地图比这个from要大很多,不这么做地图显示不完整了,不要跟我说用滚动条,那个给人感觉不好,这也是兵棋里不会缺少的操作吧),同时下面的消息框会记录鼠标的位置,这个消息框前期为我开发时显示一些测试信息用的,后期应该会把它改成一个功能区(部队参数、将领参数、环境参数、消息显示等等吧)

 

  下面把源代码放出来,懂得大大们可以指点下怎么做。

 


 

  C#开发中,控件和控件之间的消息传递有多种方式,我一般选择委托,毕竟灵活方便。以下是两种传递消息的模式,我选择了第一个,放弃了第二个;其实个人觉得第二个方法更优秀,它作为一个继承基类,可以很安全的把消息传递给它的上层类;第一种采用静态,优势是灵活方便,弊端是一个委托几乎只在一个功能上使用。

 

选择的传递消息模式

  1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using System.Text;  5   6 namespace UI  7 {  8     public enum MsgType  9     { 10         /// <summary> 11         /// 常规消息显示(黑色) 12         /// </summary> 13         Show, 14         /// <summary> 15         /// 提示信息(绿色) 16         /// </summary> 17         Info, 18         /// <summary> 19         /// 状态栏显示 20         /// </summary> 21         State, 22         /// <summary> 23         /// 错误消息,可识别,可控类型(蓝色) 24         /// </summary> 25         Error, 26         /// <summary> 27         /// 警告消息,程序异常,不可处理(红色) 28         /// </summary> 29         Warn, 30         /// <summary> 31         /// 他人发送消息的颜色 32         /// </summary> 33         OtherMessage, 34         /// <summary> 35         /// 本人发送消息的颜色 36         /// </summary> 37         OwnerMessage 38     } 39  40     class MsgEventArgs 41     { 42         private string _message; 43  44         public string Message 45         { 46             get { return _message; } 47             set { _message = value; } 48         } 49  50         private MsgType _type; 51  52         public MsgType Type 53         { 54             get { return _type; } 55             set { _type = value; } 56         } 57  58         public MsgEventArgs(string msg) 59         { 60             this._message = msg; 61  62             this._type = MsgType.Show; 63         } 64         public MsgEventArgs(string msg, MsgType type) 65         { 66             this._message = msg; 67             this._type = type; 68         } 69     } 70  71     class MsgEvnet 72     { 73         public delegate void MsgEvent(object sender, MsgEventArgs msg); 74         public static event MsgEvent msgEvent; 75  76         public static void SendMsg(string msg) 77         { 78             if (MsgEvnet.msgEvent != null) 79             { 80                 MsgEvnet.msgEvent(null, new MsgEventArgs(msg)); 81             } 82         } 83  84         public static void SendMsg(string msg, MsgType type) 85         { 86             if (MsgEvnet.msgEvent != null) 87             { 88                 MsgEvnet.msgEvent(null, new MsgEventArgs(msg, type)); 89             } 90         } 91  92         public static void SendMsg(object sender, string msg) 93         { 94             if (MsgEvnet.msgEvent != null) 95             { 96                 MsgEvnet.msgEvent(sender, new MsgEventArgs(msg)); 97             } 98         } 99 100         public static void SendMsg(object sender, string msg, MsgType type)101         {102             if (MsgEvnet.msgEvent != null)103             {104                 MsgEvnet.msgEvent(sender, new MsgEventArgs(msg, type));105             }106         }107     }108 }
消息委托类

 

放弃的传递消息模式

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5  6 namespace UI 7 { 8     public enum MsgType 9     {10         /// <summary>11         /// 常规消息显示(黑色)12         /// </summary>13         Show,14         /// <summary>15         /// 提示信息(绿色)16         /// </summary>17         Info,18         /// <summary>19         /// 状态栏显示20         /// </summary>21         State,22         /// <summary>23         /// 错误消息,可识别,可控类型(蓝色)24         /// </summary>25         Error,26         /// <summary>27         /// 警告消息,程序异常,不可处理(红色)28         /// </summary>29         Warn,30         /// <summary>31         /// 他人发送消息的颜色32         /// </summary>33         OtherMessage,34         /// <summary>35         /// 本人发送消息的颜色36         /// </summary>37         OwnerMessage38     }39 40     public class MsgEventArgs : EventArgs41     {42         public string Message;43         public MsgType Type;44 45         public MsgEventArgs(string msg)46         {47             this.Message = msg;48 49             this.Type = MsgType.Show;50         }51         public MsgEventArgs(string msg, MsgType type)52         {53             this.Message = msg;54             this.Type = type;55         }56     }57 58     public class MsgEvent59     {60         public event EventHandler<MsgEventArgs> msgEvent;61 62         public void SendMsg(string msg)63         {64             if (this.msgEvent != null)65             {66                 this.msgEvent(this, new MsgEventArgs(msg));67             }68         }69 70         public void SendMsg(string msg, MsgType type)71         {72             if (this.msgEvent != null)73             {74                 this.msgEvent(this, new MsgEventArgs(msg, type));75             }76         }77     }78 }
放弃的消息传递模式

 


 

  下面这段代码之前放出来过(http://www.cnblogs.com/preacher/p/4105810.html),做了几点修改,计算的方式:根据每个正六边形的中心点,计算出下三边的相对位置然后绘制下三边。以下算法中,把之前的基类Control改为了Label,主要方便控件透明,Control为基类是不支持控件透明。

六边形阵列绘制算法

  1 using System;  2 using System.Drawing.Drawing2D;  3 using System.Drawing;  4 using System.Windows.Forms;  5 using System.Collections.Generic;  6   7 namespace UI.Controls  8 {  9     public class SixSidesControl : Label 10     { 11         double G3 = Math.Sin(60 * Math.PI / 180);//二分之根号三 12         private int m_sideLength = 20; 13  14         public int SideLength 15         { 16             get { return m_sideLength; } 17             set 18             { 19                 m_sideLength = value; 20                 Invalidate(); 21             } 22         } 23  24  25         private float m_lineThickness = 1; 26  27         public float LineThickness 28         { 29             get { return m_lineThickness; } 30             set 31             { 32                 m_lineThickness = value; 33                 Invalidate(); 34             } 35         } 36  37  38         private Color m_lineColor = Color.Black; 39  40         public Color LineColor 41         { 42             get { return m_lineColor; } 43             set 44             { 45                 m_lineColor = value; 46                 Invalidate(); 47             } 48         } 49  50         public SixSidesControl() 51         { 52             SetStyle(ControlStyles.UserPaint, true); 53             SetStyle(ControlStyles.AllPaintingInWmPaint, true); 54             SetStyle(ControlStyles.DoubleBuffer, true); 55         } 56  57         protected override void OnPaint(PaintEventArgs pe) 58         { 59             //横线,三被的边长 60             //纵线,根号三倍的边长 61             List<float> xList = new List<float>(); 62             List<float> yList = new List<float>(); 63  64             int maxx = this.Width / (3 * m_sideLength); 65             int maxy = (int)(this.Height / (G3 * m_sideLength)); 66  67             for (int y = -1; y <= maxy; y++) 68             { 69                 float curHeight =(float)( y * G3 * m_sideLength); 70                 for (int x =-1; x <= maxx; x++) 71                 { 72                     float curWidth; 73                     if (y % 2 == 0) 74                         curWidth = (float)(x * 3 * m_sideLength); 75                     else 76                         curWidth = (float)((x * 3 + 1.5) * m_sideLength); 77  78                     yList.Add(curHeight); 79                     xList.Add(curWidth); 80                 } 81             } 82  83             using (Pen pen = new Pen(new SolidBrush(m_lineColor), m_lineThickness)) 84             { 85                 pe.Graphics.SmoothingMode = SmoothingMode.HighQuality; 86                 pen.StartCap = LineCap.Round; 87                 pen.EndCap = LineCap.Round; 88  89                 OnPaint(pen, pe, xList.ToArray(), yList.ToArray()); 90             } 91  92             base.OnPaint(pe); 93         } 94  95         private void OnPaint(Pen pen, PaintEventArgs pe, float[] x, float[] y) 96         { 97             for (int i = 0; i < x.Length; i++) 98             { 99                 //9点方向的点100                 float px1 = (float)(x[i] - m_sideLength);101                 float py1 = (float)(y[i]);102 103                 //3点方向的点104                 float px2 = (float)(x[i] + m_sideLength);105                 float py2 = (float)(y[i]);106 107                 //5点方向的点108                 float px3 = (float)(x[i] + 0.5 * m_sideLength);109                 float py3 = (float)(y[i] + G3 * m_sideLength);110 111                 //7点方向的点112                 float px4 = (float)(x[i] - 0.5 * m_sideLength);113                 float py4 = (float)(y[i] + G3 * m_sideLength);114 115                 pe.Graphics.DrawLines(pen, new PointF[]116                     {   117                         new PointF(px2, py2),118                         new PointF(px3, py3), 119                         new PointF(px4, py4),120                         new PointF(px1, py1)121                     });122             }123         }124     }125 }
六边形阵列控件

 


 

   下面这段代码主要控制鼠标操作的事件,以及通过委托把消息传递出去。当鼠标指针靠近控件边缘并在1/8的相对区域内,会触发滑动地图的事件。

兵棋地图控件

  1 using System;  2 using System.Collections.Generic;  3 using System.ComponentModel;  4 using System.Drawing;  5 using System.Data;  6 using System.Linq;  7 using System.Text;  8 using System.Windows.Forms;  9 using UI.Properties; 10 using System.Threading; 11  12 namespace UI.Controls 13 { 14     public class MyMap : Panel 15     { 16         SixSidesControl ctl = null; 17  18         readonly int _movePx = 10; 19  20         public MyMap() 21         { 22             ctl = new SixSidesControl(); 23             ctl.BackgroundImage = Resources.dt; 24             ctl.BackgroundImageLayout = ImageLayout.Stretch; 25             ctl.Size = new Size((int)(1024 * 2), (int)(600 * 2));//设置地图大小 26             ctl.LineThickness = 2;//线够不够胖 27             ctl.LineColor = Color.Gray;//线的颜色够不够深 28             ctl.SideLength = 25;//线的边够不够长 29             this.Controls.Add(ctl); 30             this.AutoScroll = false;//是否开启滚动条 31             this.BackColor = Color.Blue; 32  33             ctl.MouseMove += new MouseEventHandler(ctl_MouseMove); 34             this.MouseMove += new MouseEventHandler(MyMap_MouseMove); 35         } 36  37         void ctl_MouseMove(object sender, MouseEventArgs e) 38         { 39             MyMap_MouseMove(sender, new MouseEventArgs(e.Button, e.Clicks, e.X + ctl.Location.X, e.Y + ctl.Location.Y, e.Delta)); 40         } 41  42         void MyMap_MouseMove(object sender, MouseEventArgs e) 43         { 44             int mx = e.X; 45             int my = e.Y; 46  47             if (mx > 0 && my > 0 && mx < this.Width && my < this.Height) 48             { 49                 int x = this.Width / 8; 50                 int y = this.Height / 8; 51                 int x2 = this.Width - x; 52                 int y2 = this.Height - y; 53  54                 if (mx > x && my > y && mx < x2 && my < y2) 55                     return; 56  57                 if (mx < x && my < y) 58                 { 59                     MoveMap(_movePx, _movePx); 60                     MsgEvnet.SendMsg("左上移动,鼠标位置:(" + mx + "," + my + ")"); 61                 } 62                 else if (mx < x && my > y && my < y2) 63                 { 64                     MoveMap(_movePx, 0); 65                     MsgEvnet.SendMsg("向左移动,鼠标位置:(" + mx + "," + my + ")"); 66                 } 67                 else if (mx < x && my > y2) 68                 { 69                     MoveMap(_movePx, -_movePx); 70                     MsgEvnet.SendMsg("左下移动,鼠标位置:(" + mx + "," + my + ")"); 71                 } 72                 else if (mx > x && mx < x2 && my < y) 73                 { 74                     MoveMap(0, _movePx); 75                     MsgEvnet.SendMsg("向上移动,鼠标位置:(" + mx + "," + my + ")"); 76                 } 77                 else if (mx > x && mx < x2 && my > y2) 78                 { 79                     MoveMap(0, -_movePx); 80                     MsgEvnet.SendMsg("向下移动,鼠标位置:(" + mx + "," + my + ")"); 81                 } 82                 else if (mx > x2 && my < y) 83                 { 84                     MoveMap(-_movePx, _movePx); 85                     MsgEvnet.SendMsg("右上移动,鼠标位置:(" + mx + "," + my + ")"); 86                 } 87                 else if (mx > x2 && my > y && my < y2) 88                 { 89                     MoveMap(-_movePx, 0); 90                     MsgEvnet.SendMsg("向右移动,鼠标位置:(" + mx + "," + my + ")"); 91                 } 92                 else if (mx > x2 && my > y2) 93                 { 94                     MoveMap(-_movePx, -_movePx); 95                     MsgEvnet.SendMsg("右下移动,鼠标位置:(" + mx + "," + my + ")"); 96                 } 97             } 98         } 99 100         void MoveMap(int x, int y)101         {102             int nx = Math.Min(Math.Max(this.Width - ctl.Width, ctl.Location.X + x), 0);103             int ny = Math.Min(Math.Max(this.Height - ctl.Height, ctl.Location.Y + y), 0);104 105             if (ctl.Location.X == nx && ny == ctl.Location.Y)106                 return;107 108             ctl.Location = new Point(nx, ny);109 110             Thread.Sleep(50);111         }112 113         ~MyMap()114         { 115         116         }117     }118 }
兵棋地图

 


 

  from窗体控件里面的东西相对来说比较简单了,主要是把通过委托的消息展示下,没什么难度,把设计器和后台代码合并了。

 form窗体控件

  1 using System;  2 using System.Collections.Generic;  3 using System.ComponentModel;  4 using System.Data;  5 using System.Drawing;  6 using System.Linq;  7 using System.Text;  8 using System.Windows.Forms;  9  10 namespace UI 11 { 12     public partial class frmMap : Form 13     { 14         public frmMap() 15         { 16             InitializeComponent(); 17  18             MsgEvnet.msgEvent += (s, e) => { AppendText(this.rtxShowMsg, e); }; 19         } 20  21         private void AppendText(RichTextBox tb, MsgEventArgs e) 22         { 23             if (!this.InvokeRequired) 24             { 25                 Color color = Color.Black; 26                 switch (e.Type) 27                 { 28                     case MsgType.Info: 29                         color = Color.Green; 30                         break; 31                     case MsgType.Error: 32                         color = Color.Blue; 33                         break; 34                     case MsgType.Warn: 35                         color = Color.Red; 36                         break; 37                     case MsgType.OtherMessage: 38                         color = Color.DarkSeaGreen; 39                         break; 40                     case MsgType.OwnerMessage: 41                         color = Color.DarkSlateBlue; 42                         break; 43                 } 44                 tb.SelectionColor = color; 45                 tb.AppendText(e.Message + Environment.NewLine); 46             } 47             else 48             { 49                 tb.Invoke(new MethodInvoker(delegate { AppendText(tb, e); })); 50             } 51         } 52  53  54         private System.ComponentModel.IContainer components = null; 55  56         protected override void Dispose(bool disposing) 57         { 58             if (disposing && (components != null)) 59             { 60                 components.Dispose(); 61             } 62             base.Dispose(disposing); 63         } 64  65         private void InitializeComponent() 66         { 67             this.rtxShowMsg = new System.Windows.Forms.RichTextBox(); 68             this.myMap1 = new UI.Controls.MyMap(); 69             this.SuspendLayout(); 70             //  71             // rtxShowMsg 72             //  73             this.rtxShowMsg.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 74                         | System.Windows.Forms.AnchorStyles.Right))); 75             this.rtxShowMsg.Location = new System.Drawing.Point(0, 484); 76             this.rtxShowMsg.Name = "rtxShowMsg"; 77             this.rtxShowMsg.Size = new System.Drawing.Size(767, 62); 78             this.rtxShowMsg.TabIndex = 2; 79             this.rtxShowMsg.Text = ""; 80             //  81             // myMap1 82             //  83             this.myMap1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 84                         | System.Windows.Forms.AnchorStyles.Left) 85                         | System.Windows.Forms.AnchorStyles.Right))); 86             this.myMap1.BackColor = System.Drawing.Color.Blue; 87             this.myMap1.Location = new System.Drawing.Point(0, 2); 88             this.myMap1.Name = "myMap1"; 89             this.myMap1.Size = new System.Drawing.Size(767, 476); 90             this.myMap1.TabIndex = 3; 91             //  92             // frmMap 93             //  94             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 95             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 96             this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; 97             this.ClientSize = new System.Drawing.Size(767, 547); 98             this.Controls.Add(this.myMap1); 99             this.Controls.Add(this.rtxShowMsg);100             this.Name = "frmMap";101             this.Text = "frmMap";102             this.ResumeLayout(false);103 104         }105 106         private System.Windows.Forms.RichTextBox rtxShowMsg;107         private UI.Controls.MyMap myMap1;108     }109 }
from窗体

 


 

  时间有限,篇幅有限,今天下午就敲了这么多,下次继续。(不过上午把设计文档写好了,按照步骤一点点的做吧)

  这几段代码手打后没详细测试,可能会有问题,欢迎斧正。

 

差点忘记了,背景图片用的这个:

 

兵棋系列2----兵棋游戏中地图滑动和委托消息