海军战斗游戏-II(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/navy-battle-game-ii-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 9 分钟阅读 - 4167 个词海军战斗游戏-II(译文)
原文地址:https://www.codeproject.com/Articles/11124/Navy-Battle-Game-II
原文作者:Alex Cutovoi
译文由本站 robot-v1.0 翻译
前言
A client-server navy battle game.
客户端-服务器海军战斗游戏.
介绍(Introduction)
一个带有套接字和IO的客户端服务器应用程序,用于玩Navy Battle游戏.(A client-server application with sockets and IO to play the Navy Battle game.)
在您开始阅读之前(Before you start to read)
本文是两篇文章系列的第二部分.的(This article is the second part of a two-article series. The) 第一部分(first part) 涵盖了如何绘制海军战场.第二部分介绍客户端-服务器连接以及如何在正确的位置绘制坐标.为了更好地理解本文,您应该了解一些套接字连接(对于第2部分),即名称空间(covers how to draw a navy battle battlefield. The second part covers client-server connection and how to draw the coordinates in the right places. To better understand this article, you should know a little bit of socket connections (for the part 2), the namespace) System.Drawing
和IO(第2部分也是如此).如果您不知道我在说什么,我建议您阅读Deitel的书" C#How to Program".但是,如果您没有钱,请参阅(and IO (for the part 2 too). If you don’t have any idea what I’m talking about, I recommend you read the Deitel’s book “C# How to Program”. But if you don’t have money, the documentation in the) MSDN(MSDN) 是很大的帮助.最重要的是您要拥有这本书并在MSDN中进行导航.(is a great help. The great deal is you to have the book and to navigate in the MSDN.)
我们又回来了(We’re back again)
我们又回来了,现在说明客户端与服务器的连接以及如何在战场上绘制" X".(We’re back again, now to explain the client-server connection and how to draw the “X"s in the battlefield.)
服务器(The server)
在客户端-服务器连接中,我们必须执行一些步骤.以下是服务器步骤:(In a client-server connection, we have to follow some steps. Below are the server steps:)
- 创建侦听器对象;(Create the listener object;)
- 启动对象;(Start the object;)
- 将其关联到套接字以生成交易数据;(Associate it to a socket to make the transaction data;)
- 发送和接收数据;(Send and receive data;)
- 最后,当所有事情都完成后,关闭连接;(And finally, close the connection when all the things are done;) 在客户端服务器应用程序中,启动服务器或客户端的方法必须置于线程中.您必须执行此操作,因为服务器会一直保持侦听状态,直到建立连接为止,并且在客户端应用程序启动时,服务器会捕获客户端发出的连接请求,并且魔术已完成.(In a client-server application, the methods that start the server or client must be put in threads. You must do this because the server stays listening until a connection is made, and when the client application starts, the server catches the connection request made by the client and the magic is done.) 好的,现在我将类的构造函数放在这里:(OK, now I put here the constructor of my class:)
//The constructor
public Server(Graphics g)
{
G = g;
IPAddress IPLocalhost = IPAddress.Parse("127.0.0.1");
//first commandment: create the listener
ServerListener = new TcpListener(IPLocalhost, 65000);
//second commandment: start it!
ServerListener.Start();
}
您已经注意到,在我的构造函数中,我通过了(You have noticed that in my constructor I pass a) Graphics
称为”(parameter called “) g
“.为什么?解释在”(”. Why? The explanation is in the “) Desenho
“中的对象(” object which is in the) Running()
方法.(method.)
public void Running()
{
try
{
//third commandment: associate the Listener
//with the socket to receive data
while(true)
{
Connexion = ServerListener.AcceptSocket();
//fourth commandment: make transactions
if(Connexion.Connected)
{
DataStream = new NetworkStream(Connexion);
Reader = new BinaryReader(DataStream);
Writer = new BinaryWriter(DataStream);
m_bConnect = true;
do
{
sData = Reader.ReadString();
using(Draw Desenho = new Draw())
{
Desenho.GetCoordinates(sData+
Form1.stCoordinates, G, true);
}
}while(DataStream != null &&
sData != "Close connection");
}
}
//fifth commandment: close it!
Reader.Close();
Writer.Close();
DataStream.Close();
Connexion.Close();
Application.Exit();
}
catch(SocketException SocketEx)
{
MessageBox.Show(SocketEx.Message);
}
此方法有一个(This method has a) try
/(/) catch
具有一个套接字的块,该套接字接收由(block that has a socket which receives a socket object returned by the) AcceptSocket()
我的方法(method of my) TcpListener
目的.它验证是否建立连接访问(object. It verifies if the connection is established accessing the) Connected
属性并创建数据流以及读取器和写入器.怎么样(property and creates the datastream and the reader and the writer. What about the) Graphics g
参数?在里面(parameter? In the) do while
循环中,有一条语句:(loop, there is a statement:) using
.该语句保证在您完成所有必需的操作后,该对象将被释放.请注意,有一个(. This statement guarantees that the object is released when you have done all the necessary things with it. Notice that there is a) Draw
对象称为(object called) Desenho
.的(. The) GetCoordinates
的方法(method of the) Desenho
对象被调用,参数之一是(object is called and one of the parameters is the) Graphics
目的.(object.)
警告(Caution):创建类型变量不是一个好主意(: It’s not a good idea to create a variable of type) Graphics
.就像杰西利伯蒂(Jesse Liberty)所说:"使用(*. Like Jesse Liberty says: "Use the*)
Graphics反对,并在必要时将其释放."(*object when necessary and release it." I use this guy only in my*)
GetCoordinates方法,当(*method and it's automatically released when the*)
using` 声明已完成.(statement is finished.)
客户端(The Client)
现在,让我们来看一下客户端的步骤:(Now, let’s see the steps for the client:)
- 创建对象;(Create the object;)
- 获取发送和接收数据的流;(Obtain the stream where the data will be sent and received;)
- 发送和接收数据;(Send and receive data;)
- 关闭连接;(Close the connection;)
客户端的步骤与服务器没有太大不同.客户端与发送请求的服务器建立通信.客户端请求就像一个连接器,而套接字服务器就像一个tomade.非常简单现在,我们分析构造函数和(The steps for the client are not so different from the server. The client establishes a communication with the server sending a request. The client request acts like a connector, and the socket server, like a tomade. It’s very simple. Now, we analyze the constructor and the)
RunningClient()
方法.(method.) 看一下这段代码:(Look at this piece of code:)
//The constructor
public Client(Graphics G)
{
Gr = G;
}
public void RunningClient()
{
cClient = new TcpClient();
try
{
cClient.Connect("localhost", 65000);
DataStream = cClient.GetStream();
Reader = new BinaryReader(DataStream);
Writer = new BinaryWriter(DataStream);
do
{
sData = Reader.ReadString();
using(Draw Desenho = new Draw())
{
Desenho.GetCoordinates(sData +
Form1.stCoordinates, Gr, true);
}
} while(DataStream != null && sData != "Close connection");
Reader.Close();
Writer.Close();
DataStream.Close();
cClient.Close();
Application.Exit();
}
catch(SocketException ex)
{
MessageBox.Show(ex.Message);
}
}
您可能已经注意到,这种方法和(Very probably, you’ve noticed that this method and the) Running
课堂方法(method of the class) Server
都差不多而且你是对的.但是有一些区别.看一下这段代码:(are much equal. And you’re right. But there are a few differences. Look at this piece of code:)
public void RunningClient()
{
cClient = new TcpClient();
try
{
cClient.Connect("localhost", 65000);
DataStream = cClient.GetStream();
//others parts of code supressed
}
请注意,客户端构造函数会收到一个(Notice that the client constructor receives a) Graphics
参数,例如服务器构造函数.还要注意(parameter, like the server constructor. Notice too that the) TcpClient
对象没有(object doesn’t have a) Start
方法.由于是客户端,因此它将与服务器的连接请求发送到服务器.(method. As it is a client, it sends to the server a connection request with the) Connect()
,而在服务器中有一个(, while in the server there is a) Start()
侦听客户端是否要建立连接(输入(that listens if a client wants to establish a connection (put in a) while
循环).建立连接后,客户端将调用(loop). When the connection is established, the client calls the) GetStream()
获得方法(method to obtain the) NetworkStream
数据将被传输到的位置.此信息在(that the data will be transferred to. This information is assigned in the) DataStream
目的.因此,将发生转移.(object. So, the transfer will occur.)
GetCoordinates方法(The GetCoordinates Method)
这种方法在我们的海军战役中非常重要.与客户端一样,它在服务器中使用.它接收三个参数:(This method is so important in our Navy Battle. It’s used in the server as in the client. It receive three parameters: a) Graphics
参数,带有坐标的字符串和布尔值.的(parameter, a string with coordinates, and a boolean. The) Graphics
参数仅用于传递给(parameter is used only to be passed to a) private
方法称为(method called) DrawX()
.布尔变量用于查看玩家是否插入了坐标以填充他的战场,还是他插入了坐标以击中敌人.字符串变量包含填充当前用户战场的坐标或当前用户选择击中敌人的坐标.方法如下:(. The boolean variable is used to see if the player has inserted the coordinates to populate his battlefield or he inserted a coordinate to hit the enemy. The string variable contains the coordinates that populate the battlefield of the current user or the coordinates that the current user chooses to hit his enemy. Below is the method:)
public void GetCoordinates(string sCoordinates,
Graphics G, bool bInserted)
{
int[] iLocations = new int[sCoordinates.Length];
int iLength = sCoordinates.Length;
string sReceive;
string sCompare = sCoordinates.Substring(0,2);
m_bWhatX = bInserted;
for(int i = 0; i < iLength ; i++)
{
sReceive = sCoordinates.Substring(i,1);
switch (sReceive)
{
/*populating the array with the coordinates
that will be used to draw*/
case "A":
iLocations[i] = 90;
break;
case "a":
iLocations[i] = 90;
break;
case "B":
iLocations[i] = 140;
break;
case "b":
iLocations[i] = 140;
break;
case "C":
iLocations[i] = 190;
break;
case "c":
iLocations[i] = 190;
break;
case "D":
iLocations[i] = 240;
break;
case "d":
iLocations[i] = 240;
break;
case "E":
iLocations[i] = 290;
break;
case "e":
iLocations[i] = 290;
break;
case "1":
iLocations[i] = 40;
break;
case "2":
iLocations[i] = 90;
break;
case "3":
iLocations[i] = 140;
break;
case "4":
iLocations[i] = 190;
break;
case "5":
iLocations[i] = 240;
break;
}
}
for(int i = 0 ; i <= 8 ; i+=2)
{
//to draw the data inserted in TxtLocation
if(!bInserted)
{
/*just a inversion, cause horizontal
*line in battlefield is of numbers
* and vertical, is composed by letters
*/
DrawX(iLocations[i+1], iLocations[i], G);
}
//to compare and draw the data sended
//by client with the server coordinates and draw
else
{
//with this, the string will be
//the length of 10 when the length is 12
sCoordinates = sCoordinates.Remove(0,2);
while(true)
{
if(sCompare == sCoordinates.Substring(i,2))
{
DrawX(iLocations[i+1], iLocations[i], G);
MessageBox.Show("Acertou");
break;
}
else
{
DrawX(iLocations[i+1], iLocations[i], G);
break;
}
}
break;
}
}
}
不要害怕这种方法的大小.这很简单.该方法获取字符串的每个字符并将其放入(Don’t be scared with the size of this method. It’s simple. The method gets each character of the string and puts it in a) switch
填充整数数组的语句(statement to populate the interger array) iLocations
用于保存将由(that is used to save all the coordinates that will be used by the) DrawX()
方法.那个数字(method. The numbers that) iLocation
数组保持,由(array holds, are used by the) DrawX()
在某个正方形的中心绘制” X"的方法,该正方形由字符串指定(method to draw the “X”" in the center of some square, which is specified by the string) sCoordinates
.然后是布尔值(. Then the boolean) bInserted
用来说(is used to say if the) DrawX()
方法绘制一个坐标(即敌人发送的坐标)或绘制当前用户选择放入其战场的坐标.(method draws a single coordinate (that is the coordinate send by the enemy) or draws the coordinates that the current user chooses to put in their battlefield.)
DrawX方法(The DrawX method)
最后,我们将讨论(Finally, we will talk about the) DrawX()
方法.这非常非常简单.寻找自己:(method. It is very, very simple. Look for yourself:)
private void DrawX(int iX, int iY, Graphics G)
{
Pen pColor;
if(!m_bWhatX)
{
//in the case of server the code is this:
// pColor = new Pen(Color.Blue, 5);
pColor = new Pen(Color.Red, 5);
}
else
{
//in the case of server the code is this:
// pColor = new Pen(Color.Red, 5);
pColor = new Pen(Color.Blue, 5);
}
Point pA = new Point(iX, iY);
Point pB = new Point(iX+30, iY+30);
Point pA1 = new Point(iX+30, iY);
Point pB1 = new Point(iX, iY+30);
G.DrawLine(pColor,pA,pB);
G.DrawLine(pColor,pA1,pB1);
}
请记住,此方法将绘制客户端填充战场时发送的所有坐标,或绘制敌人发送的坐标.这是通过布尔变量完成的(Remember that this method draws all the coordinates send by the client populating the battlefield or draws the coordinate send by the enemy. This is done using the boolean variable) m_bWhatX
接收到的价值(that receives the value of the) bInserted
参数.我把服务器的(parameter. I put the server’s) Pen
对象注释只是为了让您知道每个应用程序绘制的" X".您知道为什么这种方法如此简单吗?(objects commented just for you to know what “X” each application draws. Do you see why this method is so simple?)
再次感谢你(Thank you again)
伙计,我希望您喜欢本文和本文的第一部分.我喜欢写这篇文章(这是我第一次).如果您喜欢或讨厌,请给我发送(Man, I hope that you enjoyed this article and the first part of it. I loved to write this article (it’s my first time). If you’ve liked or if you’ve hated it, send me an)电子邮件(email)您的意见,疑问,更正或新想法.我想告诉您一些事情:如果您想成为一名优秀的程序员,则需要做一件事:(with your comments, doubts, corrections, or new ideas. I want to tell you something: if you want to be a good programmer, you need to do one thing:)学了很多(study, a lot).我是根据自己的经验说的.(. I said this from my own experience.)
文章的历史(Article’s History)
- 2005年7月16日(07-16-2005)-本系列文章第二部分的开始.(- The beginning of the second part of this article series.)
- 2005年7月26日(07-26-2005)-我在这之间停了一会儿,但是最后,第二部分结束了.修订完成的两个部分,并将完整的软件包发送给The Code Project.(- I stopped in between for a while, but finally, the second part is finished. Revision of both parts done and the complete package sent to The Code Project.)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C# WinXP Windows .NET .NET1.1 Visual-Studio GDI+ VS.NET2003 Dev 新闻 翻译