如何通过统一运动在 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);
}
问题:我如何在 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);
}