Java坦克大战网络版
openkk
12年前
不足之处
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
</TC.MISSILES.SIZE();></pre></TANKS.SIZE();></tank></pre></TC.TANKS.SIZE();></pre></TC.TANKS.SIZE();></pre></TC.TANKS.SIZE();></pre>