NetworkBehaviour
NetworkBehaviours
是使用NetworkIdentity
组件处理对象的特殊脚本。这些脚本能够执行HLAPI功能,例如命令,ClientRPC
,SyncEvents
和SyncVars
。
使用Unity网络系统的服务器授权系统时,使用NetworkServer.Spawn()
必须由服务器“生成”具有NetworkIdentities
的网络对象。这会导致它们被分配一个NetworkInstanceId
并在连接到服务器的客户端上创建。
属性
属性 | 功能 |
---|---|
isLocalPlayer | 如果此对象是本地客户端的玩家对象,则为true。 |
isServer | 如果此对象正在服务器上运行并且已生成,则为true。 |
isClient | 如果此对象在客户端上运行,则为true。 |
hasAuthority | 如果此对象是对象的授权版本,则为true。所以无论是在服务器上,还是在使用localPlayerAuthority的客户端上。 |
assetid | 这是对象NetworkIdentity的assetId。 |
NETID | 这是对象NetworkIdentity的netId。 |
playerControllerId | 这是对象的NetworkIdentity的playerControllerId。 |
connectionToServer | 要用于发送到服务器的NetworkConnection对象。 |
connectionToClient | 使用NetworkConnection对象发送给客户端。 |
NetworkBehaviours具有以下所述的功能。
• 同步变量
• 网络回调
• 服务器和客户端功能
• 发送命令
• 客户端RPC调用
• 网络事件
同步变量
NetworkBehaviours
的成员变量可以从服务器同步到客户端。由于服务器在该系统中是权威的,所以同步仅在服务器到客户端方向上进行。客户做事的请求由命令处理,而不是由客户端同步的变量处理。
所述SyncVar
属性用于标记成员变量为被同步。SyncVars
可以是任何基本类型,而不是类,列表或其他集合。
public class SpaceShip : NetworkBehaviour
{
[SyncVar]
public int health;
[SyncVar]
public string playerName;
}
当服务器上的SyncVar
值发生变化时,它将被发送到游戏中所有准备好的客户端。生成对象时,它们将在客户端上创建,并使用来自服务器的所有SyncVars
的最新状态。
网络回调
在NetworkBehaviour
脚本上为各种网络事件调用回调函数。这些是基类中的虚函数,因此可以在使用代码时重写它们:
public class SpaceShip : NetworkBehaviour
{
public override void OnStartServer()
{
// disable client stuff
}
public override void OnStartClient()
{
// register client events, enable effects
}
}
OnStartServer
函数在服务器上产生对象时启动,或者在场景中的对象启动服务器时调用。OnStartClient
函数在客户端生成对象时,或客户端连接到服务器以获取场景中的对象时调用。这些功能对于执行特定于客户端或服务器的事情非常有用,例如抑制对服务器的影响或设置客户端事件。
请注意,当使用本地客户端时,这两个函数将在同一对象上调用。
其他回调包括:
• OnSerialize - 调用收集状态以从服务器发送到客户端
• OnDeSerialize - 调用将状态应用于客户端上的对象
• OnNetworkDestroy - 当服务器告诉要销毁的对象时调用客户端
• OnStartLocalPlayer - 在客户端为本地客户端的玩家对象调用(仅)
• OnRebuildObservers - 当一个对象的一组观察者被重建时在服务器上调用
• OnSetLocalVisibility - 当本地客户端的对象可见性发生更改时调用主机
• OnCheckObserver - 在服务器上调用以检查新客户端的可见性状态
服务器和客户端功能
NetworkBehaviours
中的成员函数可以使用自定义属性进行标记,以将它们指定为仅服务器或仅客户端函数。例如:
using UnityEngine;
using UnityEngine.Networking;
public class SimpleSpaceShip : NetworkBehaviour
{
int health;
[Server]
public void TakeDamage( int amount)
{
// will only work on server
health -= amount;
}
[Client]
void ShowExplosion()
{
// will only run on client
}
[ClientCallback]
void Update()
{
// engine invoked callback - will only run on client
}
}
如果在客户机或服务器未处于活动状态时调用这些属性,则该函数会立即返回。它们不会生成编译时错误,但如果在错误的作用域中调用,它们将发出警告日志消息。属性ServerCallback
和ClientCallback
可以用于用户代码不控制调用的引擎回调函数。这些属性不会导致生成警告。
发送命令
命令是客户请求在服务器上执行某些操作的方式。由于HLAPI是一个服务器授权系统,客户端只能通过命令做事情。命令在与发送命令的客户端相对应的服务器上的玩家对象上运行。此路由自动发生,因此客户端不可能为其他玩家发送命令。
命令必须以前缀“Cmd”开头,并在其上具有[Command]
自定义属性,如下所示:
using UnityEngine;
using UnityEngine.Networking;
public class SpaceShip : NetworkBehaviour
{
bool alive;
float thrusting; // 推进力
int spin;
[Command]
public void CmdThrust(float thrusting, int spin)
{
if (!alive)
{
this.thrusting = 0;
this.spin = 0;
return;
}
this.thrusting = thrusting;
this.spin = spin;
}
[ClientCallback]
void Update()
{
int spin = 0;
if (Input.GetKey(KeyCode.LeftArrow))
{
spin += 1;
}
if (Input.GetKey(KeyCode.RightArrow))
{
spin -= 1;
}
// this will be called on the server
CmdThrust(Input.GetAxis("Vertical"), spin);
}
}
通过在客户端上正常调用函数来调用命令。但不是在客户端上运行的命令功能,而是在服务器上该客户端的玩家对象上调用它。所以,命令是类型安全的,具有内置的安全性和路由到玩家,并且使用高效的序列化机制来使参数快速调用。
客户端RPC调用
客户端RPC调用是服务器对象在客户端对象上发生事件的一种方式。这与命令如何发送消息的方向相反,但概念是相同的。然而,客户端RPC调用不仅可以在玩家对象上调用,还可以在任何NetworkIdentity
对象上调用。它们必须以前缀“Rpc”开头并具有[ClientRPC]
自定义属性,如下所示:
using UnityEngine;
using UnityEngine.Networking;
public class SpaceShipRpc : NetworkBehaviour
{
[ClientRpc]
public void RpcDoOnClient(int foo)
{
Debug.Log("OnClient " + foo);
}
[ServerCallback]
void Update()
{
int value = UnityEngine.Random.Range(0,100);
if (value < 10)
{
// this will be invoked on all clients
RpcDoOnClient(value);
}
}
}
网络事件
联网事件与客户端RPC调用相似,但不是仅调用客户端对象上的函数,而是触发客户端对象上的事件。然后调用为该事件注册的其他脚本 - 使用来自服务器的参数,以便在客户端上实现联网的脚本间交互。事件必须以前缀“Event”开始,并具有SyncEvent
自定义属性。
事件可以用来构建强大的网络游戏系统,可以通过其他脚本进行扩展。此示例显示了客户端上的效果脚本如何响应由服务器上的战斗脚本生成的事件。
using UnityEngine;
using UnityEngine.Networking;
// Server script
public class MyCombat : NetworkBehaviour
{
public delegate void TakeDamageDelegate(int amount);
public delegate void DieDelegate();
public delegate void RespawnDelegate();
float deathTimer;
bool alive;
int health;
[SyncEvent(channel=1)]
public event TakeDamageDelegate EventTakeDamage;
[SyncEvent]
public event DieDelegate EventDie;
[SyncEvent]
public event RespawnDelegate EventRespawn;
[Server]
void EventTakeDamage(int amount)
{
if (!alive)
return;
if (health > amount) {
health -= amount;
}
else
{
health = 0;
alive = false;
// send die event to all clients
EventDie();
deathTimer = Time.time + 5.0f;
}
}
[ServerCallback]
void Update()
{
if (!alive)
{
if (Time.time > deathTimer)
{
Respawn();
}
return;
}
}
[Server]
void Respawn()
{
alive = true;
// send respawn event to all clients
EventRespawn();
}
}
提示
• 这是一个提供Commands和ClientRpc调用的基类。
🔚