unity3d Unity多人游戏服务器客户端因鼠标输入旋转而失去同步

ryoqjall  于 2022-11-25  发布在  其他
关注(0)|答案(1)|浏览(111)

我目前正致力于实现我的第一个多人系统与服务器权威和客户端预测与服务器协调。但我遇到了一个问题,我只是不知道别人已经解决了。我已经实现了一个固定的时间步系统根据教程,我发现:https://github.com/Ajackster/ClientPredictionTutorial/blob/master/Assets/Scripts/Client.cs,在每个时间步中,我处理用户的按键并相应地改变速度。在我开始用鼠标输入改变旋转之前,这一直很好。用户输入和鼠标输入在Update中读取()函数,我认为这是我的去同步问题的根源。我的客户端正在改变它的旋转与每一帧。但服务器仅在其以固定时间步“handleTick”从客户端接收到旋转时才改变其输入()”方法。我相信这会导致客户端对象的速度和服务器对象的速度不同步。因为客户端的速度会随着每次渲染而更新(如果我们在每个更新帧中接收到新的鼠标输入,则可能会发生这种情况),但我的服务器的速度仅在固定时间步长调用中发生变化,该调用的调用频率可能低于或高于update()
我希望这对你们这些聪明的人有一定的意义。有什么办法来处理这个问题吗?请原谅这个垃圾代码,但这是我的项目的一个片段

void Update()
    {
        timer += Time.deltaTime;
        

        if (!isServer)
        {
            verticalAxisInput = 0;
            horizonalAxisInput = 0;
            if (inputManager.getKeyManager().getKey("w"))
            {
                verticalAxisInput = 1;
            }
            else if (inputManager.getKeyManager().getKey("s"))
            {
                verticalAxisInput = -1;
            }
            
            if (inputManager.getKeyManager().getKey("d"))
            {
                horizonalAxisInput = 1;
            }
            if (inputManager.getKeyManager().getKey("a"))
            {
                horizonalAxisInput = -1;
            }
EDIT: The below line was the source of the bug. needs to be moved after transform.localRotation update
            playerInput = (transform.forward * verticalAxisInput) + (transform.right * horizonalAxisInput);
            
            pressJump = inputManager.getSingleKeyInput("space") > 0;
            pressSprint = inputManager.getSingleKeyInput("left shift") > 0;
            mouseX = Input.GetAxis(InputKeys.MOUSE_X_AXIS);
            mouseY = Input.GetAxis(InputKeys.MOUSE_Y_AXIS);
            
            playerCam.transform.localRotation = lookY(mouseY);
            transform.localRotation = lookX(mouseX);
        }

        while (timer >= MIN_TIME_BETWEEN_TICKS)
        {
            timer -= MIN_TIME_BETWEEN_TICKS;

            handleTick();
            currentTick++;
        }  

private void handleTick()
    {
        if (isServer)
        {
            PlayerInputPacket packet = RemoteDataConnection.instance.getData();
            pressJump = inputManager.getSingleKeyInput("space") > 0;
            transform.localRotation = packet.playerRot;
            inputManager.getKeyManager().setKeyMap(packet.keyMap);
            
            verticalAxisInput = 0;
            horizonalAxisInput = 0;
            if (inputManager.getKeyManager().getKey("w"))
            {
                verticalAxisInput = 1;
            }
            else if (inputManager.getKeyManager().getKey("s"))
            {
                verticalAxisInput = -1;
            }
            
            if (inputManager.getKeyManager().getKey("d"))
            {
                horizonalAxisInput = 1;
            }
            if (inputManager.getKeyManager().getKey("a"))
            {
                horizonalAxisInput = -1;
            }
         
            playerInput = (transform.forward * verticalAxisInput) + (transform.right * horizonalAxisInput);
        }
        else
        {
            ClientDataConnection.instance.writeData(new PlayerInputPacket(inputManager.getKeyManager().getKeyMap(), transform.localRotation));
        }
        
        if (currentJumpCoolDown > 0)
        {
            currentJumpCoolDown--;
        }


        move(playerInput, pressJump, pressSprint);
    }
epfja78i

epfja78i1#

发现问题。客户端正在计算更新中的输入速度()循环,但服务器是在固定时间步tick方法中执行此操作的。当客户端在固定时间步方法中计算此值时,我的问题得到了解决。我不知道“我不完全理解这是如何解决问题的,因为当客户端处理输入时,它也会向服务器发送它的旋转值,所以我认为服务器和客户端会得到同样结果,但肯定不是这样的。如果有人明白为什么会这样,我真的很感激你的回答

playerInput = (transform.forward * verticalAxisInput) + (transform.right * horizonalAxisInput);
    move(playerInput, pressJump, pressSprint);

修复后完整代码:

void Update()
    {
        timer += Time.deltaTime;
        

        if (!isServer)
        {
            verticalAxisInput = 0;
            horizonalAxisInput = 0;
            if (inputManager.getKeyManager().getKey("w"))
            {
                verticalAxisInput = 1;
            }
            else if (inputManager.getKeyManager().getKey("s"))
            {
                verticalAxisInput = -1;
            }
            
            if (inputManager.getKeyManager().getKey("d"))
            {
                horizonalAxisInput = 1;
            }
            if (inputManager.getKeyManager().getKey("a"))
            {
                horizonalAxisInput = -1;
            }

            pressJump = inputManager.getSingleKeyInput("space") > 0;
            pressSprint = inputManager.getSingleKeyInput("left shift") > 0;
            mouseX = Input.GetAxis(InputKeys.MOUSE_X_AXIS);
            mouseY = Input.GetAxis(InputKeys.MOUSE_Y_AXIS);
            
            playerCam.transform.localRotation = lookY(mouseY);
            transform.localRotation = lookX(mouseX);
            Debug.Log(characterController.velocity);
        }

        while (timer >= MIN_TIME_BETWEEN_TICKS)
        {
            timer -= MIN_TIME_BETWEEN_TICKS;

            handleTick();
            currentTick++;
        }

        doWeaponBounce();
    }

    private void handleTick()
    {
        if (isServer)
        {
            PlayerInputPacket packet = RemoteDataConnection.instance.getData();
            pressJump = inputManager.getSingleKeyInput("space") > 0;
            transform.localRotation = packet.playerRot;
            inputManager.getKeyManager().setKeyMap(packet.keyMap);
            
            verticalAxisInput = 0;
            horizonalAxisInput = 0;
            if (inputManager.getKeyManager().getKey("w"))
            {
                verticalAxisInput = 1;
            }
            else if (inputManager.getKeyManager().getKey("s"))
            {
                verticalAxisInput = -1;
            }
            
            if (inputManager.getKeyManager().getKey("d"))
            {
                horizonalAxisInput = 1;
            }
            if (inputManager.getKeyManager().getKey("a"))
            {
                horizonalAxisInput = -1;
            }
        }
        else
        {
            ClientDataConnection.instance.writeData(new PlayerInputPacket(inputManager.getKeyManager().getKeyMap(), transform.localRotation));
        }
        
        if (currentJumpCoolDown > 0)
        {
            currentJumpCoolDown--;
        }

        playerInput = (transform.forward * verticalAxisInput) + (transform.right * horizonalAxisInput);
        move(playerInput, pressJump, pressSprint);
    }

相关问题