基于Udp的五子棋对战游戏
本文主要讲述在局域网内,使用c#基于Udp协议编写一个对战的五子棋游戏。主要从Udp的使用、游戏的绘制、对战的逻辑这三个部分来讲解。
Udp通信
UdpClient udpSend;
public void Send(string sendMsg)
{
udpSend = new UdpClient();
byte[] byteMsg = Encoding.Default.GetBytes(sendMsg);
udpSend.Send(byteMsg, byteMsg.Length, this.sendIp, sendPort);
udpSend.Close();
}
UdpClient udpReceive;
public void StartReceive()
{
//接受端口5888的消息
udpReceive = new UdpClient();
Thread threadReceive = new Thread(ReceiveMessages);
threadReceive.IsBackground = true;
threadReceive.Start();
}
private void ReceiveMessages()
{
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, );//获取发送信息方的ip和端口信息
while (true)
{
try
{
//关闭receiveUdpClient时此句会产生异常 byte[] receiveBytes = udpReceive.Receive(ref remoteIPEndPoint); string message = Encoding.Default.GetString(receiveBytes, , receiveBytes.Length);
MessageParse(message);//去分析消息,并处理
}
catch
{
break;
}
}
}
游戏的绘制
玩过五子棋的都知道,主要是绘制棋盘和棋子,稍微再人性化的就是把对方最后一个放置的棋子标注出来,让我们更加清楚的知道对方的刚下的棋子是哪一个。
//paint方法
private void picChessboard_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
//绘制棋盘
chessBoard.DrawBoard(g);
//绘制棋子
chessBoard.DrawChess(g);
} //初始化全局变量
public void InitialChess()
{
for (int i = ; i < BOARDSIZE; i++)
{
for (int j = ; j < BOARDSIZE; j++)
{
chessMap[i, j] = ;
}
}
this.picChessboard.Invalidate();
}
//绘制棋盘
public void DrawBoard(Graphics g)
{
Pen p = new Pen(Brushes.Black, 3.0f);
// p.Width = 2f;
//横线
for (int i = ; i < BOARDSIZE; i++)
{
g.DrawLine(p, new Point(, (i + ) * ), new Point(BOARDLENGTH, (i + ) * ));
}
//竖线
for (int i = ; i < BOARDSIZE; i++)
{
g.DrawLine(p, new Point((i + ) * , ), new Point((i + ) * , BOARDLENGTH));
}
} //绘制棋子
public void DrawChess(Graphics g)
{ for (int i = ; i < BOARDSIZE; i++)
{
for (int j = ; j < BOARDSIZE; j++)
{
if (chessMap[i, j] == )
{
g.DrawImage(Properties.Resources.whitechess, new Point( * (i + ) - , * (j + ) - ));
}
if (chessMap[i, j] == )
{
g.DrawImage(Properties.Resources.blackchess, new Point( * (i + ) - , * (j + ) - ));
}
}
}
if (pCurrent.X !=-)
{
//绘制最后落下棋子上的红色标注
g.FillEllipse(Brushes.Red, new Rectangle((pCurrent.X + ) * -, (pCurrent.Y + ) * -, , ));
}
}
.com/cc0f6e1e1b0f4ef39c051418cb75bb81/clipboard.png)

对战逻辑
对战的逻辑简单的说就是两部分。1、自己下棋,然后设置全局变量chessMap 通知界面绘制棋子;接受对方下棋的消息,然后设置全局变量chessMap 通知界面绘制棋子;2、下棋之后检测输赢情况。
1、下棋的代码
/// <summary>
/// 下棋
/// </summary>
/// <param name="flag">设置全局变量chessMap的标志</param>
/// <param name="x">棋盘x坐标</param>
/// <param name="y">棋盘y坐标</param>
public void PutOneChess(int flag, int x, int y)
{
if (isPut||myFlag !=flag)//判断是否是自己下棋,或者是别人下棋
{
//计算鼠标点击位置在棋盘的中的行、列的位置
int tolerance = ;
int row = y / ;
int rows = y % ;
int col = x / ;
int cols = x % ; if (rows + tolerance >= )
{
row++;
}
else if (rows - tolerance <= )
{
}
else
{
return;//没有选中
} if (cols + tolerance >= )
{
col++;
}
else if (cols - tolerance <= )
{
}
else
{
return;
} col--;
row--; if (col >= && col < BOARDSIZE && row >= && row < BOARDSIZE)
{
this.chessMap[col, row] = flag;
pCurrent = new Point(col, row);//保存最新放置棋子的位置,以便标注和悔棋
this.picChessboard.Invalidate();
if (myFlag == flag)//如果是自己下棋
{
this.isPut = false;//轮到对方走棋
UpdateRemoteChessBoardDelegate(flag, x, y);//将更新对方的棋盘 if (IsWin(col, row))//自己赢了
{
InformRemoteResultDelegate();
}
}
else
{
this.isPut = true;//轮到自己下棋了。
}
}
}
}
2、检测输赢的代码
//横向
private bool Is1(int c, int r)
{
int count = ;
for (int i = c+; i <c+; i++)
{
if(i<BOARDSIZE)
{
if (chessMap[i, r] == myFlag)
{
count++;
}
else
{
break;
}
}
else
{
break ;
}
}
for (int i = c - ; i > c - ; i--)
{
if (i >= )
{
if (chessMap[i, r] == myFlag)
{
count++;
}
else
{
break;
}
}
else
{
break;
}
}
if (count > )
{
return true;
}
else
{
return false;
}
} //纵向
private bool Is2(int c, int r)
{
int count = ;
for (int i = r + ; i < r + ; i++)
{
if (i < BOARDSIZE)
{
if (chessMap[c, i] == myFlag)
{
count++;
}
else
{
break;
}
}
else
{
break;
}
}
for (int i = r - ; i > r - ; i--)
{
if (i >= )
{
if (chessMap[c, i] == myFlag)
{
count++;
}
else
{
break;
}
}
else
{
break;
}
}
if (count > )
{
return true;
}
else
{
return false;
}
} //左上-右下
private bool Is3(int c,int r)
{
int count = ;
for (int i = ; i < ;i++ )
{
if ((c - i) >= && (r - i)>=)
{
if (chessMap[c-i,r-i] == myFlag)
{
count++;
}
else
{
break;
}
}
else
{
break;
}
}
for (int i = ; i < ; i++)
{
if ((c + i) < BOARDSIZE && (r + i) < BOARDSIZE)
{
if (chessMap[c + i, r +i] == myFlag)
{
count++;
}
else
{
break;
}
}
else
{
break;
}
}
if (count > )
{
return true;
}
else
{
return false;
}
} //右下-左上
private bool Is4(int c, int r)
{
int count = ;
for (int i = ; i < ; i++)
{
if ((c - i) >=&&(r+i)<BOARDSIZE)
{
if (chessMap[c - i, r + i] == myFlag)
{
count++;
}
else
{
break;
}
}
else
{
break;
}
}
for (int i = ; i < ; i++)
{
if ((c+i) < BOARDSIZE&&(r-i)>=)
{
if (chessMap[c + i, r - i] == myFlag)
{
count++;
}
else
{
break;
}
}
else
{
break;
}
}
if (count > )
{
return true;
}
else
{
return false;
}
}

- 发送消息:Talk|"hello"
- 通知对方下棋:Put|1|230|400
- 通知对方输棋:Lose|
- 申请悔棋:ReSet|
- 对方同意:OkSet|
- 对方退出游戏:Exit|
总结
通过写这一个小游戏,让我学会了Udp的具体用法以及体会到了委托在window程序设计中的方便,以往写的程序委托都没有用武之地,我们只是知道委托的的语法如何怎么使用,但是却不知道什么情况使用,在哪里是用。
基于Udp的五子棋对战游戏的更多相关文章
- Linux网络编程10——使用UDP实现五子棋对战
思路 1. 通信 为了同步双方的棋盘,每当一方在棋盘上落子之后,都需要发送给对方一个msg消息,让对方知道落子位置.msg结构体如下: /* 用于发给对方的信息 */ typedef struct t ...
- 【微信小程序项目实践总结】30分钟从陌生到熟悉 web app 、native app、hybrid app比较 30分钟ES6从陌生到熟悉 【原创】浅谈内存泄露 HTML5 五子棋 - JS/Canvas 游戏 meta 详解,html5 meta 标签日常设置 C#中回滚TransactionScope的使用方法和原理
[微信小程序项目实践总结]30分钟从陌生到熟悉 前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05- ...
- 双人五子棋对战(需要EasyX图像库)
实训要做项目呐.天天坐在电脑面前累死了.最近题刷的少.大多数都挺水.就不挨个编辑发上来了.发发白天写的项目吧.可能好几天更一下.实训结束恢复正常. 这个游戏需要EasyX的图像库.有兴趣的可以下一个图 ...
- 使用unity3d和tensorflow实现基于姿态估计的体感游戏
使用unity3d和tensorflow实现基于姿态估计的体感游戏 前言 之前做姿态识别,梦想着以后可以自己做出一款体感游戏,然而后来才发现too young.但是梦想还是要有的,万一实现了呢.趁着p ...
- Raknet是一个基于UDP网络传输协议的C++网络库(还有一些其它库,比如nanomsg,fastsocket等等)
Raknet是一个基于UDP网络传输协议的C++网络库,允许程序员在他们自己的程序中实现高效的网络传输服务.通常情况下用于游戏,但也可以用于其它项目. Raknet有以下好处: 高性能 在同一台计算机 ...
- java Socket编程-基于UDP
package com.wzy.UDPTest; import java.net.DatagramPacket; import java.net.DatagramSocket; import java ...
- 基于FPGA的飞机的小游戏
基于FPGA的飞机的小游戏 实验原理 该实验主要分为4个模块,采用至上而下的设计方法进行设计.由50M的晶振电路提供时钟源,VGA显示控制模块.图形显示控制模块.移动模块的时钟为25M,由时钟分频电路 ...
- 基于UDP协议模拟的一个TCP协议传输系统
TCP协议以可靠性出名,这其中包括三次握手建立连接,流控制和拥塞控制等技术.详细介绍如下: 1. TCP协议将需要发送的数据分割成数据块.数据块大小是通过MSS(maximum segment siz ...
- 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程
Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...
随机推荐
- Spring+Ehcache
这里记录一下Spring+Ehcache的结合使用 1.添加依赖 <dependency> <groupId>org.springframework</groupId&g ...
- Elasticsearch Java API简介
加入依赖 我本地的Elasticsearch的版本是2.1.0,因此加入相应的maven依赖 <dependency> <groupId>org.elasticsearch&l ...
- apt错误
安装软件遇到错误,不管安装什么软件都有错误. apt-get install softname 报错如下:E: Sub-process /usr/bin/dpkg returned an error ...
- java中的IO流(输入流与输出流)概述与总结
Java中IO流,输入输出流概述与总结 总结的很粗糙,以后时间富裕了好好修改一下. 1:Java语言定义了许多类专门负责各种方式的输入或者输出,这些类都被放在java.io包中.其中, 所有输入流类都 ...
- scroll事件实现监控滚动条改变标题栏背景透明度(zepto.js )
今天做了一个类似于手机端京东首页的页面,效果图如下: 刷新页面的时候,标题栏(也就是搜索栏),背景是透明的,当我们往下滑的时候,可以改变标题栏的背景透明度(渐变效果): 当标题栏滑过轮播图后,透明度就 ...
- Linux实用指令
Linux实用指令 Rpm&Yum 一种用于互联网下载包的打包和安装工具,它包含某些Linux分发版中,它生产具有 .rpm 扩展名的文件.RPM 是 RedHat Package Man ...
- keepalived安装配置实战心得(实现高可用保证网络服务不间断)
keepalived安装配置实战心得(实现高可用保证网络服务不间断) 一.准备2台虚拟机 安装的系统是:centos-release-7-1.1503.el7.centos.2.8.x86_6 ...
- 【jQuery源码】tokenize方法
//得到由选择器生成的token对象的数组(下面的groups) //Sizzle的Token格式如下 :{value:'匹配到的字符串', type:'对应的Token类型', matches:'正 ...
- Unable to handle kernel NULL pointer dereference at virtual address 00000000问题的解决
今天在编译好内核模块后,安装内核模块memdev.ko的时候,出现了Unable to handle kernel NULL pointer dereference at virtual addres ...
- 带你了解数据库中group by的用法
前言 本章主要介绍数据库中group by的用法,也是我们在使用数据库时非常基础的一个知识点.并且也会涉及Join的使用,关于Join的用法,可以看我写的上一篇文章:带你了解数据库中JOIN的用法如有 ...