Java坦克大戰網絡版
不足之處
Server不夠高效....需要看更多書去學習
協議不夠精細
TankNewMsg TankAreadyExistMsg
子彈打中坦克后可否只發送一個消息
tankId id 被打中的tankId
同步線程
坦克退出后的服務器端處理.....另起端口管理跟命令相關之處,命令與數據分開
一段時間沒有接收到數據后的處理
更加精細的內存控制
TankServer
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;
public class TankServer {
private static int ID = 100;
public static final int TCP_PORT = 8888;
public static final int UDP_PORT = 6666;
List clients = new ArrayList();
public void start() {
new Thread(new UDPThread()).start();
ServerSocket ss = null;
try {
ss = new ServerSocket(TCP_PORT);
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
Socket s = null;
try {
s = ss.accept();
DataInputStream dis = new DataInputStream(s.getInputStream());
String IP = s.getInetAddress().getHostAddress();
int udpPort = dis.readInt();
Client c = new Client(IP, udpPort);
clients.add(c);
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeInt(ID++);
//s.close();
System.out.println("A Client Connect! Addr- " + s.getInetAddress() + ":" + s.getPort() + "----UDP Port:" + udpPort);
} catch (IOException e) {
e.printStackTrace();
} finally {
if(s != null) {
try {
s.close();
s = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
new TankServer().start();
}
private class Client {
String IP;
int udpPort;
public Client(String IP, int udpPort) {
this.IP = IP;
this.udpPort = udpPort;
}
}
private class UDPThread implements Runnable {
byte[] buf = new byte[1024];
public void run() {
DatagramSocket ds = null;
try {
ds = new DatagramSocket(UDP_PORT);
} catch (SocketException e) {
e.printStackTrace();
}
System.out.println("UDP thread started at port :" + UDP_PORT);
while(ds != null){
DatagramPacket dp = new DatagramPacket(buf, buf.length);
try {
ds.receive(dp);
for(int i=0; i
TankClient
import java.awt.Button;
import java.awt.Color;
import java.awt.Dialog;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Label;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
public class TankClient extends Frame {
public static final int GAME_WIDTH = 800;
public static final int GAME_HEIGHT = 600;
Tank myTank = new Tank(50, 50, true, Dir.STOP, this);
List missiles = new ArrayList();
List explodes = new ArrayList();
List tanks = new ArrayList();
Image offScreenImage = null;
NetClient nc = new NetClient(this);
ConnDialog dialog = new ConnDialog();
@Override
public void paint(Graphics g) {
g.drawString("missiles count:" + missiles.size(), 10, 50);
g.drawString("explodes count:" + explodes.size(), 10, 70);
g.drawString("tanks count:" + tanks.size(), 10, 90);
for(int i=0; i
NetClient
import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.Socket; import java.net.SocketException; import java.net.UnknownHostException; public class NetClient { TankClient tc; private int udpPort; String IP; //server IP DatagramSocket ds = null; public NetClient(TankClient tc) { this.tc = tc; } public void connect(String IP, int port) { this.IP = IP; try { ds = new DatagramSocket(udpPort); } catch (SocketException e) { e.printStackTrace(); } Socket s = null; try { s = new Socket(IP, port); DataOutputStream dos = new DataOutputStream(s.getOutputStream()); dos.writeInt(udpPort); DataInputStream dis = new DataInputStream(s.getInputStream()); int id = dis.readInt(); tc.myTank.id = id; if(id%2 == 0) tc.myTank.good = false; else tc.myTank.good = true; System.out.println("Connected to server! and server give me a ID:" + id); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(s != null) { try { s.close(); s = null; } catch (IOException e) { e.printStackTrace(); } } } TankNewMsg msg = new TankNewMsg(tc.myTank); send(msg); new Thread(new UDPRecvThread()).start(); } public void send(Msg msg) { msg.send(ds, IP, TankServer.UDP_PORT); } private class UDPRecvThread implements Runnable { byte[] buf = new byte[1024]; public void run() { while(ds != null){ DatagramPacket dp = new DatagramPacket(buf, buf.length); try { ds.receive(dp); parse(dp); System.out.println("a packet received from server!"); } catch (IOException e) { e.printStackTrace(); } } } private void parse(DatagramPacket dp) { ByteArrayInputStream bais = new ByteArrayInputStream(buf, 0, dp.getLength()); DataInputStream dis = new DataInputStream(bais); int msgType = 0; try { msgType = dis.readInt(); } catch (IOException e) { e.printStackTrace(); } Msg msg = null; switch (msgType) { case Msg.TANK_NEW_MSG: msg = new TankNewMsg(NetClient.this.tc); msg.parse(dis); break; case Msg.TANK_MOVE_MSG: msg = new TankMoveMsg(NetClient.this.tc); msg.parse(dis); break; case Msg.MISSILE_NEW_MSG: msg = new MissileNewMsg(NetClient.this.tc); msg.parse(dis); break; case Msg.TANK_DEAD_MSG: msg = new TankDeadMsg(NetClient.this.tc); msg.parse(dis); break; case Msg.MISSILE_DEAD_MSG: msg = new MissileDeadMsg(NetClient.this.tc); msg.parse(dis); break; } } } public int getUdpPort() { return udpPort; } public void setUdpPort(int udpPort) { this.udpPort = udpPort; } }Msg接口
import java.io.DataInputStream; import java.net.DatagramSocket; public interface Msg { public static final int TANK_NEW_MSG = 1; public static final int TANK_MOVE_MSG = 2; public static final int MISSILE_NEW_MSG = 3; public static final int TANK_DEAD_MSG = 4; public static final int MISSILE_DEAD_MSG = 5; public void send(DatagramSocket ds, String IP, int udpPort); public void parse(DataInputStream dis); }TankNewMsg
import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketException; public class TankNewMsg implements Msg { int msgType = Msg.TANK_NEW_MSG; Tank tank; TankClient tc; public TankNewMsg(Tank tank) { this.tank = tank; } public TankNewMsg(TankClient tc) { this.tc = tc; } public void send(DatagramSocket ds, String IP, int udpPort) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); try { dos.writeInt(msgType); dos.writeInt(tank.id); dos.writeInt(tank.x); dos.writeInt(tank.y); dos.writeInt(tank.dir.ordinal()); dos.writeBoolean(tank.good); } catch (IOException e) { e.printStackTrace(); } byte[] buf = baos.toByteArray(); try { DatagramPacket dp = new DatagramPacket(buf, buf.length, new InetSocketAddress(IP, udpPort)); ds.send(dp); } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public void parse(DataInputStream dis) { try { int id = dis.readInt(); if(tc.myTank.id == id) { return; } int x = dis.readInt(); int y = dis.readInt(); Dir dir = Dir.values()[dis.readInt()]; boolean good = dis.readBoolean(); //System.out.println("id:" + id + "-x:" + x + "-y:" + y + "-dir:" + dir + "-good:" + good); boolean exist = false; for(int i=0; iTankMoveMsg import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketException; public class TankMoveMsg implements Msg { int msgType = Msg.TANK_MOVE_MSG; int x, y; int id; Dir ptDir; Dir dir; TankClient tc; public TankMoveMsg(int id,int x, int y, Dir dir, Dir ptDir) { this.id = id; this.x = x; this.y = y; this.dir = dir; this.ptDir = ptDir; } public TankMoveMsg(TankClient tc) { this.tc = tc; } public void parse(DataInputStream dis) { try { int id = dis.readInt(); if(tc.myTank.id == id) { return; } int x = dis.readInt(); int y = dis.readInt(); Dir dir = Dir.values()[dis.readInt()]; Dir ptDir = Dir.values()[dis.readInt()]; //System.out.println("id:" + id + "-x:" + x + "-y:" + y + "-dir:" + dir + "-good:" + good); boolean exist = false; for(int i=0; iTankDeadMsg import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketException; public class TankDeadMsg implements Msg { int msgType = Msg.TANK_DEAD_MSG; TankClient tc; int id; public TankDeadMsg(int id) { this.id = id; } public TankDeadMsg(TankClient tc) { this.tc = tc; } public void parse(DataInputStream dis) { try { int id = dis.readInt(); if(tc.myTank.id == id) { return; } //System.out.println("id:" + id + "-x:" + x + "-y:" + y + "-dir:" + dir + "-good:" + good); for(int i=0; iTank import java.awt.Color; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.KeyEvent; import java.util.Random; public class Tank { int id; public static final int XSPEED = 5; public static final int YSPEED = 5; public static final int WIDTH = 30; public static final int HEIGHT = 30; boolean good; int x, y; private static Random r = new Random(); private boolean live = true; private int step = r.nextInt(12) + 3; TankClient tc; boolean bL, bU, bR, bD; Dir dir = Dir.STOP; Dir ptDir = Dir.D; public Tank(int x, int y, boolean good) { this.x = x; this.y = y; this.good = good; } public Tank(int x, int y, boolean good, Dir dir, TankClient tc) { this(x, y, good); this.dir = dir; this.tc = tc; } public void draw(Graphics g) { if(!live) { if(!good) { tc.tanks.remove(this); } return; } Color c = g.getColor(); if(good) g.setColor(Color.RED); else g.setColor(Color.BLUE); g.fillOval(x, y, WIDTH, HEIGHT); g.drawString("id:" + id, x, y-10); g.setColor(c); switch(ptDir) { case L: g.drawLine(x + WIDTH/2, y + HEIGHT/2, x, y + HEIGHT/2); break; case LU: g.drawLine(x + WIDTH/2, y + HEIGHT/2, x, y); break; case U: g.drawLine(x + WIDTH/2, y + HEIGHT/2, x + WIDTH/2, y); break; case RU: g.drawLine(x + WIDTH/2, y + HEIGHT/2, x + WIDTH, y); break; case R: g.drawLine(x + WIDTH/2, y + HEIGHT/2, x + WIDTH, y + HEIGHT/2); break; case RD: g.drawLine(x + WIDTH/2, y + HEIGHT/2, x + WIDTH, y + HEIGHT); break; case D: g.drawLine(x + WIDTH/2, y + HEIGHT/2, x + WIDTH/2, y + HEIGHT); break; case LD: g.drawLine(x + WIDTH/2, y + HEIGHT/2, x, y + HEIGHT); break; } move(); } private void move() { switch(dir) { case L: x -= XSPEED; break; case LU: x -= XSPEED; y -= YSPEED; break; case U: y -= YSPEED; break; case RU: x += XSPEED; y -= YSPEED; break; case R: x += XSPEED; break; case RD: x += XSPEED; y += YSPEED; break; case D: y += YSPEED; break; case LD: x -= XSPEED; y += YSPEED; break; case STOP: break; } if(dir != Dir.STOP) { ptDir = dir; } if(x < 0) x = 0; if(y < 30) y = 30; if(x + WIDTH > TankClient.GAME_WIDTH) x = TankClient.GAME_WIDTH - WIDTH; if(y + HEIGHT > TankClient.GAME_HEIGHT) y = TankClient.GAME_HEIGHT - HEIGHT; /*if(!good) { if(step == 0) { step = r.nextInt(12) + 3; Dir[] dirs = Dir.values(); dir = dirs[r.nextInt(dirs.length)]; } step --; if(r.nextInt(40) > 38) this.fire(); }*/ } public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); switch (key) { case KeyEvent.VK_LEFT: bL = true; break; case KeyEvent.VK_UP: bU = true; break; case KeyEvent.VK_RIGHT: bR = true; break; case KeyEvent.VK_DOWN: bD = true; break; } locateDirection(); } private void locateDirection() { Dir oldDir = this.dir; if(bL && !bU && !bR && !bD) dir = Dir.L; else if(bL && bU && !bR && !bD) dir = Dir.LU; else if(!bL && bU && !bR && !bD) dir = Dir.U; else if(!bL && bU && bR && !bD) dir = Dir.RU; else if(!bL && !bU && bR && !bD) dir = Dir.R; else if(!bL && !bU && bR && bD) dir = Dir.RD; else if(!bL && !bU && !bR && bD) dir = Dir.D; else if(bL && !bU && !bR && bD) dir = Dir.LD; else if(!bL && !bU && !bR && !bD) dir = Dir.STOP; if(dir != oldDir) { TankMoveMsg msg = new TankMoveMsg(id, x, y, dir, ptDir); tc.nc.send(msg); } } public void keyReleased(KeyEvent e) { int key = e.getKeyCode(); switch (key) { case KeyEvent.VK_CONTROL: fire(); break; case KeyEvent.VK_LEFT: bL = false; break; case KeyEvent.VK_UP: bU = false; break; case KeyEvent.VK_RIGHT: bR = false; break; case KeyEvent.VK_DOWN: bD = false; break; } locateDirection(); } private Missile fire() { if(!live) return null; int x = this.x + WIDTH/2 - Missile.WIDTH/2; int y = this.y + HEIGHT/2 - Missile.HEIGHT/2; Missile m = new Missile(id, x, y, this.good, this.ptDir, this.tc); tc.missiles.add(m); MissileNewMsg msg = new MissileNewMsg(m); tc.nc.send(msg); return m; } public Rectangle getRect() { return new Rectangle(x, y, WIDTH, HEIGHT); } public boolean isLive() { return live; } public void setLive(boolean live) { this.live = live; } }Missileimport java.awt.Color; import java.awt.Graphics; import java.awt.Rectangle; import java.util.List; public class Missile { public static final int XSPEED = 10; public static final int YSPEED = 10; public static final int WIDTH = 10; public static final int HEIGHT = 10; private static int ID = 1; TankClient tc; int tankId; int id; int x, y; Dir dir = Dir.R; boolean live = true; boolean good; public Missile(int tankId, int x, int y, boolean good, Dir dir) { this.tankId = tankId; this.x = x; this.y = y; this.good = good; this.dir = dir; this.id = ID++; } public Missile(int tankId, int x, int y, boolean good, Dir dir, TankClient tc) { this(tankId, x, y, good, dir); this.tc = tc; } public void draw(Graphics g) { if(!live) { tc.missiles.remove(this); return; } Color c = g.getColor(); g.setColor(Color.BLACK); g.fillOval(x, y, WIDTH, HEIGHT); g.setColor(c); move(); } private void move() { switch(dir) { case L: x -= XSPEED; break; case LU: x -= XSPEED; y -= YSPEED; break; case U: y -= YSPEED; break; case RU: x += XSPEED; y -= YSPEED; break; case R: x += XSPEED; break; case RD: x += XSPEED; y += YSPEED; break; case D: y += YSPEED; break; case LD: x -= XSPEED; y += YSPEED; break; case STOP: break; } if(x < 0 || y < 0 || x > TankClient.GAME_WIDTH || y > TankClient.GAME_HEIGHT) { live = false; } } public Rectangle getRect() { return new Rectangle(x, y, WIDTH, HEIGHT); } public boolean hitTank(Tank t) { if(this.live && t.isLive() && this.good != t.good &&this.getRect().intersects(t.getRect())) { this.live = false; t.setLive(false); tc.explodes.add(new Explode(x, y, tc)); return true; } return false; } public boolean hitTanks(Listtanks) { for(int i=0; i MissileNewMsg import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketException; public class MissileNewMsg implements Msg { int msgType = Msg.MISSILE_NEW_MSG; TankClient tc; Missile m; public MissileNewMsg(Missile m) { this.m = m; } public MissileNewMsg(TankClient tc) { this.tc = tc; } public void send(DatagramSocket ds, String IP, int udpPort) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); try { dos.writeInt(msgType); dos.writeInt(m.tankId); dos.writeInt(m.id); dos.writeInt(m.x); dos.writeInt(m.y); dos.writeInt(m.dir.ordinal()); dos.writeBoolean(m.good); } catch (IOException e) { e.printStackTrace(); } byte[] buf = baos.toByteArray(); try { DatagramPacket dp = new DatagramPacket(buf, buf.length, new InetSocketAddress(IP, udpPort)); ds.send(dp); } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public void parse(DataInputStream dis) { try { int tankId = dis.readInt(); if(tankId == tc.myTank.id) { return; } int id = dis.readInt(); int x = dis.readInt(); int y = dis.readInt(); Dir dir = Dir.values()[dis.readInt()]; boolean good = dis.readBoolean(); //System.out.println("id:" + id + "-x:" + x + "-y:" + y + "-dir:" + dir + "-good:" + good); Missile m = new Missile(tankId, x, y, good, dir, tc); m.id = id; tc.missiles.add(m); } catch (IOException e) { e.printStackTrace(); } } }MissileDeadMsgimport java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketException; public class MissileDeadMsg implements Msg { int msgType = Msg.MISSILE_DEAD_MSG; TankClient tc; int tankId; int id; public MissileDeadMsg(int tankId, int id) { this.tankId = tankId; this.id = id; } public MissileDeadMsg(TankClient tc) { this.tc = tc; } public void parse(DataInputStream dis) { try { int tankId = dis.readInt(); int id = dis.readInt(); //System.out.println("id:" + id + "-x:" + x + "-y:" + y + "-dir:" + dir + "-good:" + good); for(int i=0; iExplode import java.awt.Color; import java.awt.Graphics; public class Explode { int x, y; private int[] diameters = {4, 7, 12, 18, 26, 32, 49, 30, 14, 6}; private boolean live = true; private TankClient tc; int step = 0; public Explode(int x, int y, TankClient tc) { this.x = x; this.y = y; this.tc = tc; } public void draw(Graphics g) { if(!live) { tc.explodes.remove(this); return; } Color c = g.getColor(); g.setColor(Color.ORANGE); g.fillOval(x, y, diameters[step], diameters[step]); g.setColor(c); step ++; if(step == diameters.length) { live = false; } } }Dirpublic enum Dir { L, LU, U, RU, R, RD, D, LD, STOP }![]()
轉自:http://blog.csdn.net/slience_perseverance/article/details/7844993
本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!