首页 > 解决方案 > Libgdx socket.io 敌人移动只出现在第一个连接的客户端

问题描述

我正在使用socket.io(使用node.js)在Libgdx中构建一个mmorpg。我正在尝试创建敌人(怪物,骷髅等)。我创建了一个怪物类,它适用于单人游戏,但我正在尝试在每个在线玩家上正确移动这些敌人。当我运行此代码时,它会在所有客户端上创建敌人,但是当敌人移动时,客户端上不会出现任何动作。所以我需要将每个怪物的位置发送到服务器并在每个客户端获取这些位置客户,但我不知道该怎么做。

我的游戏画面代码:

public class GameScreen implements Screen {

    private final float UPDATE_TIME = 1/60f;
    float timer;
    private Socket socket;
    String id;
    Player player;
    Texture playerTex;
    Texture friendlyPlayerTex;
    Texture monsterTex;
    HashMap<String, FriendlyPlayer> friendlyPlayers;
    HashMap<String, MPMonster> monsters;
    private Multiplayer game;
    TiledMap tiledMap;
    OrthographicCamera camera;
    private Viewport gamePort;
    TiledMapRenderer tiledMapRenderer;
    private Hud hud;
    private World world;
    private Box2DDebugRenderer box2DDebugRenderer;
    private BitmapFont usernameFont;
    private Monster monster;

    public GameScreen(Multiplayer game) {
        this.game = game;

        Gdx.input.setInputProcessor(null);

        playerTex = new Texture("player.png");
        friendlyPlayerTex = new Texture("player.png");
        monsterTex = new Texture("agent.png");

        friendlyPlayers = new HashMap<String, FriendlyPlayer>();
        monsters = new HashMap<String, MPMonster>();

        float w = Gdx.graphics.getWidth() / Multiplayer.PPM;
        float h = Gdx.graphics.getHeight() / Multiplayer.PPM;

        camera = new OrthographicCamera();
        camera.setToOrtho(false,w,h);
        camera.update();

        tiledMap = new TmxMapLoader().load("maps/newmap.tmx");
        tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap, 1 / Multiplayer.PPM);

        world = new World(new Vector2(0, 0), true);
        box2DDebugRenderer = new Box2DDebugRenderer();

        new B2DWorldCreator(world, tiledMap);

        gamePort = new FitViewport(Multiplayer.V_WIDTH / Multiplayer.PPM, Multiplayer.V_HEIGHT / Multiplayer.PPM, camera);

        hud = new Hud(game.batch);

        usernameFont = new BitmapFont(Gdx.files.internal("pixthulhu/raw/font-export.fnt"));
        usernameFont.setUseIntegerPositions(false);
        usernameFont.getData().setScale(1 / 140f);
        usernameFont.setColor(Color.WHITE);

        //monster = new Monster(700, 800, 28, 32, monsterTex, world);

        connectSocket();
        configSocketEvents();
    }

    public void updateServer(float dt) {
        timer += dt;
        if(timer >= UPDATE_TIME && player != null && player.hasMoved()) {
            JSONObject data = new JSONObject();
            try {
                data.put("x", player.getX());
                data.put("y", player.getY());
                data.put("vx", player.body.getLinearVelocity().x);
                data.put("vy", player.body.getLinearVelocity().y);
                data.put("bx", player.body.getPosition().x);
                data.put("by", player.body.getPosition().y);
                data.put("username", player.username);
                socket.emit("playerMoved", data);
            } catch (JSONException e) {
                Gdx.app.log("SOCKET.IO", "Error sending update data!");
            }
        }

        if(timer >= UPDATE_TIME && monster != null && monster.hasMoved()) {
            JSONObject data = new JSONObject();
            try {
                data.put("x", monster.getX());
                data.put("y", monster.getY());
                data.put("vx", monster.body.getLinearVelocity().x);
                data.put("vy", monster.body.getLinearVelocity().y);
                data.put("bx", monster.body.getPosition().x);
                data.put("by", monster.body.getPosition().y);
                socket.emit("monsterMoved", data);
            } catch (JSONException e) {
                Gdx.app.log("SOCKET.IO", "Error sending update data!");
            }
        }
    }

    public void handleInput(){
        if(Gdx.input.isKeyPressed(Input.Keys.Y)) {
            camera.zoom += 0.1f;
        } else if(Gdx.input.isKeyPressed(Input.Keys.H)) {
            camera.zoom -= 0.1f;
        }
    }

    @Override
    public void render (float delta) {
        handleInput();
        updateServer(Gdx.graphics.getDeltaTime());

        world.step(1/60f, 6, 2);

        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        tiledMapRenderer.setView(camera);
        tiledMapRenderer.render();

        box2DDebugRenderer.render(world, camera.combined);

        game.batch.setProjectionMatrix(camera.combined);
        game.batch.begin();

        if(player != null){
            player.update(delta);
            player.draw(game.batch);
            player.handleInput();
        }

        if(monster != null) {
            monster.update(delta);
            monster.draw(game.batch);
            monster.chase(player);
        }

        camera.update();

        for(HashMap.Entry<String, FriendlyPlayer> entry : friendlyPlayers.entrySet()){
            //entry.getValue().update(delta);/////////////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            entry.getValue().draw(game.batch);
            entry.getValue().setPosition();
            usernameFont.draw(game.batch, entry.getValue().username, entry.getValue().bx - 15 / Multiplayer.PPM, entry.getValue().by + 38 / Multiplayer.PPM);
        }

        for(HashMap.Entry<String, MPMonster> entry : monsters.entrySet()){
            entry.getValue().draw(game.batch);
            //entry.getValue().update(delta);
        }

        game.batch.end();

        game.batch.setProjectionMatrix(hud.stage.getCamera().combined);
        hud.stage.draw();
    }

    public void connectSocket(){
        try {
            socket = IO.socket("http://localhost:8080");
            socket.connect();
        } catch(Exception e){
            System.out.println(e);
        }
    }
    public void configSocketEvents(){
        socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                Gdx.app.log("SocketIO", "Connected");
                player = new Player(playerTex, world, camera);
                monster = new Monster(700, 800, 28, 32, monsterTex, world);
            }
        }).on("socketID", new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                JSONObject data = (JSONObject) args[0];
                try {
                    id = data.getString("id");
                    Gdx.app.log("SocketIO", "My ID: " + id);
                } catch (JSONException e) {
                    Gdx.app.log("SocketIO", "Error getting ID");
                }
            }
        }).on("newPlayer", new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                JSONObject data = (JSONObject) args[0];
                try {
                    String playerId = data.getString("id");
                    Gdx.app.log("SocketIO", "New Player Connect: " + id);
                    friendlyPlayers.put(playerId, new FriendlyPlayer(friendlyPlayerTex, world, game));
                }catch(JSONException e){
                    Gdx.app.log("SocketIO", "Error getting New PlayerID");
                }
            }
        }).on("playerDisconnected", new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                JSONObject data = (JSONObject) args[0];
                try {
                    id = data.getString("id");
                    friendlyPlayers.remove(id);
                }catch(JSONException e){
                    Gdx.app.log("SocketIO", "Error getting disconnected PlayerID");
                }
            }
        }).on("playerMoved", new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                JSONObject data = (JSONObject) args[0];
                try {
                    //SEND STATE AND BOX2D
                    String playerId = data.getString("id");
                    Double x = data.getDouble("x");
                    Double y = data.getDouble("y");
                    Double vx = data.getDouble("vx");
                    Double vy = data.getDouble("vy");
                    Double bx = data.getDouble("bx");
                    Double by = data.getDouble("by");
                    String username = data.getString("username");
                    if(friendlyPlayers.get(playerId) != null) {
                        friendlyPlayers.get(playerId).setPosition(x.floatValue(), y.floatValue());
                        friendlyPlayers.get(playerId).vx = vx.floatValue();
                        friendlyPlayers.get(playerId).vy = vy.floatValue();
                        friendlyPlayers.get(playerId).bx = bx.floatValue();
                        friendlyPlayers.get(playerId).by = by.floatValue();
                        friendlyPlayers.get(playerId).username = username;
                        friendlyPlayers.get(playerId).update(Gdx.graphics.getDeltaTime());
                    }
                }catch(JSONException e){
                }
            }
        }).on("getPlayers", new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                JSONArray objects = (JSONArray) args[0];
                try {
                    for(int i = 0; i < objects.length(); i++){
                        /////GET STATE AND SET TO COOP PLAYER
                        FriendlyPlayer coopPlayer = new FriendlyPlayer(friendlyPlayerTex, world, game);
                        Vector2 position = new Vector2();
                        Float vx, vy;
                        Float bx, by;
                        String username;
                        position.x = ((Double) objects.getJSONObject(i).getDouble("x")).floatValue();
                        position.y = ((Double) objects.getJSONObject(i).getDouble("y")).floatValue();
                        vx = ((Double) objects.getJSONObject(i).getDouble("vx")).floatValue();
                        vy = ((Double) objects.getJSONObject(i).getDouble("vy")).floatValue();
                        bx = ((Double) objects.getJSONObject(i).getDouble("bx")).floatValue();
                        by = ((Double) objects.getJSONObject(i).getDouble("by")).floatValue();
                        username = objects.getJSONObject(i).getString("username");
                        coopPlayer.setPosition(position.x, position.y);
                        coopPlayer.vx = vx;
                        coopPlayer.vy = vy;
                        coopPlayer.bx = bx;
                        coopPlayer.by = by;
                        coopPlayer.username = username;
                        friendlyPlayers.put(objects.getJSONObject(i).getString("id"), coopPlayer);
                        coopPlayer.update(Gdx.graphics.getDeltaTime());
                    }
                } catch(JSONException e){

                }
            }
        }).on("newMonster", new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                JSONObject data = (JSONObject) args[0];
                try {
                    String monsterId = data.getString("id");
                    monsters.put(monsterId, new MPMonster(700, 800, 28, 32, monsterTex, world));
                }catch(JSONException e){
                    Gdx.app.log("SocketIO", "Error creating new monster");
                }
            }
        }).on("monsterMoved", new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                JSONObject data = (JSONObject) args[0];
                try {
                    String playerId = data.getString("pid");
                    String monsterId = data.getString("id");
                    Double x = data.getDouble("x");
                    Double y = data.getDouble("y");
                    Double vx = data.getDouble("vx");
                    Double vy = data.getDouble("vy");
                    Double bx = data.getDouble("bx");
                    Double by = data.getDouble("by");
                    if(monsters.get(monsterId) != null) {
                        monsters.get(monsterId).setPosition(x.floatValue(), y.floatValue());
                        monsters.get(monsterId).vx = vx.floatValue();
                        monsters.get(monsterId).vy = vy.floatValue();
                        monsters.get(monsterId).bx = bx.floatValue();
                        monsters.get(monsterId).by = by.floatValue();
                        monsters.get(monsterId).update(Gdx.graphics.getDeltaTime());
                    }
                } catch (JSONException e) {

                }
            }
        }).on("getMonsters", new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                JSONArray objects = (JSONArray) args[0];
                try {
                    for(int i = 0; i < objects.length(); i++){
                        /////GET STATE AND SET TO COOP PLAYER
                        MPMonster monster = new MPMonster(700, 800, 28, 32, monsterTex, world);
                        Vector2 position = new Vector2();
                        Float vx, vy;
                        Float bx, by;
                        position.x = ((Double) objects.getJSONObject(i).getDouble("x")).floatValue();
                        position.y = ((Double) objects.getJSONObject(i).getDouble("y")).floatValue();
                        vx = ((Double) objects.getJSONObject(i).getDouble("vx")).floatValue();
                        vy = ((Double) objects.getJSONObject(i).getDouble("vy")).floatValue();
                        bx = ((Double) objects.getJSONObject(i).getDouble("bx")).floatValue();
                        by = ((Double) objects.getJSONObject(i).getDouble("by")).floatValue();
                        monster.setPosition(position.x, position.y);
                        monster.vx = vx;
                        monster.vy = vy;
                        monster.bx = bx;
                        monster.by = by;
                        monsters.put(objects.getJSONObject(i).getString("id"), monster);
                        //monsters.get(objects.getJSONObject(i).getString("id")).chase(player);
                        monsters.get(objects.getJSONObject(i).getString("id")).update(Gdx.graphics.getDeltaTime());
                        //monster.update(Gdx.graphics.getDeltaTime());
                    }
                } catch(JSONException e){

                }
            }
        });
    }

    @Override
    public void show() {

    }

    @Override
    public void resize(int width, int height) {
        gamePort.update(width, height);
    }

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void hide() {

    }

    @Override
    public void dispose() {
        playerTex.dispose();
        friendlyPlayerTex.dispose();
    }
}

我的怪物代码:

public class Monster extends Sprite {
    private float x;
    private float y;
    private World world;
    private Vector2 previousPosition;
    public Body body;
    private TextureRegion monsterStand;

    public Monster(float x, float y, int w, int h, Texture texture, World world) {
        super(texture);
        this.x = x;
        this.y = y;
        this.world = world;

        monsterStand = new TextureRegion(texture, 0, 0, w, h);

        setBounds(700 / Multiplayer.PPM, 800 / Multiplayer.PPM, 28 / Multiplayer.PPM, 32 / Multiplayer.PPM);
        monsterPhysics();
        setRegion(monsterStand);

        previousPosition = new Vector2(getX(), getY());
    }

    public void update(float dt) {
        setPosition(body.getPosition().x - getWidth() / 2, body.getPosition().y - getHeight() / 2);

        body.applyLinearImpulse(
                (0 - body.getLinearVelocity().x) * body.getMass(),
                (0 - body.getLinearVelocity().y) * body.getMass(),
                body.getWorldCenter().x, body.getWorldCenter().y, true
        );
    }

    public void chase(Player player) {
        float speedX = 0;
        float speedY = 0;

        if(Funcs.distance(body.getPosition(), player.body.getPosition()) <= 1.3f) {
            if(player.body.getPosition().x > body.getPosition().x) {
                speedX = 0.5f;
            } else if(player.body.getPosition().x < body.getPosition().x) {
                speedX = -0.5f;
            } else {
                speedX = 0f;
            }

            if(player.body.getPosition().y > body.getPosition().y) {
                speedY = 0.5f;
            } else if(player.body.getPosition().y < body.getPosition().y) {
                speedY = -0.5f;
            } else {
                speedY = 0f;
            }

            body.applyLinearImpulse(
                    (speedX - body.getLinearVelocity().x) * body.getMass(),
                    (speedY - body.getLinearVelocity().y) * body.getMass(),
                    body.getWorldCenter().x, body.getWorldCenter().y, true
            );
        }
    }

    private void monsterPhysics() {
        BodyDef bdef = new BodyDef();
        PolygonShape shape = new PolygonShape();
        FixtureDef fdef = new FixtureDef();

        Rectangle rect = getBoundingRectangle();

        bdef.type = BodyDef.BodyType.DynamicBody;
        bdef.position.set(700 / Multiplayer.PPM, 800 / Multiplayer.PPM);

        body = world.createBody(bdef);

        shape.setAsBox(rect.getWidth() / 2, rect.getHeight() / 2);

        fdef.shape = shape;

        body.createFixture(fdef);
    }

    public boolean hasMoved(){
        if(previousPosition.x != getX() || previousPosition.y != getY()){
            previousPosition.x = getX();
            previousPosition.y = getY();
            return true;
        }
        return false;
    }
}

我也有 MPMonster 类:

public class MPMonster extends Sprite {
    private float x;
    private float y;
    public float vx;
    public float vy;
    public float bx;
    public float by;
    private World world;
    private Vector2 previousPosition;
    public Body body;
    private TextureRegion monsterStand;

    public MPMonster(float x, float y, int w, int h, Texture texture, World world) {
        super(texture);
        this.x = x;
        this.y = y;
        this.world = world;

        monsterStand = new TextureRegion(texture, 0, 0, w, h);

        setBounds(x / Multiplayer.PPM, y / Multiplayer.PPM, w / Multiplayer.PPM, h / Multiplayer.PPM);
        monsterPhysics();
        setRegion(monsterStand);

        previousPosition = new Vector2(getX(), getY());
    }

    public void update(float dt) {
        //setRegion(getFrame(dt));
        setPosition(body.getPosition().x - getWidth() / 2, body.getPosition().y - getHeight() / 2);
        body.setTransform(bx, by, 0);
    }

    public void chase(Player player) {
        float speedX = 0;
        float speedY = 0;

        if(Funcs.distance(body.getPosition(), player.body.getPosition()) <= 1.3f) {
            if(player.body.getPosition().x > body.getPosition().x) {
                speedX = 0.5f;
            } else if(player.body.getPosition().x < body.getPosition().x) {
                speedX = -0.5f;
            } else {
                speedX = 0f;
            }

            if(player.body.getPosition().y > body.getPosition().y) {
                speedY = 0.5f;
            } else if(player.body.getPosition().y < body.getPosition().y) {
                speedY = -0.5f;
            } else {
                speedY = 0f;
            }

            body.applyLinearImpulse(
                    (speedX - body.getLinearVelocity().x) * body.getMass(),
                    (speedY - body.getLinearVelocity().y) * body.getMass(),
                    body.getWorldCenter().x, body.getWorldCenter().y, true
            );
        }
    }

    private void monsterPhysics() {
        BodyDef bdef = new BodyDef();
        PolygonShape shape = new PolygonShape();
        FixtureDef fdef = new FixtureDef();

        Rectangle rect = getBoundingRectangle();

        bdef.type = BodyDef.BodyType.DynamicBody;
        bdef.position.set(x / Multiplayer.PPM, y / Multiplayer.PPM);

        body = world.createBody(bdef);

        shape.setAsBox(rect.getWidth() / 2, rect.getHeight() / 2);

        fdef.shape = shape;

        body.createFixture(fdef);
    }

    public boolean hasMoved(){
        if(previousPosition.x != getX() || previousPosition.y != getY()){
            previousPosition.x = getX();
            previousPosition.y = getY();
            return true;
        }
        return false;
    }
}

我的服务器代码:

var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var players = [];
var monsters = [];

server.listen(8080, function(){
    console.log("Server is now running...");
});

io.on('connection', function(socket){
    console.log("Player Connected!");
    monsterID = ID();
    socket.emit('socketID', { id: socket.id });
    socket.emit('getPlayers', players);
    socket.emit('getMonsters', monsters);
    socket.broadcast.emit('newPlayer', { id: socket.id });
    socket.broadcast.emit('newMonster', { id: monsterID });
    socket.on('playerMoved', function(data) {
        data.id = socket.id;
        socket.broadcast.emit('playerMoved', data);

        for(var i = 0; i < players.length; i++) {
            if(players[i].id == data.id) {
                players[i].username = data.username;
                players[i].x = data.x;
                players[i].y = data.y;
                players[i].vx = data.vx;
                players[i].vy = data.vy;
                players[i].bx = data.bx;
                players[i].by = data.by;
            }
        }
    });
    socket.on('monsterMoved', function(data) {
        data.id = monsterID;
        data.pid = socket.id;
        socket.broadcast.emit('monsterMoved', data);

        for(var i = 0; i < monsters.length; i++) {
            if(monsters[i].id == data.id) {
                monsters[i].x = data.x;
                monsters[i].y = data.y;
                monsters[i].vx = data.vx;
                monsters[i].vy = data.vy;
                monsters[i].bx = data.bx;
                monsters[i].by = data.by;
            }
        }
    });
    socket.on('disconnect', function(){
        console.log("Player Disconnected");
        socket.broadcast.emit('playerDisconnected', { id: socket.id });
        for(var i = 0; i < players.length; i++){
            if(players[i].id == socket.id){
                players.splice(i, 1);
            }
        }
    });
    players.push(new player(socket.id, "", 900 / 100, 600 / 100, 0, 0, 0, 0));
    monsters.push(new monster(monsterID, 700 / 100, 800 / 100, 0, 0, 700 / 100, 800 / 100));
});

function player(id, username, x, y, vx, vy, bx, by){
    this.id = id;
    this.username = username;
    this.x = x;
    this.y = y;
    this.vx = vx;
    this.vy = vy;
    this.bx = bx;
    this.by = by;
}

function monster(id, x, y, vx, vy, bx, by) {
    this.id = id;
    this.x = x;
    this.y = y;
    this.vx = vx;
    this.vy = vy;
    this.bx = bx;
    this.by = by;
}

var ID = function () {
    return Math.random().toString().substr(2, 9);
  };

标签: javascriptjavanode.jssocket.iolibgdx

解决方案


推荐阅读