如何通过统一运动在 C# 控制台上进行玩家运动计算

How to do player movement calculations on c# console from unity movement

问题:我如何在 c# 控制台上根据来自 unity 的玩家输入来计算玩家的位置。

进一步解释,客户端是运行统一的,服务器是一个c#控制台应用程序。当玩家按下移动键时。 (w, 根据本地位置让玩家向前移动,让玩家一直向前移动) 发送给服务器玩家按下w,然后服务器响应并告诉客户端它按下了w,改变玩家 w is pressed bool 为 true。然后角色移动。

本质上,我想弄清楚如何制作一个方程式来完成 unity 所做的事情,但没有 t运行sform,甚至没有 t运行sform 的工作方式,这样我就可以应用到服务器端。

这是客户端代码:

 private void Update()
{
    SendKeysToServer();
    PlayerController();
    PlayerPositionUpdateChecker();
}

public void PlayerController()
{
    if (gameObject.name == ntwmng.Playername)
    {
        MovementControllerPlayer();
        JumpControllerPlayer();
        RotationControllerPlayer();
        MovementFinalizer(); 
    }
    else
    {
        MovementControllerClones();
        JumpControllerClones();
        RotationControllerClones();
        MovementFinalizerClones();
    }
}

public void MovementControllerPlayer()
{
    if (CharContr.isGrounded)
    {
        moveDirection = new Vector3(0, 0, 0);

        if (wKeyDownPlayer)
        {
            moveDirection = moveDirection + new Vector3(0, 0, speed * Time.deltaTime);
        }
        if (sKeyDownPlayer)
        {
            moveDirection = moveDirection + new Vector3(0, 0, -speed * Time.deltaTime);
        }
        if (qKeyDownPlayer)
        {
            moveDirection = moveDirection + new Vector3(-speed * Time.deltaTime, 0, 0);
        }
        if (eKeyDownPlayer)
        {
            moveDirection = moveDirection + new Vector3(speed * Time.deltaTime, 0, 0);
        }

        moveDirection = transform.TransformDirection(moveDirection);
        //moveDirection *= speed; 
    }

}

public void RotationControllerPlayer()
{
    if (dKeyDownPlayer)
    {
        transform.Rotate(0, RotationSpeed * Time.deltaTime, 0);
    }
    if(aKeyDownPlayer)
    {
        transform.Rotate(0, -RotationSpeed * Time.deltaTime, 0);
    }
}

public void JumpControllerPlayer()
{
    if (CharContr.isGrounded)
    {

        if (SpaceKeyDownPlayer)
        {
            moveDirection.y = jumpSpeed * Time.deltaTime;
        } 
    }
}

public void MovementFinalizer()
{
    moveDirection.y -= gravity * Time.deltaTime;
    CharContr.Move(moveDirection);
}

public void CameraAndListenerController()
{
    if (gameObject.name == ntwmng.Playername)
    {
        if (playercam.enabled == false)
        {
            playercam.enabled = true;
        }
        if (AudioListener.enabled == false)
        {
            AudioListener.enabled = true;
        }
    }
    else
    {
        if (playercam.enabled == true)
        {
            playercam.enabled = false;
        }
        if (AudioListener.enabled == true)
        {
            AudioListener.enabled = false;
        }
    }
}

public void SendKeysToServer()
{
    NetworkStream NtwrkStrm = ServerConnection.GetStream();
    IFormatter Formatter = new BinaryFormatter();

    foreach (KeyCode kcode in Enum.GetValues(typeof(KeyCode)))
    {
        if(Input.GetKeyDown(kcode))
        {
            string type = "Movement Update Key Down";
            string kycode = Convert.ToString(kcode);
            //Debug.Log(kycode);
            Formatter.Serialize(NtwrkStrm, type);
            NtwrkStrm.Flush();
            Formatter.Serialize(NtwrkStrm, ntwmng.Playername);
            NtwrkStrm.Flush();
            Formatter.Serialize(NtwrkStrm, kycode);
            NtwrkStrm.Flush();
        }else
        if(Input.GetKeyUp(kcode))
        {
            string type = "Movement Update Key Up";
            string kycode = Convert.ToString(kcode);
            //Debug.Log(kycode);
            Formatter.Serialize(NtwrkStrm, type);
            NtwrkStrm.Flush();
            Formatter.Serialize(NtwrkStrm, ntwmng.Playername);
            NtwrkStrm.Flush();
            Formatter.Serialize(NtwrkStrm, kycode);
            NtwrkStrm.Flush();
        }
    }
}

public void MovementControllerClones()
{
    if (CharContr.isGrounded)
    {
        moveDirection = new Vector3(0, 0, 0);

        if (wKeyDownClone)
        {
            moveDirection = moveDirection + new Vector3(0, 0, speed * Time.deltaTime);
        }
        if (sKeyDownClone)
        {
            moveDirection = moveDirection + new Vector3(0, 0, -speed * Time.deltaTime);
        }
        if (qKeyDownClone)
        {
            moveDirection = moveDirection + new Vector3(-speed * Time.deltaTime, 0, 0);
        }
        if (eKeyDownClone)
        {
            moveDirection = moveDirection + new Vector3(speed * Time.deltaTime, 0, 0);
        }

        moveDirection = transform.TransformDirection(moveDirection);
        //moveDirection *= speed;
    }

}

public void RotationControllerClones()
{
    if (dKeyDownClone)
    {
        transform.Rotate(0, RotationSpeed * Time.deltaTime, 0);
    }
    if (aKeyDownClone)
    {
        transform.Rotate(0, -RotationSpeed * Time.deltaTime, 0);
    }
}

public void JumpControllerClones()
{
    if (CharContr.isGrounded)
    {

        if (SpaceKeyDownClone)
        {
            moveDirection.y = jumpSpeed* Time.deltaTime;
        }
    }
}

public void MovementFinalizerClones()
{
    moveDirection.y -= gravity * Time.deltaTime;
    CharContr.Move(moveDirection);
}

public void CloneKeyUpdater(string type,string kcode)
{
    //Debug.Log("Key " + kcode + " Clone Updating");
    if (type == "Movement Update Key Down")
    {
        if (kcode == "W")
        {
            wKeyDownClone = true;
        }
        if (kcode == "A")
        {
            aKeyDownClone = true;
        }
        if (kcode == "D")
        {
            dKeyDownClone = true;
        }
        if (kcode == "S")
        {
            sKeyDownClone = true;
        }
        if (kcode == "Q")
        {
            qKeyDownClone = true;
        }
        if (kcode == "E")
        {
            eKeyDownClone = true;
        }
        if (kcode == "Space")
        {
            SpaceKeyDownClone = true;
        }
    }
    else if (type == "Movement Update Key Up")
    {
        if (kcode == "W")
        {
            wKeyDownClone = false;
        }
        if (kcode == "A")
        {
            aKeyDownClone = false;
        }
        if (kcode == "D")
        {
            dKeyDownClone = false;
        }
        if (kcode == "S")
        {
            sKeyDownClone = false;
        }
        if (kcode == "Q")
        {
            qKeyDownClone = false;
        }
        if (kcode == "E")
        {
            eKeyDownClone = false;
        }
        if (kcode == "Space")
        {
            SpaceKeyDownClone = false;
        }
    }
}

public void PlayerKeyUpdater(string type, string kcode)
{
    //Debug.Log("Key down " + kcode + " Updating");
    if (type == "Movement Update Key Down")
    {
        if (kcode == "W")
        {
            wKeyDownPlayer = true;
        }
        if (kcode == "A")
        {
            aKeyDownPlayer = true;
        }
        if (kcode == "D")
        {
            dKeyDownPlayer = true;
        }
        if (kcode == "S")
        {
            sKeyDownPlayer = true;
        }
        if (kcode == "Q")
        {
            qKeyDownPlayer = true;
        }
        if (kcode == "E")
        {
            eKeyDownPlayer = true;
        }
        if (kcode == "Space")
        {
            SpaceKeyDownPlayer = true;
        }
    }
    else if (type == "Movement Update Key Up")
    {
        if (kcode == "W")
        {
            wKeyDownPlayer = false;
        }
        if (kcode == "A")
        {
            aKeyDownPlayer = false;
        }
        if (kcode == "D")
        {
            dKeyDownPlayer = false;
        }
        if (kcode == "S")
        {
            sKeyDownPlayer = false;
        }
        if (kcode == "Q")
        {
            qKeyDownPlayer = false;
        }
        if (kcode == "E")
        {
            eKeyDownPlayer = false;
        }
        if (kcode == "Space")
        {
            SpaceKeyDownPlayer = false;
        }
    }
}

任何帮助将不胜感激。 :)

编辑: 所以我想出了一个方程式,我用它来尝试和模仿玩家的运动,截至目前,它只能在 0 到 90 度之间工作,只要告诉我它是准确的。方程式非常接近,但只有一点点偏差。有什么建议么?此外,这是客户端的 运行,不受服务器影响,因此我可以精确计算。数学结果比玩家当前位置慢大约每秒 1 个单位。基本上,在速度 = 20 的情况下按 w 1 秒后,数学结果为 19,实际位置为 20。

这是代码

    if (CharContr.velocity != Vector3.zero)//checks if the player is moving
    {
        if (rotation < 90f && rotation > 0f) // makes sure the rotation is 0-90
        {
            percent = (100 / (90 / rotation)) / 100; // gets the percent
            x = x + (percent * speed * Time.deltaTime); //adds to current position multiplied by speed and delta time
            invertPercent = 1 - percent; //gets the percent for z
            z = z + (invertPercent * speed * Time.deltaTime); // adds and stuff again
        }

将键码发送到服务器并根据 bool 同步位置不是最佳做法。

好的做法是,将 x、y 和 z 位置的 3 个浮点值发送到服务器,然后将其广播给其他玩家。 所以其他玩家有没有近似的确切位置

对不起,如果我回答错了地方,因为我没有足够的代表发表评论。

如果你想自己实现它而不是使用 Unity 的内置 NetworkTransform,这真的比你想象的要复杂。阅读这篇 "Client-Side Prediction and Server Reconciliation" 文章。那篇文章有很多部分,但它向您展示了发生了什么以及如何完成的。

尽管如此,如果您使用 Rigidbody,Unity 会通过提供一个新函数 (Physics.Simulate) 简化其中的一部分。您使用 Physics.Simulate 函数模拟服务器上的所有刚体,序列化每个刚体的变换并发送给所有客户端。

在客户端上,接收数据,反序列化它们,然后从当前转换到接收到的转换。您可以找到一个示例,说明如何使用 Physics.Simulate 在 x 秒 .

中确定刚体的位置

所以我做了一些搜索并提出了一个解决方案,这仅适用于玩家向前移动并且玩家方向在 0 到 90 之间的情况。基本上我必须使用 transform.translate 而不是使用角色控制器。我这样做的原因是,当玩家按下 w 时,它会将其发送到服务器,服务器可以同时 运行,然后使用该信息来判断玩家应该是什么。

if (rotation < 90f && rotation > 0f)
        {
            moveDirection = new Vector3(0, 0, 0);
            percent = (100 / (90 / rotation)) / 100;
            invertPercent = 1 - percent;

            x = percent * speed;
            z = invertPercent * speed;
            transform.Translate(x * Time.deltaTime, 0, z * Time.deltaTime, Space.World);
            newposition = newposition + new Vector3(x * Time.deltaTime, 0, z * Time.deltaTime);
        }