logo资料库

c#网络五子棋游戏模块.pdf

第1页 / 共55页
第2页 / 共55页
第3页 / 共55页
第4页 / 共55页
第5页 / 共55页
第6页 / 共55页
第7页 / 共55页
第8页 / 共55页
资料共55页,剩余部分请下载后查看
第 15 章 网络五子棋游戏模块 (Socket 编程+UDP 协议实现) 随着计算机信息技术的发展,网络游戏已成为人们生活中的重要组 成部分,由于网络游戏占用的资源比较大,易受到病毒的攻击,所以局 域网游戏受到众多游戏爱好者的亲睐。五子棋游戏因其简单的规则、漂 亮的界面,而深受广大玩家的喜爱,而对于初步探索网络编程的编程爱 好者来说,五子棋游戏因其规则简单而很受欢迎。本章将制作一个具有 游戏大厅和多人对话功能的网络五子棋游戏。通过本章的学习,读者能 够学到:  UDP 协议的使用  如何实现带图片的下拉列表  进入房间的指定座位  显示当前房间的人员信息列表  显示当前房间的人员信息  在对决窗体中下棋  判断五子棋的输赢情况  局域网互相发送信息
C#典型模块与项目实战大全 15.1 网络五子棋游戏模块概述 15.1.1 模块概述 网络五子棋游戏模块的主要实现目标如下:  操作简单方便、界面简洁美观;  在注册时设置注册人员的头像和性别;  进入某区的房间时,显示当前房间的人员信息;  进入和退出座位时,显示座位状态;  在对决双方的棋盘上显示棋子;  在下完棋子后,高亮度显示最后下的棋子;  按五子棋的规则判断对决双方的输赢;  在服务器端对人员的分数进行排序。 了解网络五子棋游戏模块的主要实现目标之后,接下来开始制作五子棋游戏,但在制 作之前,必须要有一个大体的思路。 制作网络五子棋游戏模块,首先需要创建两个 Windows 应用程序,分别用来作为客 户端和服务器端(即注册、登录、大厅及对决窗体),其中,客户端主要用于实现用户注 册、登录、发送信息和五子棋对决等功能;服务器端主要用于显示在线人员的状态,并作 为客户端向远程客户端发送信息的一个中转站。然后创建一个 Windows 类库,主要用于 记录传递信息的结构。图 15.1 所示为网络五子棋游戏模块的业务流程图。 2 图 15.1 网络五子棋游戏模块的业务流程图
第 15 章 网络五子棋游戏模块(Socket 编程+UDP 协议实现) 实 践 真 知 技巧 客户端与服务器端所使用的 UDP 协议是同一个协议,如果使用两个 UDP 协议进行传输,它们的程序集将不匹配,无法进行通信。 15.1.2 功能结构 网络五子棋游戏模块的功能结构如图 15.2 所示。 网络五子棋游戏模块 服务器端 客户端 开 启 服 务 停 止 服 务 查 看 分 数 排 名 用 户 注 册 系 统 登 录 显 示 人 员 列 表 进 入 指 定 座 位 五 子 棋 对 决 判 断 五 子 棋 输 赢 局 域 网 聊 天 增 加 \减 少 分 数 图 15.2 网络五子棋游戏模块的功能结构图 15.1.3 程序预览 网络五子棋游戏模块是由多个窗体组成,下面列出几个典型窗体。 服务器窗体如图 15.3 所示,该窗体主要用于控制 UDP 协议的开启和关闭。客户端注 册窗体如图 15.4 所示,该窗体主要用于注册用户,并将注册的信息发送给服务器端进行 记录。 图 15.3 服务器窗 图 15.4 客户端注册窗体 3
C#典型模块与项目实战大全 五子棋大厅窗体如图 15.5 所示,该窗体主要用于显示五子棋的房间人员情况及在线 用户信息。 对决窗体如图 15.6 所示,该窗体主要用于实现五子棋对决功能。 图 15.5 五子棋大厅窗体 图 15.6 对决窗体 15.2 关键技术 15.2.1 在下拉列表中绘制图片 4 本模块在对游戏用户进行注册时,为了便于在游戏中区分用户,自制了一个带有图片 的下拉列表,通过该列表用户可以随意设置头像,如图 15.7 所示。
第 15 章 网络五子棋游戏模块(Socket 编程+UDP 协议实现) 图 15.7 带有图片的下拉列表 在下拉列表中绘制图片是使用 ComboBox 控件和 GDI+技术来实现的,在 ComboBox 控件的列表项中绘制图片前要对 DrawMode 和 DropDownStyle 属性进行设置。下面对这两 个属性进行详细说明。 (1)DrawMode 属性。该属性用于获取或设置一个值,该值指示是由代码还是由操 作系统来处理列表中元素的绘制。 语法: public DrawMode DrawMode { get; set; } 说明:它的属性值为 DrawMode 枚举值之一,默认为 Normal。DrawMode 的枚举值 如表 15.1 所示。 表 15.1 DrawMode 的枚举值 枚 举 值 说 明 Normal 控件中的所有元素都由操作系统绘制,并且元素大小都相等 OwnerDrawFixed 控件中的所有元素都由手动绘制,并且元素大小都相等 OwnerDrawVariable 控件中的所有元素都由手动绘制,元素大小可能不相等 (2)DropDownStyle 属性。该属性用于确定用户能否在文本部分中输入新值以及列 表部分是否总显示。 语法: public ComboBoxStyle DropDownStyle { get; set; } 说明:它的属性值为 ComboBoxStyle 枚举值之一,默认为 DropDown。ComboBoxStyle 的枚举值如表 15.2 所示。 枚 举 值 DropDown DropDownList Simple 表 15.2 ComboBoxStyle 的枚举值 说 明 文本部分可编辑,用户必须单击箭头按钮来显示列表部分。这是默认样式 用户不能直接编辑文本部分,用户必须单击箭头按钮来显示列表部分 文本部分可编辑,列表部分总可见 在 ComboBox 控件的列表项中绘制图片,主要是在该控件的 DrawItem 事件中进行的, 该事件在 ComboBox 控件的可视方位更改时发生。 下面介绍在 ComboBox 控件中绘制图片的相关步骤。 (1)首先在窗体的 Shown(第一次显示)事件中设置 ComboBox 控件的 DrawMode 和 DropDownStyle 属性,使该控件的下拉项可以进行手动绘制,并且不能在文本部分输入 新值。代码如下: 5
C#典型模块与项目实战大全 private void F_SerSetup_Shown(object sender, EventArgs e) { comboBox_CPhoto.Items.Clear(); comboBox_CPhoto.DrawMode = DrawMode.OwnerDrawFixed;//所有元素是手动绘制的 comboBox_CPhoto.DropDownStyle = ComboBoxStyle.DropDownList; //根据绘制图片的个数,添加空的列表项 for (int i = 0; i < imageList1.Images.Count; i++) { comboBox_CPhoto.Items.Add(""); } } (2)然后在 ComboBox 控件的 DrawItem 事件中,将 ImageList 组件所存储的图片绘 制到下拉列表项中。代码如下: private void comboBox_CPhoto_DrawItem(object sender, DrawItemEventArgs e) { Graphics g = e.Graphics; Rectangle r = e.Bounds; Size imageSize = imageList1.ImageSize; if (e.Index >= 0) { string s = (string)comboBox_CPhoto.Items[e.Index]; StringFormat sf = new StringFormat(); sf.Alignment = StringAlignment.Near; //如果当前项有焦点或有键盘加速键 if (e.State == (DrawItemState.NoAccelerator | DrawItemState.NoFocusRect)) { imageList1.Draw(e.Graphics, r.Left, r.Top, e.Index); //绘制图像 e.DrawFocusRectangle(); //显示取得焦点时的虚线框 } else { e.Graphics.FillRectangle(new SolidBrush(Color.White), r); imageList1.Draw(e.Graphics, r.Left, r.Top, e.Index); e.DrawFocusRectangle(); } } } //设置文本的对齐方式 //设置各项的背景颜色 //绘制图片 //显示取得焦点时的虚线框 15.2.2 UDP 协议的使用 UDP(User Datagram Protocol)协议,即“用户数据报协议”,它是一种无连接协议, 在用该协议进行数据传输时,发送方只需要知道对方的 IP 地址和端口号就可以发送数 据,并不需要进行连接,当连接的远程主机端口号处于监听状态时,则 UDP 必须处于 连接状态。 使用 C#发送和接收 UDP 数据包主要用到 UdpClient 类的 Send 方法和 Receive 方法, 下面分别对它们进行介绍。 6 1.Send 方法 该方法将 UDP 数据报发送给指定的远程计算机,其语法格式如下: public int Send ( byte[] dgram , int bytes , IPEndPoint endPoint );
第 15 章 网络五子棋游戏模块(Socket 编程+UDP 协议实现) Send 方法的参数说明如表 15.3 所示。 表 15.3 Send 方法的参数说明 参 数 说 明 dgram bytes endPoint filePath 返回值 要发送的 UDP 数据文报(以字节数组表示) 数据文报中的字节数 一个 IPEndPoint,表示要将数据文报发送到的主机和端口 文件所在路径 返回已发送的字节数 下面使用 Send 方法向远程计算机发送消息,代码如下: byte[] Data = Encoding.Unicode.GetBytes(richTextBox1.Rtf); UdpClient server = new UdpClient(); IPAddress IP = IPAddress.Parse("192.168.1.230"); IPEndPoint receivePoint = new IPEndPoint(IP, 11000); server.Send(Data, Data.Length, receivePoint); 2.Receive 方法 该方法用于返回远程主机发送的 UDP 数据报,其语法格式如下: public byte [] Receive ( ref IPEndPoint remoteEP ) ; 说明:RemoteEP 表示一个 IPEndPoint 类的实例,表示网络中发送此数据包的节点。 它的返回值为一个 Byte 类型的数组,它包含数据报数据。 如果指定了远程计算机发送到本地计算机的端口号,可以通过监听本地端口号来实现 对数据的获取,下面就是通过监听本地计算机的端口号“11000”来获取信息的相关代码: UdpClient server = new UdpClient(); IPAddress IP = IPAddress.Parse("127.0.0.1"); IPEndPoint receivePoint = new IPEndPoint(IP, 11000); byte[] recData = server.Receive(ref receivePoint); 15.2.3 用 Socket 实现消息传递的必备条件 在刚开始编写网络五子棋游戏模块时,客户端和服务器端分别调用 GobangClass 类库 (主要是使用自定义控件 UDPSocket 实现局域网的通信),在客户端向服务器端发送消息 时,会弹出错误提示,具体提示为:无法找到程序集“GobangClass, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”。 那么,如何解决上面出现的这种问题呢?开发人员只需要同时将类库(主要是 UDP 协议)添加到客户端和服务器端的引用中,使客户端和服务器端调用同一个类库即可。 实 践 真 知 技巧 开发网络五子棋游戏模块时,为了便于对程序的编写和调试,将客户端解 7 决方案和类库都添加到了服务器端解决方案中。
C#典型模块与项目实战大全 15.2.4 自定义事件的设置 本模块在设置五子棋的下棋过程中,设置了几个自定义事件来完成在单击棋盘时添加 棋子的操作。 事件是类和对象向外界发出的消息,事件的执行是通过事件委托的方式,调用已准备 好的处理方法,它是在消息之前响应的。要响应事件并针对某些事件执行已定义的方法, 需要做到以下几步: //发布事件的类 //定义事件参数类 (1)声明事件委托; (2)声明事件; (3)添加事件的触发方法; (4)添加事件的处理程序(响应事件的方法); (5)将指定的事件处理程序绑定到要处理的事件上(订阅事件); (6)用户信息操作并触发事件(调用事件的触发方法); (7)通过事件委托的回调,执行需要的事件处理程序。 下面列举一个简单的自定义事件处理程序的示例,代码如下: public class TestEventSource { public class TestEventArgs : EventArgs { public readonly char KeyToRaiseEvent; public TestEventArgs(char keyToRaiseEvent) { KeyToRaiseEvent = keyToRaiseEvent; } } //定义 delegate public delegate void TestEventHandler(object sender, TestEventArgs e); public event TestEventHandler TestEvent; //用 event 关键字声明事件对象 protected virtual void OnTestEvent(TestEventArgs e)//事件触发方法 { if (TestEvent != null) TestEvent(this, e); } public void RaiseEvent(char keyToRaiseEvent) { TestEventArgs e = new TestEventArgs(keyToRaiseEvent); OnTestEvent(e); } } public class TestEventListener { //定义处理事件的方法,与声明事件的 delegate 具有相同的参数和返回值类型 public void KeyPressed(object sender, TestEventSource.TestEventArgs e) { Console.WriteLine(" 发 送 者 : {0} , 所 按 的 键 为 : {1}", sender, } public void Subscribe(TestEventSource evenSource) //订阅事件 { evenSource.TestEvent += new TestEventSource.TestEventHandler(KeyPressed); } //监听事件的类 //引发事件 8 e.KeyToRaiseEvent);
分享到:
收藏