我目前正在开发一款游戏,遇到以下情况:
我有一个 Player 预制游戏对象,上面附加了一个脚本(见下文)。我已经设置了网络管理器,并在“服务”下设置了一个帐户,以便能够使用多人游戏方面。
我已设置好基础,以便玩家生成和多人游戏正常运行。玩家能够移动,我在每个构建 session 中看到其他玩家的移动。
我有一段代码,当玩家“行走”时(如果按下 A、W、S 或 D 键,我调用“CmdWalk()”。
基本上 CmdWalk() 可以改变我的玩家的腿部旋转,使其看起来像是在行走。 (我不喜欢动画,所以这是我唯一知道的方法)。
问题是只有本地玩家能够看到他们的玩家“走路”,其他在线玩家看不到移动。 我不确定我做错了什么,有人可以帮忙吗。
下面是我为播放器准备的完整脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class PlayerController : NetworkBehaviour
{
public float speedH = 2.0f;
private float yaw = 0.0f;
public float WalkingTime; //timer for walking animation
public GameObject PlayerLeftLeg;
public GameObject PlayerRightLeg;
private float PlayerStatMenuTimer;
public GameObject PlayerStatsMenu;
// Update is called once per frame
void Update ()
{
if (!isLocalPlayer)
{
return;
}
//keep track of time for player stat menu
//if not here than menua will show and hide like a thousand times when pressed once due to update reading code per frame
PlayerStatMenuTimer = PlayerStatMenuTimer + 1 * Time.deltaTime;
//moving player left right forward backward
var x = Input.GetAxis ("Horizontal") * Time.deltaTime * 50.0f;
var z = Input.GetAxis ("Vertical") * Time.deltaTime * 50.0f;
transform.Translate (x, 0, z);
//rotating player or "Looking"
yaw += speedH * Input.GetAxis ("Mouse X");
transform.eulerAngles = new Vector3 (0.0f, yaw, 0.0f);
//if player is using WASD to move then do leg moving animation
//if not moving then set legs to be still and reset in standing position
//FYI: "transform.TransformVector(1,0,0)" was used instead of "Vector3.forward" was because
// vector3.forward is local space, so when i rotate player the sense of "forward" also changes, thus i needed
// a code that uses the world space, thus i used "transform.TransformVector(1,0,0)"
if (Input.GetKey (KeyCode.W) || Input.GetKey (KeyCode.S) || Input.GetKey (KeyCode.A) || Input.GetKey (KeyCode.D))
{
CmdWalk ();
}
else
{
//if player not walking then reset
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis (0, Vector3.forward);
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis (0, Vector3.forward);
WalkingTime = 0;
}
//get hidden mouse pointer back and unlock
if (Input.GetKey (KeyCode.Escape))
{
Cursor.lockState = CursorLockMode.None;
}
//opens and closes stat menu
if (Input.GetKey (KeyCode.Return) && (PlayerStatMenuTimer >= 1) && (PlayerStatsMenu.activeSelf == false))
{
Cursor.lockState = CursorLockMode.None;
PlayerStatsMenu.SetActive (true);
PlayerStatMenuTimer = 0;
//call the script "GetplayerStats" and call function "retrieceplayerstats"
var GetStats = GetComponent<GetPlayerStats> ();
GetStats.RetrievePlayerStats ();
}
else if (Input.GetKey (KeyCode.Return) && PlayerStatMenuTimer >= 1 && PlayerStatsMenu == true)
{
Cursor.lockState = CursorLockMode.Locked;
PlayerStatsMenu.SetActive (false);
PlayerStatMenuTimer = 0;
}
}
private void Awake ()
{
//this code locks mouse onto center of window
//Screen.lockCursor = true;
Cursor.lockState = CursorLockMode.Locked;
}
[Command]
void CmdWalk ()
{
//timer
WalkingTime += Time.deltaTime;
//right leg stepping forward
if (WalkingTime > 0 && WalkingTime < .4)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis (PlayerRightLeg.transform.rotation.x - (60 * WalkingTime), transform.TransformVector (1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis (PlayerLeftLeg.transform.rotation.x + (60 * WalkingTime), transform.TransformVector (1, 0, 0));
}
//left leg stepping forward
if (WalkingTime >.4 && WalkingTime < 1.2)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis (PlayerRightLeg.transform.rotation.x + (60 * (WalkingTime - .8f)), transform.TransformVector (1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis (PlayerLeftLeg.transform.rotation.x - (60 * (WalkingTime - .8f)), transform.TransformVector (1, 0, 0));
}
//right leg stepping forward
if (WalkingTime > 1.2 && WalkingTime < 1.59)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis (PlayerRightLeg.transform.rotation.x - (60 * (WalkingTime - 1.6f)), transform.TransformVector (1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis (PlayerLeftLeg.transform.rotation.x + (60 * (WalkingTime - 1.6f)), transform.TransformVector (1, 0, 0));
}
//resetting
if (WalkingTime > 1.6)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis (0, Vector3.forward);
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis (0, Vector3.forward);
WalkingTime = 0;
}
}
}
抱歉,代码量很大,但唯一需要查看的部分是键“A”、“W”、“S”、“D”和“Void CmdWalk()”的“IF 语句”
谢谢。
最佳答案
让我感到惊讶的是 local Player
看到了移动。我会说只有 Host/Server Player
可以看到它,因为
[Command]
void CmdWalk()
{
//timer
WalkingTime += Time.deltaTime;
//right leg stepping forward
if (WalkingTime > 0 && WalkingTime < .4)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x - (60 * WalkingTime), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x + (60 * WalkingTime), transform.TransformVector(1, 0, 0));
}
//left leg stepping forward
if (WalkingTime > .4 && WalkingTime < 1.2)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x + (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x - (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0));
}
//right leg stepping forward
if (WalkingTime > 1.2 && WalkingTime < 1.59)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x - (60 * (WalkingTime - 1.6f)), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x + (60 * (WalkingTime - 1.6f)), transform.TransformVector(1, 0, 0));
}
//resetting
if (WalkingTime > 1.6)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
WalkingTime = 0;
}
}
仅在服务器上执行。所以实际上,Host 也应该可以看到其他 Client 的移动。
然而,要将调用传回给所有 客户端,您应该添加一个ClientRpc
[Command]
void CmdWalk()
{
RpcWalk();
}
[ClientRpc]
void RpcWalk()
{
//timer
WalkingTime += Time.deltaTime;
// also it is slightly more efficient to use if-else
// to avoid unneccesary checks since
// only one of those conditions can be true at a time
//right leg stepping forward
if (WalkingTime > 0 && WalkingTime < .4)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x - (60 * WalkingTime), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x + (60 * WalkingTime), transform.TransformVector(1, 0, 0));
}
//left leg stepping forward
else if (WalkingTime > .4 && WalkingTime < 1.2)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x + (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x - (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0));
}
//right leg stepping forward
else if (WalkingTime > 1.2 && WalkingTime < 1.59)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x - (60 * (WalkingTime - 1.6f)), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x + (60 * (WalkingTime - 1.6f)), transform.TransformVector(1, 0, 0));
}
//resetting
else if (WalkingTime > 1.6)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
WalkingTime = 0;
}
}
更新
这种方法的一般问题仍然是网络延迟。用户(如果不是主机)将不会看到他自己的移动结果,直到调用被发送到服务器然后返回到他自己。所以我会另外在本地播放器上进行移动并为他跳过 Rpc 调用:
void Walk()
{
//timer
WalkingTime += Time.deltaTime;
//right leg stepping forward
if (WalkingTime > 0 && WalkingTime < .4)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x - (60 * WalkingTime), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x + (60 * WalkingTime), transform.TransformVector(1, 0, 0));
}
//left leg stepping forward
else if (WalkingTime > .4 && WalkingTime < 1.2)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x + (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x - (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0));
}
//right leg stepping forward
else if (WalkingTime > 1.2 && WalkingTime < 1.59)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x - (60 * (WalkingTime - 1.6f)), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x + (60 * (WalkingTime - 1.6f)), transform.TransformVector(1, 0, 0));
}
//resetting
else if (WalkingTime > 1.6)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
WalkingTime = 0;
}
if(!isLocalPlayer) return;
// if executed by the local Player invoke the call on the server
CmdWalk(gameObject);
}
// passing the GameObject reference over network works
// since the player GameObject has a unique identity on all instances
// namely the NetworkIdentity
[Command]
void CmdWalk(GameObject caller)
{
Walk();
RpcWalk(caller);
}
[ClientRpc]
void RpcWalk(GameObject caller)
{
// skip if server since already done it in CmdWalk
if(isServer) return;
// skip if this is caller since already done locally
if(caller == gameObject) return;
Walk();
}
并在更新
中使用
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D))
{
Walk();
}
代替
关于c# - Unity Moving Player Leg 多人游戏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53784897/