凉渃渃 2021-06-21 00:23 采纳率: 80%
浏览 13

有关java游戏网络传输协议莫名中断

package client.protocol;

import client.bean.Dir;
import client.bean.Push;
import client.bean.Tee;
import client.client.TeeClient;

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;

/**
 * Created by lichunxuan on 2021/6/19.
 */
public class TeeThrewMsg implements Msg {

        private int msgType = Msg.TEE_MOVE_MSG;
        private int teeId;
        private TeeClient tc;
        private Push p;
        private int x, y;
        private Dir dir;
        private Dir ptDir;

        public TeeThrewMsg(int teeId,int x,int y,Dir dir, Dir ptDir,Push p){
            this.x=x;
            this.y=y;
            this.dir=dir;
            this.ptDir=ptDir;
            this.teeId = teeId;
            this.p = p;
        }

        public TeeThrewMsg(TeeClient tc){
            this.tc = tc;
        }

        @Override
        public void send(DatagramSocket ds, String IP, int UDP_Port) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream(30);//指定大小, 免得字节数组扩容占用时间
            DataOutputStream dos = new DataOutputStream(baos);
            try {
                dos.writeInt(msgType);
                dos.writeInt(teeId);
                dos.writeInt(p.getX() - 20);
                dos.writeInt(p.getY() - 20);
                dos.writeInt(dir.ordinal());
                dos.writeInt(ptDir.ordinal());
                dos.writeInt(x);
                dos.writeInt(y);

            } catch (IOException e) {
                e.printStackTrace();
            }
            byte[] buf = baos.toByteArray();
            try{
                DatagramPacket dp = new DatagramPacket(buf, buf.length, new InetSocketAddress(IP, UDP_Port));
                ds.send(dp);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void parse(DataInputStream dis) {
            try{
                int id = dis.readInt();
                if(id == this.tc.getMyTee().getId()){
                    return;
                }
                Dir dir = Dir.values()[dis.readInt()];
                Dir ptDir = Dir.values()[dis.readInt()];
                int x = dis.readInt();
                int y = dis.readInt();
                for(Tee t : tc.getTees()){
                    if(t.getId() == id){
                        t.setDir(dir);
                        t.setPtDir(ptDir);
                        t.setX(x);
                        t.setY(y);
                        break;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
}

在这个协议运行之前,坦克仍能正常移动,但是一旦进行了这个操作,那么被push的坦克会被强制移动,这个在其他玩家界面能看到,但是在发出push命令的玩家界面看不到,并且一旦坦克被push之后所进行的所有操作都不会再被上传,无法在其他玩家的界面显示出操作。

下面补充一下这个方法

这个是在坦克类里对push行为进行的反应

 @Override
    public void actionToTeePushEvent(TeePushEvent teePushEvent) {
        this.tc.getExplodes().add(new Explode(teePushEvent.getSource().getX() - 20,
                teePushEvent.getSource().getY() - 20, this.tc));//tee自身产生一个爆炸
        this.dir=teePushEvent.getSource().getDir();
        this.ptDir=teePushEvent.getSource().getDir();
        this.threw();
        this.dir= Dir.STOP;
        this.dir= Dir.STOP;
        TeeThrewMsg msg = new TeeThrewMsg(this.id,this.x,this.y,this.dir,this.ptDir,teePushEvent.getSource());
        this.tc.getNc().send(msg);
    }

这个是用户个人界面的paint方法

 public void paint(Graphics g) {
        g.drawString("missiles count:" + missiles.size(), 10, 50);
        g.drawString("explodes count:" + explodes.size(), 10, 70);
        g.drawString("tees    count:" + tees.size(), 10, 90);

        for(int i = 0; i < missiles.size(); i++) {
            Missile m = missiles.get(i);
            if (m.hitTee(myTee)) {
                /*TeeDeadMsg msg = new TeeDeadMsg(myTee.getId());
                nc.send(msg);*/
                MissileDeadMsg mmsg = new MissileDeadMsg(m.getTeeId(), m.getId());
                nc.send(mmsg);
               /* nc.sendClientDisconnectMsg();
                gameOverDialog.setVisible(true);*/
            }
            m.draw(g);
        }
        for(int i = 0; i < pushes.size(); i++) {
                Push p = pushes.get(i);
                if(p.hitTee(myTee)){
                    PushDeadMsg mmsg = new PushDeadMsg(p.getTeeId(), p.getId());
                    nc.send(mmsg);
                }
                p.draw(g);

        }
        for(int i = 0; i < explodes.size(); i++) {
            Explode e = explodes.get(i);
            e.draw(g);
        }
        for(int i = 0; i < tees.size(); i++) {
            Tee t = tees.get(i);
                t.draw(g);
            }
        if(null != myTee){
            myTee.draw(g);
        }
    }

这个是反应

package client.strategy;

import client.bean.Push;
import client.bean.Tee;
import client.protocol.PushNewMsg;

/**
 * Created by lichunxuan on 2021/6/18.
 */
public class NormalPushAction implements PushAction {
    @Override
    public void pushAction(Tee tee) {
        if(!tee.isLive()) return;
        int x = tee.getX() + 15 - 5;//确定推动的坐标
        int y = tee.getY() + 15 - 5;
        Push p = new Push(tee.getId(), x, y, tee.isGood(), tee.getPtDir(), tee.getTc());//产生一个推动
        tee.getTc().getPushes().add(p);

        PushNewMsg msg = new PushNewMsg(p);
        tee.getTc().getNc().send(msg);

    }
}

补充一下,在进行发出push类子弹打到人之前,所有用户正常,一旦打到人,被打到的坦克界面:坦克会被推动,但是之后所有操作不能再被其他坦克界面收到,而发出push类子弹的用户做出的操作,能被 被打到的坦克收到。

 

最后补充可能有用的代码段

package client.event;

import client.bean.Push;

/**
 * Created by lichunxuan on 2021/6/18.
 */
public class TeePushEvent {
    private Push source;

    public TeePushEvent(Push source){
        this.source = source;
    }

    public Push getSource() {
        return source;
    }

}
import java.awt.*;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by lichunxuan on 2021/6/19.
 */
public class Push {
        public static final int XSPEED = 20;
        public static final int YSPEED = 20;
        private static int ID = 10;

        private int id;
        private TeeClient tc;
        private int teeId;
        private int x, y;
        private Dir dir = Dir.R;
        private boolean live = true;
        private boolean good;

        private static Toolkit tk = Toolkit.getDefaultToolkit();
        private static Image[] imgs = null;
        private static Map<String, Image> map = new HashMap<>();
        static{
            imgs = new Image[]{
                    tk.getImage(client.bean.Push.class.getClassLoader().getResource("client/images/push/m.png")),
                    tk.getImage(client.bean.Push.class.getClassLoader().getResource("client/images/push/n.png"))
            };
            map.put("n", imgs[0]);
            map.put("m", imgs[1]);
        }
        public static final int WIDTH = imgs[0].getWidth(null);
        public static final int HEIGHT = imgs[0].getHeight(null);

        public Push(int teeId, int x, int y, boolean good, Dir dir) {
            this.teeId = teeId;
            this.x = x;
            this.y = y;
            this.good = good;
            this.dir = dir;
            this.id = ID++;
        }

        public Push(int teeId, int x, int y, boolean good, Dir dir, TeeClient tc) {
            this(teeId, x, y, good, dir);
            this.tc = tc;
        }

        public void draw(Graphics g) {
            if(!live) {
                tc.getPushes().remove(this);
                return;
            }
            g.drawImage(good ? map.get("n") : map.get("m"), x, y, null);
            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 > TeeClient.GAME_WIDTH || y > TeeClient.GAME_HEIGHT) {
                live = false;
            }
        }

        public Rectangle getRect() {
            return new Rectangle(x, y, imgs[0].getWidth(null), imgs[0].getHeight(null));
        }

        public boolean hitTee(Tee t) {//子弹击中坦克的方法
            if(this.live && t.isLive() && this.good != t.isGood() && this.getRect().intersects(t.getRect())) {
                this.live = false;//子弹死亡
                t.actionToTeePushEvent(new TeePushEvent(this));//告知观察的坦克被打中了
                return true;
            }
            return false;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public void setLive(boolean live) {
            this.live = live;
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }

        public Dir getDir() {
            return dir;
        }

        public boolean isGood() {
            return good;
        }

        public int getTeeId() {
            return teeId;
        }

}
package client.client;

import client.bean.*;
import client.protocol.MissileDeadMsg;
import client.protocol.PushDeadMsg;
import client.protocol.TeeDeadMsg;

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;

public class TeeClient extends Frame {
    public static final int GAME_WIDTH = 800;
    public static final int GAME_HEIGHT = 600;
    private Image offScreenImage = null;

    private Monitor monitor = new Monitor(this);
    public Tee myTee;//客户端的坦克
    private NetClient nc = new NetClient(this);
    private ConDialog dialog = new ConDialog();
    private GameOverDialog gameOverDialog = new GameOverDialog();
    private UDPPortWrongDialog udpPortWrongDialog = new UDPPortWrongDialog();
    private ServerNotStartDialog serverNotStartDialog = new ServerNotStartDialog();

    private List<Missile> missiles = new ArrayList<>();//存储游戏中的子弹集合
    private List<Push> pushes=new ArrayList<>();//存储推动的集合
    private List<Explode> explodes = new ArrayList<>();//爆炸集合
    private List<Tee> tees = new ArrayList<>();//坦克集合

    @Override
    public void paint(Graphics g) {
        g.drawString("missiles count:" + missiles.size(), 10, 50);
        g.drawString("explodes count:" + explodes.size(), 10, 70);
        g.drawString("tees    count:" + tees.size(), 10, 90);

        for(int i = 0; i < missiles.size(); i++) {
            Missile m = missiles.get(i);
            if (m.hitTee(myTee)) {
                /*TeeDeadMsg msg = new TeeDeadMsg(myTee.getId());
                nc.send(msg);*/
                MissileDeadMsg mmsg = new MissileDeadMsg(m.getTeeId(), m.getId());
                nc.send(mmsg);
               /* nc.sendClientDisconnectMsg();
                gameOverDialog.setVisible(true);*/
            }
            m.draw(g);
        }
        for(int i = 0; i < pushes.size(); i++) {
                Push p = pushes.get(i);
                if(p.hitTee(myTee)){
                    PushDeadMsg mmsg = new PushDeadMsg(p.getTeeId(), p.getId());
                    nc.send(mmsg);
                }
                p.draw(g);

        }
        for(int i = 0; i < explodes.size(); i++) {
            Explode e = explodes.get(i);
            e.draw(g);
        }
        for(int i = 0; i < tees.size(); i++) {
            Tee t = tees.get(i);
                t.draw(g);
            }
        if(null != myTee){
            myTee.draw(g);
        }
    }

    @Override
    public void update(Graphics g) {
        if(offScreenImage == null) {
            offScreenImage = this.createImage(800, 600);
        }
        Graphics gOffScreen = offScreenImage.getGraphics();
        Color c = gOffScreen.getColor();
        gOffScreen.setColor(Color.LIGHT_GRAY);
        gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
        gOffScreen.setColor(c);
        paint(gOffScreen);
        g.drawImage(offScreenImage, 0, 0, null);
    }

    public void launchFrame() {
        this.setLocation(400, 300);
        this.setSize(GAME_WIDTH, GAME_HEIGHT);
        this.setTitle("TeeClient");
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                nc.sendClientDisconnectMsg();//关闭窗口前要向服务器发出注销消息.
                System.exit(0);
            }
        });
        this.setResizable(false);
        this.setBackground(Color.LIGHT_GRAY);

        this.addKeyListener(new Monitor(this));

        this.setVisible(true);

        new Thread(new PaintThread()).start();

        dialog.setVisible(true);
    }

    public static void main(String[] args) {
        TeeClient tc = new TeeClient();
        tc.launchFrame();
    }

    /**
     * 重画线程
     */
    class PaintThread implements Runnable {
        public void run() {
            while(true) {
                repaint();
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 游戏开始前连接到服务器的对话框
     */
    class ConDialog extends Dialog{
        Button b = new Button("connect to server");
        TextField tfIP = new TextField("127.0.0.1", 15);//服务器的IP地址
        TextField tfTeeName = new TextField("myTee", 8);

        public ConDialog() {
            super(TeeClient.this, true);
            this.setLayout(new FlowLayout());
            this.add(new Label("server IP:"));
            this.add(tfIP);
            this.add(new Label("tee name:"));
            this.add(tfTeeName);
            this.add(b);
            this.setLocation(500, 400);
            this.pack();
            this.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    setVisible(false);
                    System.exit(0);
                }
            });
            b.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    String IP = tfIP.getText().trim();
                    String teeName = tfTeeName.getText().trim();
                    myTee = new Tee(teeName, 50 + (int)(Math.random() * (GAME_WIDTH - 100)),
                            50 + (int)(Math.random() * (GAME_HEIGHT - 100)), true, Dir.STOP, TeeClient.this);
                    nc.connect(IP);
                    setVisible(false);
                }
            });
        }
    }

    /**
     * 坦克死亡后退出的对话框
     */
    class GameOverDialog extends Dialog{
        Button b = new Button("exit");
        public GameOverDialog() {
            super(TeeClient.this, true);
            this.setLayout(new FlowLayout());
            this.add(new Label("Game Over~"));
            this.add(b);
            this.setLocation(500, 400);
            this.pack();
            this.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    System.exit(0);
                }
            });
            b.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    System.exit(0);
                }
            });
        }
    }

    /**
     * UDP端口分配失败后的对话框
     */
    class UDPPortWrongDialog extends Dialog{
        Button b = new Button("ok");
        public UDPPortWrongDialog() {
            super(TeeClient.this, true);
            this.setLayout(new FlowLayout());
            this.add(new Label("something wrong, please connect again"));
            this.add(b);
            this.setLocation(500, 400);
            this.pack();
            this.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    System.exit(0);
                }
            });
            b.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    System.exit(0);
                }
            });
        }
    }

    /**
     * 连接服务器失败后的对话框
     */
    class ServerNotStartDialog extends Dialog{
        Button b = new Button("ok");
        public ServerNotStartDialog() {
            super(TeeClient.this, true);
            this.setLayout(new FlowLayout());
            this.add(new Label("The server has not been opened yet..."));
            this.add(b);
            this.setLocation(500, 400);
            this.pack();
            this.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    System.exit(0);
                }
            });
            b.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    System.exit(0);
                }
            });
        }
    }

    public void gameOver(){
        this.gameOverDialog.setVisible(true);
    }

    public List<Missile> getMissiles() {
        return missiles;
    }


    public List<Explode> getExplodes() {
        return explodes;
    }

    public List<Tee> getTees() {
        return tees;
    }


    public Tee getMyTee() {
        return myTee;
    }

    public NetClient getNc() {
        return nc;
    }

    public UDPPortWrongDialog getUdpPortWrongDialog() {
        return udpPortWrongDialog;
    }

    public ServerNotStartDialog getServerNotStartDialog() {
        return serverNotStartDialog;
    }

    public List<Push> getPushes() {
        return pushes;
    }

}
package client.bean;

import client.client.TeeClient;
import client.event.TeeHitEvent;
import client.event.TeeHitListener;
import client.event.TeePushEvent;
import client.event.TeePushListener;
import client.protocol.TeeDeadMsg;
import client.protocol.TeeMoveMsg;
import client.protocol.TeeReduceBloodMsg;
import client.protocol.TeeThrewMsg;
import client.strategy.*;
import client.strategy.Push;

import java.awt.*;
import java.awt.event.KeyEvent;
import java.nio.channels.NonWritableChannelException;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by lichunxuan on 2021/5/11.
 */
public class Tee implements TeeHitListener,TeePushListener,Fire,Push {
    int id;

    public static final int XSPEED = 5;
    public static final int YSPEED = 5;

    private String name;
    private boolean good;
    int x;
    int y;
    private boolean live = true;
    private TeeClient tc;
    Dir dir = Dir.STOP;
    Dir ptDir = Dir.D;
    private int blood = 100;
    private FireAction fireAction = new NormalFireAction();//可以开火
    private PushAction pushAction = new NormalPushAction();//可以推动

    private static Toolkit tk = Toolkit.getDefaultToolkit();
    private static Image[] imgs = null;
    private static Map<String, Image> map = new HashMap<>();
    static{
        imgs = new Image[]{//加载两方阵营的图片
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/tD.png")),
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/tL.png")),
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/tLD.png")),
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/tLU.png")),
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/tR.png")),
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/tRD.png")),
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/tRU.png")),
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/tU.png")),

            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/eD.png")),
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/eL.png")),
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/eLD.png")),
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/eLU.png")),
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/eR.png")),
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/eRD.png")),
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/eRU.png")),
            tk.getImage(Tee.class.getClassLoader().getResource("client/images/tee/eU.png")),
        };
        map.put("tD", imgs[0]);
        map.put("tL", imgs[1]);
        map.put("tLD", imgs[2]);
        map.put("tLU", imgs[3]);
        map.put("tR", imgs[4]);
        map.put("tRD", imgs[5]);
        map.put("tRU", imgs[6]);
        map.put("tU", imgs[7]);
        map.put("eD", imgs[8]);
        map.put("eL", imgs[9]);
        map.put("eLD", imgs[10]);
        map.put("eLU", imgs[11]);
        map.put("eR", imgs[12]);
        map.put("eRD", imgs[13]);
        map.put("eRU", imgs[14]);
        map.put("eU", imgs[15]);
    }

    public static final int WIDTH =  imgs[0].getWidth(null);
    public static final int HEIGHT = imgs[0].getHeight(null);

    public Tee(int x, int y, boolean good, String name) {
        this.x = x;
        this.y = y;
        this.good = good;
        this.name = name;
    }

    public Tee(String name, int x, int y, boolean good, Dir dir, TeeClient tc) {
        this(x, y, good, name);
        this.dir = dir;
        this.tc = tc;
    }

    /**
     * 根据tee阵营画出图片
     * @param g
     */
    public void draw(Graphics g) {
        if(!live) {
            if(!good) {
                tc.getTees().remove(this);
            }
            return;
        }
        switch(ptDir) {
            case L:
                g.drawImage(good ? map.get("tL") : map.get("eL"), x, y, null);
                break;
            case LU:
                g.drawImage(good ? map.get("tLU") : map.get("eLU"), x, y, null);
                break;
            case U:
                g.drawImage(good ? map.get("tU") : map.get("eU"), x, y, null);
                break;
            case RU:
                g.drawImage(good ? map.get("tRU") : map.get("eRU"), x, y, null);
                break;
            case R:
                g.drawImage(good ? map.get("tR") : map.get("eR"), x, y, null);
                break;
            case RD:
                g.drawImage(good ? map.get("tRD") : map.get("eRD"), x, y, null);
                break;
            case D:
                g.drawImage(good ? map.get("tD") : map.get("eD"), x, y, null);
                break;
            case LD:
                g.drawImage(good ? map.get("tLD") : map.get("eLD"), x, y, null);
                break;
        }
        move();
    }

    /**
     * 根据teept的方向进行移动
     */
    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;
                default:
        }

        if(dir != Dir.STOP) {
            ptDir = dir;
        }

        if(x < 0) live=false;
        if(y < 30) live=false;
        if(x + WIDTH > TeeClient.GAME_WIDTH) live=false;
        if(y + HEIGHT > TeeClient.GAME_HEIGHT) live=false;

       if(!live){
           TeeDeadMsg msg = new TeeDeadMsg(this.id);//向其他客户端转发坦克死亡的消息
           this.tc.getNc().send(msg);
           this.tc.getNc().sendClientDisconnectMsg();//和服务器断开连接
           this.tc.gameOver();
       }
    }


    public void threw() {
        switch(dir) {
            case L:
                x -= XSPEED*15;
                break;
            case LU:
                x -= XSPEED*15;
                y -= YSPEED*15;
                break;
            case U:
                y -= YSPEED*15;
                break;
            case RU:
                x += XSPEED*15;
                y -= YSPEED*15;
                break;
            case R:
                x += XSPEED*15;
                break;
            case RD:
                x += XSPEED*15;
                y += YSPEED*15;
                break;
            case D:
                y += YSPEED*15;
                break;
            case LD:
                x -= XSPEED*15;
                y += YSPEED*15;
                break;
            default:
        }
        ptDir = dir;
    }



    @Override
    public void fire() {//发出一颗炮弹的方法
        fireAction.fireAction(this);
    }

    @Override
    public void push(){pushAction.pushAction(this);}

    @Override
    public void actionToTeeHitEvent(TeeHitEvent teeHitEvent) {
        this.tc.getExplodes().add(new Explode(teeHitEvent.getSource().getX() - 20,
                teeHitEvent.getSource().getY() - 20, this.tc));//tee自身产生一个爆炸
        if(this.blood == 1){//坦克每次扣1滴血, 如果只剩下1滴了, 那么就标记为死亡.这个血量设定是为了不让他死
            this.live = false;
            TeeDeadMsg msg = new TeeDeadMsg(this.id);//向其他客户端转发坦克死亡的消息
            this.tc.getNc().send(msg);
            this.tc.getNc().sendClientDisconnectMsg();//和服务器断开连接
            this.tc.gameOver();
            return;
        }
        this.blood -= 1;//血量减少1并通知其他客户端本坦克血量减少1.
        TeeReduceBloodMsg msg = new TeeReduceBloodMsg(this.id, teeHitEvent.getSource());
        this.tc.getNc().send(msg);
    }

//    public boolean threwTee(Tee t) {//两个tee碰撞的方法
//        if(t.dir!=Dir.STOP && this.live && t.isLive() && this.good != t.isGood() && this.getRect().intersects(t.getRect())) {
//            t.actionToTeePushEvent(new TeePushEvent(this));//告知观察的tee相撞了
//            return true;
//        }
//        return false;
//    }

    @Override
    public void actionToTeePushEvent(TeePushEvent teePushEvent) {
        this.tc.getExplodes().add(new Explode(teePushEvent.getSource().getX() - 20,
                teePushEvent.getSource().getY() - 20, this.tc));//tee自身产生一个爆炸
        this.dir=teePushEvent.getSource().getDir();
        this.ptDir=teePushEvent.getSource().getDir();
        this.threw();
        this.dir= Dir.STOP;
        this.dir= Dir.STOP;
        TeeThrewMsg msg = new TeeThrewMsg(this.id,this.x,this.y,this.dir,this.ptDir,teePushEvent.getSource());
        this.tc.getNc().send(msg);
    }

    public Rectangle getRect() {
        return new Rectangle(x, y, imgs[0].getWidth(null), imgs[0].getHeight(null));
    }

    public boolean isLive() {
        return live;
    }

    public void setLive(boolean live) {
        this.live = live;
    }

    public boolean isGood() {
        return good;
    }

    public void setGood(boolean good) {
        this.good = good;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public Dir getDir() {
        return dir;
    }

    public void setDir(Dir dir) {
        this.dir = dir;
    }

    public Dir getPtDir() {
        return ptDir;
    }

    public void setPtDir(Dir ptDir) {
        this.ptDir = ptDir;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getBlood() {
        return blood;
    }

    public void setBlood(int blood) {
        this.blood = blood;
    }

    public String getName() {
        return name;
    }

    public TeeClient getTc() {
        return tc;
    }

    public void setTc(TeeClient tc) {
        this.tc = tc;
    }
}
package client.client;

import client.protocol.*;
import server.TeeServer;

import java.io.*;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.Socket;

/**
 * 网络方法接口
 */
public class NetClient {
    private TeeClient tc;
    private int UDP_PORT;//客户端的UDP端口号
    private String serverIP;//服务器IP地址
    private int serverUDPPort;//服务器转发客户但UDP包的UDP端口
    private int TEE_DEAD_UDP_PORT;//服务器监听坦克死亡的UDP端口
    private DatagramSocket ds = null;//客户端的UDP套接字

    public void setUDP_PORT(int UDP_PORT) {
        this.UDP_PORT = UDP_PORT;
    }

    public NetClient(TeeClient tc){
        this.tc = tc;
        try {
            this.UDP_PORT = getRandomUDPPort();
        }catch (Exception e){
            tc.getUdpPortWrongDialog().setVisible(true);//弹窗提示
            System.exit(0);//如果选择到了重复的UDP端口号就退出客户端重新选择.
        }
    }

    /**
     * 与服务器进行TCP连接
     * @param ip server IP
     */
    public void connect(String ip){
        serverIP = ip;
        Socket s = null;
        try {
            ds = new DatagramSocket(UDP_PORT);//创建UDP套接字
            try {
                s = new Socket(ip, TeeServer.TCP_PORT);//创建TCP套接字
            }catch (Exception e1){
                tc.getServerNotStartDialog().setVisible(true);
            }
            DataOutputStream dos = new DataOutputStream(s.getOutputStream());
            dos.writeInt(UDP_PORT);//向服务器发送自己的UDP端口号
            DataInputStream dis = new DataInputStream(s.getInputStream());
            int id = dis.readInt();//获得自己的id号
            this.serverUDPPort = dis.readInt();//获得服务器转发客户端消息的UDP端口号
            this.TEE_DEAD_UDP_PORT = dis.readInt();//获得服务器监听坦克死亡的UDP端口
            tc.getMyTee().setId(id);//设置坦克的id号
            tc.getMyTee().setGood((id & 1) == 0 ? true : false);//根据坦克的id号分配阵营
            System.out.println("connect to server successfully...");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try{
                if(s != null) s.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        new Thread(new UDPThread()).start();//开启客户端UDP线程, 向服务器发送或接收游戏数据

        TeeNewMsg msg = new TeeNewMsg(tc.getMyTee());//创建坦克出生的消息
        send(msg);
    }

    /**
     * 客户端随机获取UDP端口号
     * @return
     */
    private int getRandomUDPPort(){
        return 55558 + (int)(Math.random() * 9000);
    }

    public void send(Msg msg){
        msg.send(ds, serverIP, serverUDPPort);
    }

    public class UDPThread implements Runnable{

        byte[] buf = new byte[1024];

        @Override
        public void run() {
            while(null != ds){
                DatagramPacket dp = new DatagramPacket(buf, buf.length);
                try{
                    ds.receive(dp);
                    parse(dp);
                } 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.TEE_NEW_MSG :
                    msg = new TeeNewMsg(tc);
                    msg.parse(dis);
                    break;
                case  Msg.TEE_MOVE_MSG :
                    msg = new TeeMoveMsg(tc);
                    msg.parse(dis);
                    break;
                case Msg.MISSILE_NEW_MSG:
                    msg = new MissileNewMsg(tc);
                    msg.parse(dis);
                    break;
                case Msg.TEE_DEAD_MSG:
                    msg = new TeeDeadMsg(tc);
                    msg.parse(dis);
                    break;
                case Msg.MISSILE_DEAD_MSG:
                    msg = new MissileDeadMsg(tc);
                    msg.parse(dis);
                    break;
                case Msg.TEE_ALREADY_EXIST_MSG:
                    msg = new TeeAlreadyExistMsg(tc);
                    msg.parse(dis);
                    break;
                case Msg.TEE_REDUCE_BLOOD_MSG:
                    msg = new TeeReduceBloodMsg(tc);
                    msg.parse(dis);
                    break;
                case Msg.PUSH_NEW_MSG:
                    msg = new PushNewMsg(tc);
                    msg.parse(dis);
                    break;
                case Msg.PUSH_DEAD_MSG:
                    msg = new PushDeadMsg(tc);
                    msg.parse(dis);
                    break;
                case Msg.TEE_THREW_MSG:
                    msg = new TeeThrewMsg(tc);
                    msg.parse(dis);
                    break;
            }
        }
    }

    public void sendClientDisconnectMsg(){
        ByteArrayOutputStream baos = new ByteArrayOutputStream(88);
        DataOutputStream dos = new DataOutputStream(baos);
        try {
            dos.writeInt(UDP_PORT);//发送客户端的UDP端口号, 从服务器Client集合中注销
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(null != dos){
                try {
                    dos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(null != baos){
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        byte[] buf = baos.toByteArray();
        try{
            DatagramPacket dp = new DatagramPacket(buf, buf.length, new InetSocketAddress(serverIP, TEE_DEAD_UDP_PORT));
            ds.send(dp);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 写回答

1条回答 默认 最新

  • 关注

    网络数据的发送与接收最好封装成JAVABEAN,进行对象处理。

    评论

报告相同问题?

悬赏问题

  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题