多人游戏中的线性脉冲和错误位置

f4t66c6m  于 2021-06-29  发布在  Java
关注(0)|答案(1)|浏览(347)

我正在用libgdx创建一个游戏。我最初是跟随一个超级马里奥兄弟游戏教程从youtube,然而,我已经改变了游戏,包括我自己的人物和图形。我使用kryonet作为一种手段,包括在我的游戏多人功能。这就是我遇到几个问题的地方。
首先,我使用线性冲动进行移动,所以当我的角色打到一个通电,有一个线性冲动应用,他们被赋予力量,向前移动更快。这很管用,直到你看两个屏幕,角色a的位置在一个玩家的屏幕上是不同的,而在另一个玩家的屏幕上是不同的。我得到的两个字符的线性脉冲值也不同。我正常的右,左,上的动作也是用线性冲动完成的。由于线性脉冲值的随机性,我得到了这个误差,我想说的是,就像一个滑动的冰误差,把一个冰块推过一个表面并不总是保证相同的位置。下面是我的多人客户端类的一些代码。

client.addListener(new ThreadedListener(new Listener() {
            // What to do with the packets.
            public void connected(Connection connection) {

            }

            public void received(Connection connection, Object object) {

                if (object instanceof MovementJump) {
                    MovementJump packet = (MovementJump) object;

                    PlayScreen.player.b2body.applyLinearImpulse(new Vector2(0, 4f),
                            PlayScreen.player.b2body.getWorldCenter(), true);
                }

                if (object instanceof MovementRight) {
                    MovementRight packet = (MovementRight) object;

                    PlayScreen.player.b2body.applyLinearImpulse(new Vector2(packet.impulse, 0),
                            PlayScreen.player.b2body.getWorldCenter(), true);
                }

                if (object instanceof MovementLeft) {
                    MovementLeft packet = (MovementLeft) object;

                    PlayScreen.player.b2body.applyLinearImpulse(new Vector2(-packet.impulse, 0),
                            PlayScreen.player.b2body.getWorldCenter(), true);
                }

                if (object instanceof MovementP2Jump) {
                    MovementP2Jump packet = (MovementP2Jump) object;

                    PlayScreen.player2.b2body.applyLinearImpulse(new Vector2(0, 4f),
                            PlayScreen.player2.b2body.getWorldCenter(), true);
                }

                if (object instanceof MovementP2Right) {
                    MovementP2Right packet = (MovementP2Right) object;

                    PlayScreen.player2.b2body.applyLinearImpulse(new Vector2(packet.impulse, 0),
                            PlayScreen.player2.b2body.getWorldCenter(), true);
                }

                if (object instanceof MovementP2Left) {
                    MovementP2Left packet = (MovementP2Left) object;

                    PlayScreen.player2.b2body.applyLinearImpulse(new Vector2(-packet.impulse, 0),
                            PlayScreen.player2.b2body.getWorldCenter(), true);
                }
            }

        }));
    }

这是我屏幕上的一些代码

if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)
                        && player.b2body.getLinearVelocity().x <= player.getMinSpeed()) {

                    MovementRight pos = new MovementRight();
                    MPClient.client.sendTCP(pos);
                }

                if (Gdx.input.isKeyPressed(Input.Keys.LEFT)
                        && player.b2body.getLinearVelocity().x >= -player.getMinSpeed()) {

                    MovementLeft pos = new MovementLeft();
                    MPClient.client.sendTCP(pos);
                }
ndh0cuux

ndh0cuux1#

你应该发送每个角色的坐标,而不是发送力。
为什么?如果应用一个脉冲并发送一个数据包通知其他客户机这个脉冲,那么在ping延迟之后,他们的脉冲将首先被添加,这个延迟永远不会是0。这意味着他们的脉搏将被添加之后,他们的字符将因此永远落后。
我可以想出两种方法来做这件事,但可能还有很多其他的方法!第一种是客户端,第二种是服务器端,两者各有利弊。就我个人而言,我推荐服务器端的结构,因为被黑客攻击的mp游戏确实会让玩家感到厌烦。
客户端结构:
优点(更少的滞后,对滞后的玩家更灵敏的控制)缺点:(易于破解)
每当客户角色的位置发生变化时,发送 PositionUpdatePacket 以你当前的坐标为服务器。这个包只需要包含( float x, float y, byte characterID )
服务器将数据包发送到所有其他连接的客户端。
每个客户端都会根据角色id更新角色。
服务器端结构:
优点(难以破解)缺点:(对落后的玩家React不太灵敏)
当一个玩家输入了一个信息(例如向左移动),然后你发送一个 MoveRequestPacket 以所需的方向到达服务器。每当方向改变或播放器停止时,只需通过tcp发送一次。
服务器更新此播放器并向所需方向移动,即更新方法行为。这将应用脉冲。这里的优势是服务器可以做各种点击框检查和防止移动,如果玩家想穿过墙等,以防止黑客攻击。
服务器连续发送 PositionUpdatePacket 向所有连接的客户端(包括发送请求的客户端)发送当前角色位置,只要角色移动。
每个客户端更新角色。
在两个结构中 PositionUpdatePacket 必须发送到所有连接的客户端连续只要字符移动,这意味着这个数据包将发送很多。为了减少对性能的影响,应该通过udp发送,并且每秒只能发送x次。雷艇以20t/s的速度发射阵地。
如果你派 PositionUpdatePacket 频率比你的 #update 或者 #step 方法然后每个字符将结巴和滞后。为了解决这个问题,你可以使用插值来平滑运动。
我希望这有帮助。祝你好运!

相关问题