Java坦克大戰網絡版

openkk 12年前發布 | 33K 次閱讀 Java 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;
    }
}
Missile

import 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(List tanks) {
        for(int i=0; iMissileNewMsg
  

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();
        }
    }


}
MissileDeadMsg

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 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;           
        }
    }
}
Dir

public enum Dir {
    L, LU, U, RU, R, RD, D, LD, STOP
}
Java坦克大戰網絡版

Java坦克大戰網絡版

Java坦克大戰網絡版

Java坦克大戰網絡版

Java坦克大戰網絡版

Java坦克大戰網絡版

 轉自:http://blog.csdn.net/slience_perseverance/article/details/7844993

 

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!