复习上一章物体运动
玩家按下W键向前移动,此时
Update()
中调用Move()
函数,更新PlayerController
类中的velocity、xRot、yRot
值,而PlayerController
类中的FixedUpdate()
函数会均匀调用,实现玩家移动。
PlayerInput模块:Update()中获取x,y得到速度velocity,调用controler.Move()更新PlayerController模块中的速度velocity
PlayerController模块:FixUpdate()均匀检测(0.02s)速度velocity是否为0,如果不为0,更改位置坐标,使角色移动
控制鼠标运动同理
实现联机的两种方式
Server判断:Client处理用户输入,将用户输入信息传给Server,Server控制角色移动,将结果返回给所有Client【延迟大;不易作弊】
Client模式:Client处理用户用户输入以及角色移动,然后将结果发给Server,Server仅同步结果给其他Client【延迟小;易作弊】
击中与未击中判定:采取攻击者视角。在射击者看来,是否击中目标自己很明确,因为准星是否瞄准到对方身上自己能看到,而从被攻击者的视角来看,被攻击者并不知道自己是否被瞄准且击中。
联机实现
安装网络包
com.unity.netcode.gameobjects(需要更新到Unity 2021.3及以后版本才能看到)
- 工具栏:Windows->Package Manager
- 左上角改为: Unity Registry,找到对应的包,右下角install(已经安装则显示Remove)
配置网络组件
创建空
Object
,命名为NetworkManager
管理所有需要联机同步的物体,添加组件NetwortkManager
,NetworkManager
会有两个警告:安装包 Multiplaers Tools(按照上文方法);选择NetworkTrnasform
后即可消除。添加需要同步的物体 Player
设置需要同步的信息,Player自身
玩家的部分信息是不需要同步的,比如Scale等,因为Scale是不变的。
开局创建角色与UI
创建角色:在NetWorkManager
中设置 Player Prefab。
创建开局相机:【否则开局黑屏】,全局创建并调整即可,命名为SceneCamera。
UI创建:
创建 Canvas 命名为 MenuUI【如果提示import包则import即可】
添加 Button组件
添加事件逻辑:在
NetworkManager
中添加脚本NetWorkManagerUI
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
using UnityEngine.UI;
public class NetworkManagerUI : MonoBehaviour
{
[SerializeField]
private Button hostButton;
[SerializeField]
private Button serverButton;
[SerializeField]
private Button clientButton;
void Start()
{
hostButton.onClick.AddListener(() =>
{
NetworkManager.Singleton.StartHost();
});
serverButton.onClick.AddListener(() =>
{
NetworkManager.Singleton.StartServer();
});
clientButton.onClick.AddListener(() =>
{
NetworkManager.Singleton.StartClient();
});
}
}
禁用非本地玩家的组件
此时直接运行 host和client,会发现两个角色会同时移动,并且unity中显示有多个Audio被使用的警告。
原因是在一个Player中,没有禁用其他Player的输入控制和Camera;并且开始菜单的Camera和本地Player的Cameara也会有冲突。
在Player中添加一段脚本PlayerSetup解决此问题。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
public class PlayerSetup : NetworkBehaviour
{
[SerializeField]
private Behaviour[] componentsToDisable;
private Camera sceneCamera;
void Start()
{
if (!IsLocalPlayer)
{
for (int i = 0; i < componentsToDisable.Length; i++)
{
componentsToDisable[i].enabled = false;
}
}
else
{
sceneCamera = Camera.main;
if (sceneCamera != null)
{
sceneCamera.gameObject.SetActive(false);
}
}
}
private void OnDisable()
{
if (sceneCamera != null)
{
sceneCamera.gameObject.SetActive(true);
}
}
}
SceneCamera无法拖动赋值,因为Player不在场景里,要设置为MainCemera来获取
控制不同玩家移动
此时,不会同时控制多个Player 但是,打开两个窗口时,只能控制其中一个。
原因是Unity默认不信任客户端,没有授权,需要自己写一段脚本打开授权
创建脚本 ClientNetworkTransform
using Unity.Netcode.Components;
using UnityEngine;
namespace Unity.Multiplayer.Samples.Utilities.ClientAuthority
{
[DisallowMultipleComponent]
public class ClientNetworkTransform : NetworkTransform
{
protected override bool OnIsServerAuthoritative()
{
return false;
}
}
}
代码含义:重载NetWorkTransform
中的授权函数
所以,要将用到NetWorkTransform
的地方改为ClientNetWorkTransform
评论区