C# DarkRift 游戏服务端框架教程 04 移动同步

发送我们的位置

在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”。

构建并测试它!现在应该可以移动了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值