我正在开发一个基于轮换的多人游戏。所以我有一个名为gameController的脚本,它有全局计时器来改变轮次,还可以选择在当前轮次中哪些球员在进攻,哪些球员在防守。此脚本是附加到带有网络标识的gameObject
的单例脚本(此网络标识没有由服务器标记为控制器的复选框)。我试图在服务器连接时将此游戏对象派生到所有客户端,并且使该游戏对象已存在于场景中(展位情况不起作用)。
嗯,主要的问题是,在gameController脚本中,我在更新函数中有一个检查器,用于检查是否连接了任何新播放器。在连接的情况下,它应该调用一个名为EventOnNewPlayerAddedDelegate
的syncEvent
(我尝试直接调用它,也是使用命令和使用ClientRpc),以让玩家知道他们必须调用名为"OnRegisterPlayer“的函数,这是他们自己的播放器脚本中的一个函数,它调用gameController脚本上的函数,传递播放器对象(我也尝试过通过命令和rpc ),类似于:GameController.instance.RegisterPlayer(this);
所以有谁知道如何触发此SyncEvent
将播放器注册到由服务器控制的非播放器对象?
非常感谢。
我在这里附上一个简短的展台脚本,使其更容易理解:
GameController:
public class GameController : NetworkBehaviour
{
public delegate void OnNewPlayerAddedDelegate();
[SyncEvent]
public event OnNewPlayerAddedDelegate EventOnNewPlayerAddedDelegate;
List<GamePlayerManager> players = new List<GamePlayerManager>();
public static GameController instance { get; private set; }
float timePerTorn = 30f;
bool isCountdown = false;
[System.NonSerialized]
public float countdownTime;
int roundNumber = 0;
int NumberOfPlayers;
int NumberOfPlayersChanged;
void Awake()
{
Debug.Log("Awaking ");
if (instance != null)
{
Debug.Log("Destoring ");
DestroyImmediate(this);
return;
}
instance = this;
}
// Use this for initialization
void Start()
{
if (!isServer)
{
return;
}
players = new List<GamePlayerManager>();
StartCountdown(5f);//20
}
void Update()
{
if (isServer)
{
if (isCountdown)
{
countdownTime -= Time.deltaTime;
if (countdownTime <= 0)
{
AlterGlobalTurns();
}
}
}
NumberOfPlayers = NetworkManager.singleton.numPlayers;
if (NumberOfPlayersChanged != NumberOfPlayers)
{
Debug.Log("num of players changed ---> " + NumberOfPlayers);
NumberOfPlayersChanged = NumberOfPlayers;
EventOnNewPlayerAddedDelegate();
//RpcNewPlayerAdded();
//CmdNewPlayerAdded();
}
}
[ClientRpc]
void RpcNewPlayerAdded()
{
Debug.Log("---------------- RpcNewPlayerAdded ------------");
EventOnNewPlayerAddedDelegate();
}
[Command]
void CmdNewPlayerAdded()
{
Debug.Log("---------------- CmdNewPlayerAdded ------------");
EventOnNewPlayerAddedDelegate();
}
public void RegisterPlayer(GamePlayerManager player)
{
Debug.Log("player ---> " + player.name);
if (players.Contains(player))
{
return;
}
Debug.Log("players ---> " + players);
players.Add(player);
}
}
PlayerScript:
public class GamePlayerManager : NetworkBehaviour
{
[System.NonSerialized]
public bool isPlayingOnTorn = true;
void Awake()
{
GameController.instance.EventOnNewPlayerAddedDelegate += OnRegisterPlayer;
}
private void Start()
{
if (!isLocalPlayer)
{
return;
}
}
public override void OnStartServer()
{
GameObject gc = (GameObject)Instantiate(NetworkManager.singleton.spawnPrefabs[2], transform.position, transform.rotation);
NetworkServer.Spawn(gc);
}
void OnRegisterPlayer(){
if (isLocalPlayer)
{
//GameController.instance.RegisterPlayer(this);
//RpcRegisterPlayer();
CmdRegisterPlayer();
}
}
[Command]
void CmdRegisterPlayer(){
Debug.Log("-------------Command Register player -------------");
GameController.instance.RegisterPlayer(this);
}
[ClientRpc]
void RpcRegisterPlayer()
{
Debug.Log("------------- RPC REgister Player -------------");
GameController.instance.RegisterPlayer(this);
}
}
发布于 2018-11-28 23:06:56
我想我已经看到这里的问题了。
问题是GameController是由OnStartServer()函数中的playerScript(只要播放器也是主机)产生的。所以第一个问题是GameController没有检测到主机播放器,因为它不是新的连接。第二个问题是,当连接第二个客户端时,GameController会检测客户端连接并以比客户端唤醒更快的速度发送事件信号,因此当客户端已经在工作时,信号就会消失。
我解决了删除这个信号的问题,如果GameController存在,直接在playerScript中检查,然后检查播放器是否已经注册。
我现在的问题是,如果有任何方式在播放器(主机)之前实例化和唤醒服务器对象,我理解答案是“不”,因为播放器是主机,它需要运行才能拥有服务器。第二个问题是,是否有任何信号或任何信号来知道连接了一个新的播放器,并等待它被唤醒。
非常感谢。你可以在Unity论坛上检查孔螺纹:https://forum.unity.com/threads/multiplayer-syncevent-problem-with-non-player-objects.589309/
https://stackoverflow.com/questions/53504879
复制相似问题