本文主要讲述在局域网内,使用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(5888); Thread threadReceive = new Thread(ReceiveMessages); threadReceive.IsBackground = true; threadReceive.Start(); } private void ReceiveMessages() { IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0);//获取发送信息方的ip和端口信息 while (true) { try { //关闭receiveUdpClient时此句会产生异常 byte[] receiveBytes = udpReceive.Receive(ref remoteIPEndPoint); string message = Encoding.Default.GetString(receiveBytes, 0, 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 = 0; i < BOARDSIZE; i++) { for (int j = 0; j < BOARDSIZE; j++) { chessMap[i, j] = 0; } } this.picChessboard.Invalidate(); } //绘制棋盘 public void DrawBoard(Graphics g) { Pen p = new Pen(Brushes.Black, 3.0f); // p.Width = 2f; //横线 for (int i = 0; i < BOARDSIZE; i++) { g.DrawLine(p, new Point(0, (i + 1) * 50), new Point(BOARDLENGTH, (i + 1) * 50)); } //竖线 for (int i = 0; i < BOARDSIZE; i++) { g.DrawLine(p, new Point((i + 1) * 50, 0), new Point((i + 1) * 50, BOARDLENGTH)); } } //绘制棋子 public void DrawChess(Graphics g) { for (int i = 0; i < BOARDSIZE; i++) { for (int j = 0; j < BOARDSIZE; j++) { if (chessMap[i, j] == 1) { g.DrawImage(Properties.Resources.whitechess, new Point(50 * (i + 1) - 20, 50 * (j + 1) - 20)); } if (chessMap[i, j] == 2) { g.DrawImage(Properties.Resources.blackchess, new Point(50 * (i + 1) - 20, 50 * (j + 1) - 20)); } } } if (pCurrent.X !=-1) { //绘制最后落下棋子上的红色标注 g.FillEllipse(Brushes.Red, new Rectangle((pCurrent.X + 1) * 50-5, (pCurrent.Y + 1) * 50-5, 10, 10)); } }
对战逻辑
对战的逻辑简单的说就是两部分。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 = 8; int row = y / 50; int rows = y % 50; int col = x / 50; int cols = x % 50; if (rows + tolerance >= 50) { row++; } else if (rows - tolerance <= 0) { } else { return;//没有选中 } if (cols + tolerance >= 50) { col++; } else if (cols - tolerance <= 0) { } else { return; } col--; row--; if (col >= 0 && col < BOARDSIZE && row >= 0 && 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 = 1; for (int i = c+1; i <c+5; i++) { if(i<BOARDSIZE) { if (chessMap[i, r] == myFlag) { count++; } else { break; } } else { break ; } } for (int i = c - 1; i > c - 5; i--) { if (i >= 0) { if (chessMap[i, r] == myFlag) { count++; } else { break; } } else { break; } } if (count > 4) { return true; } else { return false; } } //纵向 private bool Is2(int c, int r) { int count = 1; for (int i = r + 1; i < r + 5; i++) { if (i < BOARDSIZE) { if (chessMap[c, i] == myFlag) { count++; } else { break; } } else { break; } } for (int i = r - 1; i > r - 5; i--) { if (i >= 0) { if (chessMap[c, i] == myFlag) { count++; } else { break; } } else { break; } } if (count > 4) { return true; } else { return false; } } //左上-右下 private bool Is3(int c,int r) { int count = 1; for (int i = 1; i < 5;i++ ) { if ((c - i) >= 0 && (r - i)>=0) { if (chessMap[c-i,r-i] == myFlag) { count++; } else { break; } } else { break; } } for (int i = 1; i < 5; i++) { if ((c + i) < BOARDSIZE && (r + i) < BOARDSIZE) { if (chessMap[c + i, r +i] == myFlag) { count++; } else { break; } } else { break; } } if (count > 4) { return true; } else { return false; } } //右下-左上 private bool Is4(int c, int r) { int count = 1; for (int i = 1; i < 5; i++) { if ((c - i) >=0&&(r+i)<BOARDSIZE) { if (chessMap[c - i, r + i] == myFlag) { count++; } else { break; } } else { break; } } for (int i = 1; i < 5; i++) { if ((c+i) < BOARDSIZE&&(r-i)>=0) { if (chessMap[c + i, r - i] == myFlag) { count++; } else { break; } } else { break; } } if (count > 4) { return true; } else { return false; } }
总结
通过写这一个小游戏,让我学会了Udp的具体用法以及体会到了委托在window程序设计中的方便,以往写的程序委托都没有用武之地,我们只是知道委托的的语法如何怎么使用,但是却不知道什么情况使用,在哪里是用。