簡單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常年不線上,郵件聯絡) 朱曉 (泰山學院)。相互交流 謝謝
http://download.csdn.net/source/2986606