2017-12-27 8 views
0

Unity와 함께 3D 모바일 게임을 개발 중이며 멀티 플레이어 부분을 작성해야하는 시점에 왔습니다. node.js/socket.io와의 모든 중매 등을 썼지 만 게임 내에서 문제가 발생했습니다. 문제는; 사용자가 이동할 때마다, 그는 자신의 위치를 ​​다른 사용자에게 전송합니다. 그러나 서버가 매우 강력하다면 (CPU 4GHz, 램 16GB), 사용자는 싱글 플레이 (AI 동작)를하는 것처럼 움직이지 않습니다. 그들은 몇 프레임 미끄러 져 보였으므로 그것이 예상대로 부드럽지 않게 움직입니다. FPS 차이와 같은 원인이 될 수있는 것에 대한 아이디어가 있습니다. 사용자 중 한 명이 다른 FPS 차이의 다른 것보다 느리게 방출 할 수 있기 때문에. 모든 아이디어 어떻게이 문제를 없앨 수 있습니까?3D 멀티 플레이어 게임의 FPS 차이점

+0

운동에 Time.deltaTime을 곱하고 있습니까? 우리가 더 잘 돕도록 문제의 운동 기능을 제공하십시오. –

+0

안녕하세요, 위치 (x, y, z)에 vector3를 사용했습니다. 사용자가 움직이면 vector3 데이터를 따라 서버로 "이동"합니다. 그리고 서버는 해당 정보를 게임에있는 다른 사용자에게 전달합니다. 서버에서이 방출을 받으면 데이터를 사용자 객체로 설정합니다. Time.deltaTime –

+0

Time.deltaTime을 기준으로 운동을 곱하면 프레임 차이가 동일 해집니다. 이렇게하면 문제가 해결됩니다. 또한 게임 서버를 실행하기 위해 노드와 같은 것을 사용하는 것은 좋은 생각이 아닙니다. 1,000 명 이상의 플레이어를 얻게되면 그 이유를 이해하게됩니다. –

답변

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

관련 문제