【发布时间】:2022-06-17 19:54:44
【问题描述】:
我是 Unity 的新手,我已经开始学习如何使用 Fishnet 网络。我创建了一个基本的玩家移动脚本,它可以比网络转换更快地同步玩家位置。但是我遇到了一个奇怪的问题,我不知道如何解决。
在我的场景中,我有一个网络管理器,它在连接后会生成我的播放器预制件——一个带有播放器脚本和网络对象的简单精灵。我没有添加网络转换,因为我将手动同步每个玩家的位置以减少客户端之间的延迟。这是播放器脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FishNet.Object;
public class Player : NetworkBehaviour
{
private void Update()
{
if (IsOwner) //only the client that owns this object will run this code
{
//get input, send it to server
float horizontalInput = Input.GetAxisRaw("Horizontal");
float verticalInput = Input.GetAxisRaw("Vertical");
RpcMoveCharacter(horizontalInput, verticalInput);
}
//since this is an observers rpc, only the server will call it
RpcSendCharacterPosition(transform.position.x, transform.position.y);
}
[ServerRpc]
public void RpcMoveCharacter(float x, float y)
{
//change the position of the server's instance of the player
transform.Translate(x * 10f * Time.deltaTime * Vector3.right);
transform.Translate(y * 10f * Time.deltaTime * Vector3.up);
}
[ObserversRpc]
public void RpcSendCharacterPosition(float x, float y)
{
if (IsClientOnly)
{
//ensure clients' instance of the player match the server's' position
transform.position = new Vector2(x, y);
}
}
}
脚本运行良好...除了一个问题:两个玩家的玩家移动速度不一致。只有当我构建并运行我的游戏,然后连接两个版本的游戏时才会出现这些问题。
当任一玩家是主机(服务器 + 客户端)时,他们的玩家对象在两个屏幕上均以中等速度移动。这是预期的速度。
当从我的统一编辑器窗口运行的游戏版本只是一个客户端时,玩家在两个屏幕上的移动速度都很快——比预期快很多倍。
当我使用“构建并运行”创建的游戏版本只是一个客户端时,玩家在两个屏幕上的移动速度都很慢——比预期慢很多倍。
我已经测试了我能想到的一切。我做的一项测试是防止网络管理器生成播放器预制件,提前将播放器对象放置在场景中,然后进行转换:
private void Update()
{
if (IsOwner)
{
float horizontalInput = Input.GetAxisRaw("Horizontal");
float verticalInput = Input.GetAxisRaw("Vertical");
RpcMoveCharacter(horizontalInput, verticalInput);
}
RpcSendCharacterPosition(transform.position.x, transform.position.y);
}
[ServerRpc]
到这里:
private void Update()
{
//now anyone can control the player object
float horizontalInput = Input.GetAxisRaw("Horizontal");
float verticalInput = Input.GetAxisRaw("Vertical");
RpcMoveCharacter(horizontalInput, verticalInput);
RpcSendCharacterPosition(transform.position.x, transform.position.y);
}
//same effect as note above
[ServerRpc (RequireOwnership = false)]
为了查看是否存在有关玩家生成功能的问题。我的更改效果为零——根本没有任何改变。 如果我的 editor 是一个客户端,它仍然移动播放器太快,如果我的 build 是一个客户端,它仍然移动播放器太慢。强>
我尝试的另一件事是制作一个全新的项目,以防我在上一个项目中奇怪地切换了设置或其他东西。一旦我创建了一个新项目,我所做的就是导入鱼网,将鱼网的默认 NetworkManager 对象添加到我的场景中,创建一个名为 player 的简单预制件,将一个网络对象和原始播放器脚本添加到播放器预制件中,将网络管理器设置为生成播放器预制件,然后再试一次。不走运——一切都完全一样。
有什么想法吗?我被困在这里——我不知道还能尝试什么,因为代码/场景中的一切似乎都运行良好。我无法弄清楚为什么我的构建会与我的编辑器的播放模式表现不同,无论哪个是服务器(或主机),哪个只是客户端。
谢谢!
【问题讨论】:
-
一般注意你总结了垂直和水平移动 -> 移动对角线时你会移动得更快(使用
Vector3.ClampMaginutde来避免这种情况) -
一般来说,调用网络方法每一帧都不是一个好主意,你不能保证它们以相同的时间间隔到达服务器,因为所有设备都有不同的每秒帧数 => 所以
Time.deltaTime在服务器端将无效,因为一个玩家可能仍然比另一个更频繁地调用它。您应该以特定的时间间隔调用它,并确保服务器正确补偿这个固定的时间间隔(例如,存储每个玩家最后收到的时间戳并乘以差异)或在客户端计算它并发送最终动作 -
我很想在客户端计算它并发送最终动作,但我不知道该怎么做。我已经尝试过 transform.Translate 和 transform.position 无济于事 - 我该怎么做?我应该使用水平输入和垂直输入变量来确定 x 和 y 变量(然后我可以将它们传递给服务器)吗?我怎么做?以及如何在不使用更新每帧发送 rpc 的情况下发送最终动作?我找不到这方面的任何指南(除了一些使用过时的网络系统的十年前的论坛帖子)
-
var movement = transform.rotation * Vector2.ClampMagnitude(new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")), 1f) * 10f * speed * Time.deltaTime;这是您在客户端执行的操作,然后您在transform.position += movement;中使用此操作,或者计算每个客户端的位置,然后只同步最终位置(这就是我更喜欢的) -
知道了!这与我尝试做的非常相似,我只是缺少一些基本的东西,谢谢!不过,再一次,在不使用更新方法的情况下同步最终位置的最佳方法是什么? (据我所知,SyncVars 只与服务器>客户端通信,除非我遗漏了什么。这意味着我需要一个 rpc,如果我要使用 ServerRpc,如果不在更新函数中,我应该在哪里调用它?太棒了!
标签: c# unity3d network-programming