简单C#坦克大战网络版代码
写完单机版 http://blog.csdn.net/xiaoxiao108/archive/2010/12/18/6084473.aspx游戏后
再写个网络版玩玩。
开发工具vs2008
网络版实现方法很简单
1.一个服务端,多个客户端
2.服务端开个端口监听,当一个客户端程序后连接到服务端后,服务端分配个编号给客户端作为他的坦克编号
3.当有新坦克创建,坦克移动,等操作时,客户端发送数据到服务端,服务端再把数据发送到所有的客户端来实现网络游戏的同步
具体实现代码
1.服务端开启服务代码
public void Start()
{
//开启udp线程
Thread t = new Thread(UDPThread);
t.IsBackground = true;
t.Start();
//开启tcp服务
TcpListener tl = new TcpListener(TCP_PORT);
tl.Start();
while (true)
{
TcpClient tc = tl.AcceptTcpClient();
Stream ns = tc.GetStream();
BinaryReader br = new BinaryReader(ns);
int udpPort = br.ReadInt32();//br.Close();不能关闭br
BinaryWriter bw = new BinaryWriter(ns);
bw.Write(ID++);
IPEndPoint rep = (IPEndPoint)tc.Client.RemoteEndPoint;
Client c = new Client(rep.Address.ToString(), udpPort);
clients.Add(c);
Console.WriteLine("A Client TCP Connect! Addr- " + rep.Address.ToString() + ":" + rep.Port);
}
}
2.服务端udp数据接收转发代码
private void UDPThread()
{
Console.WriteLine("UDP thread started at port :" + UDP_PORT);
byte[] buf = new byte[1024];
UdpClient uc = new UdpClient(UDP_PORT); 跟java有区别 如果这句话放到while外面 就不能接受第二个坦克连入
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 0);
while (true)
{
buf = uc.Receive(ref ipep);
Console.WriteLine("a udp packet received! from " + ipep.Address + ":" + ipep.Port);
//把收到的数据转发给每一个客户端
for (int i = 0; i < clients.Count; i++)
{
Client c = clients[i];
UdpClient _uc = new UdpClient();
_uc.Connect(c.ip, c.udpPort);
_uc.Send(buf, buf.Length);
}
}
}
3.客户端连接代码
public void Connect(string ip, int port)
{
this.ip = ip;
TcpClient client = new TcpClient();
client.Connect(ip, port);
Stream ns = client.GetStream();
BinaryWriter bw = new BinaryWriter(ns);
bw.Write(udpPort);
BinaryReader br = new BinaryReader(ns); //bw.Close();不能关闭bw
//从服务器端取到服务器分配的坦克编号
int id = br.ReadInt32();
tc.myTank.ID = id;
//编号为偶数的设置为坏蛋
if (id % 2 == 0)
tc.myTank.Good = false;
else
tc.myTank.Good = true;
//可以在“输出窗口”看到下面的调试代码
Debug.WriteLine("Connected to server! and server give me a ID:" + id);
br.Close();
ns.Close();
client.Close();
TankNewMsg msg = new TankNewMsg(tc.myTank);
Send(msg);
//开启接收线程
Thread t = new Thread(UDPRecvThread);
t.IsBackground = true;
t.Start();
}
4.坦克加入消息代码发送代码
public void Send(UdpClient uc, string ip, int udpPort)
{
uc.Connect(ip, udpPort);
//程序中用 | 来分割发送的内容
string str = msgType + "|" + tank.ID + "|" + tank.x + "|" + tank.y + "|" + (int)tank.dir + "|" + tank.Good;
uc.Send(Encoding.UTF32.GetBytes(str), Encoding.UTF32.GetBytes(str).Length);
}
5.坦克加入消息解析代码
public void Parse(byte[] b)
{
string str = Encoding.UTF32.GetString(b);
string[] strs = str.Split('|');
int id = Convert.ToInt32(strs[1]);
//如果数据包里是自己的坦克不处理
if (id == tc.myTank.ID)
{
return;
}
int x = Convert.ToInt32(strs[2]);
int y = Convert.ToInt32(strs[3]);
Direction dir = (Direction)Convert.ToInt32(strs[4]);
bool good = Convert.ToBoolean(strs[5]);
Boolean exist = false;
for (int i = 0; i < tc.tanks.Count; i++)
{
Tank t = tc.tanks[i];
if (t.ID == id)
{
exist = true;
break;
}
}
//如果坦克不存在就创建出来
if (!exist)
{
TankNewMsg msg = new TankNewMsg(tc.myTank);
tc.nc.Send(msg);
//Tank t = new Tank(x, y, good, tc);//java中是这样写得Tank t = new Tank(x,y,good,dir,tc)
Tank t = new Tank(x, y, good, dir, tc); //有可能是老坦克 给新坦克发包 所以要家dir参数
t.ID = id;
tc.tanks.Add(t);
}
}
6.坦克移动消息
public void Send(UdpClient uc, string ip, int udpPort)
{
uc.Connect(ip, udpPort);
//程序中用 | 来分割发送的内容
string str = msgType + "|" + id + "|" + x + "|" + y + "|" + Convert.ToInt32(dir);
uc.Send(Encoding.UTF32.GetBytes(str), Encoding.UTF32.GetBytes(str).Length);
}
public void Parse(byte[] b)
{
string str = Encoding.UTF32.GetString(b);
string[] strs = str.Split('|');
int id = Convert.ToInt32(strs[1]);
//如果数据包里是自己的坦克不处理
if (id == tc.myTank.ID)
{
return;
}
int x = Convert.ToInt32(strs[2]);
int y = Convert.ToInt32(strs[3]);
Direction dir = (Direction)Convert.ToInt32(strs[4]);
for (int i = 0; i < tc.tanks.Count; i++)
{
Tank t = tc.tanks[i];
if (t.ID == id)
{
t.dir = dir;
t.x = x;
t.y = y;
break;
}
}
}
7.子弹消息处理代码
public void Send(UdpClient uc, string ip, int udpPort)
{
uc.Connect(ip, udpPort);
//程序中用 | 来分割发送的内容
string str = msgType + "|" + m.tankID + "|" + m.x + "|" + m.y + "|" + (int)m.dir + "|" + m.good;
uc.Send(Encoding.UTF32.GetBytes(str), Encoding.UTF32.GetBytes(str).Length);
}
public void Parse(byte[] b)
{
string str = Encoding.UTF32.GetString(b);
string[] strs = str.Split('|');
int tankID = Convert.ToInt32(strs[1]);
if (tankID == tc.myTank.ID)
{
return;
}
int x = Convert.ToInt32(strs[2]);
int y = Convert.ToInt32(strs[3]);
Direction dir = (Direction)Convert.ToInt32(strs[4]);
bool good = Convert.ToBoolean(strs[5]);
Missile m = new Missile(tankID, x, y, good, dir, tc);
tc.missiles.Add(m);
}
单机测试时 先运行服务端 再运行多个客户端就ok
多机联网游戏时修改下 nc.Connect("127.0.0.1", 8888);中的ip地址就可以在局域网内玩了
private void Form1_Load(object sender, EventArgs e)
{
myTank = new Tank(50, 20, true, this);//放到前面 this不能用 //y轴比java的减少了30
nc = new NetClient(this);
nc.Connect("127.0.0.1", 8888);
//nc.connect("192.168.1.168",8888);
//nc.connect("10.10.10.1",8888);
}
如果你发现有什么不合理的,需要改进的地方,邮件联系328452421@qq.com(qq常年不在线,邮件联系) 朱晓 (泰山学院)。相互交流 谢谢