Unity와 함께 3D 모바일 게임을 개발 중이며 멀티 플레이어 부분을 작성해야하는 시점에 왔습니다. node.js/socket.io와의 모든 중매 등을 썼지 만 게임 내에서 문제가 발생했습니다. 문제는; 사용자가 이동할 때마다, 그는 자신의 위치를 다른 사용자에게 전송합니다. 그러나 서버가 매우 강력하다면 (CPU 4GHz, 램 16GB), 사용자는 싱글 플레이 (AI 동작)를하는 것처럼 움직이지 않습니다. 그들은 몇 프레임 미끄러 져 보였으므로 그것이 예상대로 부드럽지 않게 움직입니다. FPS 차이와 같은 원인이 될 수있는 것에 대한 아이디어가 있습니다. 사용자 중 한 명이 다른 FPS 차이의 다른 것보다 느리게 방출 할 수 있기 때문에. 모든 아이디어 어떻게이 문제를 없앨 수 있습니까?3D 멀티 플레이어 게임의 FPS 차이점
0
A
답변
1
정확하게 클라이언트/서버간에 데이터를 전송하는 방법에 따라 약간 다릅니다.
(당신은 유니티의 네트워킹이 아닌 프레임 워크를 사용하여 여기에 가정합니다)
transform.position = X.Yf;
으로 수신기 클라이언트에서 새로운 위치를 설정하지 오히려 때문에 일부 보간을해야 결코
지연/이미 알아 차린 시간 요소.
transform.position = Vector3.Lerp(actualPosition, receivedPosition, Time.deltaTime * interpolationRate);
저는 Unity가 NetworkTransform을 좋아하지 않았습니다. 원활하게 작동하지 못했기 때문입니다. 그래서 나는 동기화를위한 내 자신의 문장을 썼다. (많은 인터넷 검색을하는 오프쇼어)
여기서는 위치에 대해서만 예제를 제공 할 것이다. 당신은 그것을 스스로 조정할 수 있고 회전 부분을 쓸 수 있어야합니다. 그것은 완벽하지 않을 수도 있지만 그것은 그것을 사용하는 방법입니다 (지금까지 꽤 만족).
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class CustomNetworkTransform : NetworkBehaviour
{
/* If we are not the localPlayer we will save here
* the last received Position to which we are actually moving.
* (see below in the transmition part) */
private Vector3 _lastReceivedPosition = Vector3.zero;
/*#############################################*/
/* THE RECEIVING PART */
/* The interpolation rate. You have to tweak this maybe
* but 15 seemed a good value so far */
private float _interpolationRate = 15.0f;
private void Update()
{
/* I used hasAuthority here instead of isLocalPlayer
* so it works with a Host-Clients
* setup as well as with a Client-Server-Clients one.
*/
if (hasAuthority) return;
ReceiveData();
}
private void ReceiveData()
{
InterpolatePosition(_lastReceivedPosition, Time.deltaTime * _interpolationRate);
}
private void InterpolatePosition(Vector3 receivedPosition, float factor)
{
transform.position = Vector3.Lerp(transform.position, receivedPosition, factor);
}
/* That's already all for the receiving Part. Maybe that already
* Fits your need. Down here I anyway add the way how I transmit stuff. Maybe it helps you to understand better the way Networking works in Unity.
*/
/*#############################################*/
/* THE TRANSMITION PART */
/* To save a bit of Bandwidth we use this as a treshold
* If you whish you can set this also to 0 */
[Tooltip("The Accuracy of synchronized Positions")]
[SerializeField]
private float _positionAccuracy = 0.05f;
/* Make a forced Transmition every x seconds
* also if nothing was changed */
[SerializeField]
private float _forcedSyncTimeout = 2.0f;
/* Counter for the forced transmition
* I set it to 0 at the beginning to have an instant
* sync when connecting. */
private float _timeout = 0;
/* Wel'll compare the actual position to this one and only
* sync, if the distance is bigger than the _positionAccuracy */
private Vector3 _lastTransmittedPosition = Vector3.zero;
private void FixedUpdate()
{
/* again here I use hasAuthority instead of
* isLocalPlayer so it works in both connection designs */
if (!hasAuthority) return;
TransmitChangedData();
_timeout-= Time.deltaTime;
if (_timeout > 0) return;
TransmitData();
_timeout = _forcedSyncTimeout;
}
/* This is the forced transmition
* which doesn't check for changes */
private void TransmitData()
{
TransmitPositionToServer(transform.position)
}
/* This is the normal transmition which checks
* if changes are big enough before transmitting */
private void TransmitChangedData()
{
if(Vector3.Distance(transform.position, _lastTransmittedPosition) > _positionAccuracy)
{
TransmitPositionToServer(transform.position);
_lastTransmittedPosition = transform.position;
}
}
/* NOTE: for the transmition I don't use SyncVar
* but rather a 3-Step Syncronization:
*
* 1. Client transmits data to Server
* 2. Server transmits data to all Clients
* 3. All other Clients receive and interpolate the position
*
* I felt more comfortable doing this to have
* more freedom and better debug options.
*
* This will also do all the interpolations on the server as well
* so it can be used e.g. to observe. */
//STEP 1.
/*
* Only performed on clients
*/
[Client]
private void TransmitPositionToServer(Vector3 value)
{
CmdPushPositionToServer(value);
}
//STEP 2.
/*
* Invoced from the client but only performed on the server
*/
[Command]
private void CmdPushPositionToServer(Vector3 value)
{
_lastReceivedPosition = value;
RpcProvidePositionToClients(value);
}
//STEP 3.
/*
* Invoced from the server but only performed on all the client
*/
[ClientRpc]
private void RpcProvidePositionToClients(Vector3 value)
{
/* This value is also set on the originally sending client
* but it doesn't matter since we don't move this client
* because he has the local authority (see Update())*/
_lastReceivedPosition = value;
}
}
희망이 있습니다.
한 번도 다른 수신 된 데이터 패키지를 배열에 저장하고이를 통해 보간하는 일종의 파이프 보간을 사용하여 다른 솔루션을 보았지만 내 의견으로는 더 잘 작동하지 않았습니다.
+0
당신을 진심으로 환영합니다! 도와 줘서 기쁘다;) – derHugo
운동에 Time.deltaTime을 곱하고 있습니까? 우리가 더 잘 돕도록 문제의 운동 기능을 제공하십시오. –
안녕하세요, 위치 (x, y, z)에 vector3를 사용했습니다. 사용자가 움직이면 vector3 데이터를 따라 서버로 "이동"합니다. 그리고 서버는 해당 정보를 게임에있는 다른 사용자에게 전달합니다. 서버에서이 방출을 받으면 데이터를 사용자 객체로 설정합니다. Time.deltaTime –
Time.deltaTime을 기준으로 운동을 곱하면 프레임 차이가 동일 해집니다. 이렇게하면 문제가 해결됩니다. 또한 게임 서버를 실행하기 위해 노드와 같은 것을 사용하는 것은 좋은 생각이 아닙니다. 1,000 명 이상의 플레이어를 얻게되면 그 이유를 이해하게됩니다. –