发送我们的位置
在Unity项目中创建一个名为 "Player" 的新C#脚本,这将在我们移动时将我们的位置发送到服务器。将以下代码添加到脚本中:
using DarkRift.Client;
using DarkRift.Client.Unity;
public class Player : MonoBehaviour
{
const byte MOVEMENT_TAG = 1;
[SerializeField]
[Tooltip("The distance we can move before we send a position update.")]
float moveDistance = 0.05f;
public UnityClient Client { get; set; }
Vector3 lastPosition;
void Awake()
{
lastPosition = transform.position;
}
void Update()
{
if (Vector3.Distance(lastPosition, transform.position) > moveDistance)
{
/* Send position to server here */
lastPosition = transform.position;
}
}
}
将这段代码添加到您的ControllablePlayer预制件中。在PlayerSpawner中,将while循环中的if语句更改为:
if (id == client.ID)
{
obj = Instantiate(controllablePrefab, position, Quaternion.identity) as GameObject;
Player player = obj.GetComponent<Player>();
player.Client = client;
}
else
{
obj = Instantiate(networkPrefab, position, Quaternion.identity) as GameObject;
}
现在可以尝试填充Player类的代码以发送我们的位置。需要发送的仅是transform.position的x和y分量。如果您卡住了,这是我在距离if语句之后编写的代码:
using (DarkRiftWriter writer = DarkRiftWriter.Create())
{
writer.Write(transform.position.x);
writer.Write(transform.position.y);
using (Message message = Message.Create(Tags.MovePlayerTag, writer))
Client.SendMessage(message, SendMode.Unreliable);
}
请不要忘记将标签添加到Tags文件中:
public static readonly ushort MovePlayerTag = 1;
这些内容都应该非常熟悉,我们创建一个写入器并打包要发送的数据,将其放入带有运动标记的消息中,然后不可靠地发送(如果服务器没有收到位置,那也不是世界末日,因为我们很快就会再次发送)。
更新服务器上的位置信息
在我们的服务器插件中,我们需要跟踪每个玩家的位置变化,以便新连接的玩家始终获取最新的位置,并将位置更新消息发送给所有其他玩家。
在ClientConnected方法中,我们可以添加以下代码行来开始跟踪玩家位置变化并将位置更新消息发送给所有其他玩家:
e.Client.MessageReceived += MovementMessageReceived;
在上述问题中,我们需要将movement 标签常量添加到标签文件中,并告诉客户端对象在接收到消息时调用我们的处理程序进行处理。现在让我们添加处理程序:
void MovementMessageReceived(object sender, MessageReceivedEventArgs e)
{
using (Message message = e.GetMessage() as Message)
{
if (message.Tag == Tags.MovePlayerTag)
{
using (DarkRiftReader reader = message.GetReader())
{
float newX = reader.ReadSingle();
float newY = reader.ReadSingle();
Player player = players[e.Client];
player.X = newX;
player.Y = newY;
using (DarkRiftWriter writer = DarkRiftWriter.Create())
{
writer.Write(player.ID);
writer.Write(player.X);
writer.Write(player.Y);
message.Serialize(writer);
}
foreach (IClient c in ClientManager.GetAllClients().Where(x => x != e.Client))
c.SendMessage(message, e.SendMode);
}
}
}
}
以下代码的前几行应该是很熟悉的。在此,编写者只是更新消息内容,以便包括玩家ID(当我们在客户端接收时需要知道是谁发送的)和半径(稍后会用到)。最后,我们将消息发送给除发送者外的所有人,以便它们都更新其位置。很简单!
更新客户端位置
为了处理游戏中的移动,我们将使用单个管理器来移动所有客户端。在您的Unity项目中创建一个名为NetworkPlayerManager的新C#脚本,并添加以下内容:
using DarkRift.Client;
using DarkRift.Client.Unity;
public class NetworkPlayerManager : MonoBehaviour
{
[SerializeField]
[Tooltip("The DarkRift client to communicate on.")]
UnityClient client;
Dictionary<ushort, AgarObject> networkPlayers = new Dictionary<ushort, AgarObject>();
public void Add(ushort id, AgarObject player)
{
networkPlayers.Add(id, player);
}
}
将上述脚本添加到我们的Network对象中,并分配客户端字段。在PlayerSpawner中添加以下字段,并在inspector中进行分配:
[SerializeField]
[Tooltip("The network player manager.")]
NetworkPlayerManager networkPlayerManager;
最后,在SpawnPlayer方法的while循环末尾添加以下代码行
networkPlayerManager.Add(id, agarObj);
尝试编写接收移动消息的逻辑,不要忘记可以参考PlayerSpawner中的接收代码和我们编写的插件代码。这是我的实现:
public void Awake()
{
client.MessageReceived += MessageReceived;
}
void MessageReceived(object sender, MessageReceivedEventArgs e)
{
using (Message message = e.GetMessage() as Message)
{
if (message.Tag == Tags.MovePlayerTag)
{
using (DarkRiftReader reader = message.GetReader())
{
ushort id = reader.ReadUInt16();
Vector3 newPosition = new Vector3(reader.ReadSingle(), reader.ReadSingle(), 0);
if (networkPlayers.ContainsKey(id))
networkPlayers[id].SetMovePosition(newPosition);
}
}
}
}
进入“Edit ”->“ Project Settings”->“Player ”并勾选“Run in Background”。
构建并测试它!现在应该可以移动了!