问题描述
我目前正在开发游戏,并且遇到以下情况:
I am currently working on a game and I have the following situation:
我有一个Player预制游戏对象,并附有脚本(请参见下文).我已经设置了网络管理器,并且已经在服务"下设置了一个帐户,以便能够使用多人游戏方面.
I have a Player prefab gameobject with a script attached to it (see below). I have set up Network Manager and I have set up an account under "Services" to be able to use the multiplayer aspect.
我已经进行了基本设置,以便播放器可以生成并可以进行多人游戏.玩家可以移动,每次构建会话时我都能看到其他玩家的移动.
I have the basics set up so that the player does spawn and multiplayer does work. The player is able to move and I see the movement on the other players on each build session.
我有一段代码,当播放器行走"时(如果按了A,W,S或D键,则称为"CmdWalk()".)
I have a chunk of code that when the player is "walking" (if either keys A, W, S, or D is pressed, I call "CmdWalk()".
基本上,CmdWalk()使它改变了播放器的腿部旋转,使它看起来好像在走路. (我不喜欢动画,所以这是我唯一的方法.)
Basically CmdWalk() makes it so that it changes my player's legs rotation so that it makes it seem like it is walking. (I am not into animation so this is the only way I know).
问题在于,只有本地玩家才能看到他们的玩家行走",而其他在线玩家则看不到移动. 我不确定自己做错了什么,请有人帮忙.
The issue is that only the local player is able to see their player "walk", the other players online does not see the movement. I am not sure what I have done wrong, can someone please help.
以下是我为播放器准备的整个脚本:
Below is the entire script I have for the player:
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语句"
Sorry for the amount of code but the only parts that needs to be looked at is the "IF statement" for keys "A" "W" "S" "D" and the "Void CmdWalk()"
谢谢.
推荐答案
local Player
看到了动静,这让我感到惊讶.我只能说Host / Server Player
可以看到它,因为
It surprises me that the local Player
is seeing the movement. I'ld say only the Host / Server Player
can see it since
[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;
}
}
仅在服务器上执行.因此,实际上,主持人也应该已经可以看到其他客户端的动向.
is only executed on the server. So actually it should also be possible already for the Host to see also the movements of other Clients.
无论如何将呼叫转接回所有客户,您都应该添加ClientRpc
However to pass the call back to all clients you should rather add a 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调用:
The problem in general with this approach is still the network lag. The user (if not the Host) won't see the result of his own movements until the call was sent to the server and than back to himself. So I would additionally do the movement already on the local player and skip for him the Rpc call:
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();
}
并在Update
中使用
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D))
{
Walk();
}
代替
这篇关于Unity Moving Player腿多人游戏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!