5 - 차량 조정
개요
5부에서는 Unity Wheel Collider 튜토리얼의 일부로 생성한 CarControl
스크립트에 약간의 수정을 가하여 차량 위치와 움직임 예측을 개선합니다.
위치 동기화
차량의 위치는 이전 단계에서 추가한 NetworkTransform
에 의해 동기화됩니다. 추가적으로, Physics Forecast 시스템은 원격 시간 이후의 예측(extrapolation)을 수행하여 차량 위치를 예측합니다. Forecast Physics가 비활성화되어 있으면 위치는 원격 시간으로 동기화됩니다.
Network Project Config
에셋에서 해당 박스가 체크되어 있는지 확인하여 Forecast Physics가 활성화되었는지 확인하세요.

FixedUpdate()
물리 기반 NetworkTransform
을 사용할 때는 차량의 움직임 로직이 Update()
나 FixedUpdateNetwork()
가 아닌 FixedUpdate()
에서 처리되어야 합니다.
이는 비물리 기반 NetworkObject
가 FixedUpdateNetwork()
를 사용해야 하는 것과는 다릅니다.
Forecast Physics에서는 Unity의 RigidBody
보간(interpolation)을 사용하여 부드러운 움직임을 제공하므로, FixedUpdateNetwork()
기반의 네트워크 보간을 사용하지 않습니다.
Unity의 보간 기능을 활용하려면 차량의 RigidBody
의 Interpolation
모드를 Interpolate
로 설정하세요.

차량 움직임 예측 개선
이번 단계에서는 차량의 현재 가속 상태와 조향 상태(turning amount)를 네트워크로 전송할 수 있도록 구현합니다. 이를 통해 각 클라이언트는 수신한 최신 입력 값을 기반으로 다른 차량의 움직임을 예측할 수 있습니다.
예: 클라이언트 A가 "왼쪽"을 누르고 있다면, 클라이언트 B는 클라이언트 A의 차량이 계속 "왼쪽"으로 조향할 것이라 예측하게 됩니다. 이로 인해 더 현실적인 예측이 가능해집니다.
이 작업을 위해 기존의 MonoBehaviour
대신 NetworkBehaviour
를 상속해야 하며, 가속 및 조향 상태를 네트워크 속성(Networked Property)으로 만들기 위해 Fusion의 [Networked]
특성을 사용합니다.
네트워크 속성은 { get; set; }
이 포함된 자동 구현 속성(auto-implemented property)이어야 하며, 일반 필드는 지원되지 않습니다.
아래 코드 스니펫은 vInput
(가속)과 hInput
(조향) 값이 네트워크 속성으로 변경된 것을 보여줍니다:
C#
public class CarControl : NetworkBehaviour
{
public float motorTorque = 2000;
public float brakeTorque = 2000;
public float maxSpeed = 20;
public float steeringRange = 30;
public float steeringRangeAtMaxSpeed = 10;
public float centreOfGravityOffset = -1f;
[Networked] private float vInput { get; set; }
[Networked] private float hInput { get; set; }
이 코드는 FixedUpdate()
상단의 입력 처리 부분도 다음과 같이 변경됩니다:
C#
void FixedUpdate()
{
if (Object.HasStateAuthority)
{
vInput = Input.GetAxis("Vertical");
hInput = Input.GetAxis("Horizontal");
}
vInput
과 hInput
값은 StateAuthority
를 가진 플레이어만 설정할 수 있으며, 나머지 클라이언트는 해당 값을 수신합니다. 이렇게 하면 각 클라이언트는 자신이 제어하지 않는 차량에 대해서도 최신 가속 및 조향 정보를 사용하여 보다 정확한 움직임 예측이 가능합니다.
결과적으로, 예측된 가속 및 조향 정보 + 물리 예측 시스템의 조합은 매끄럽고 정확한 플레이 경험을 제공합니다.
최종 CarControl.cs 전체 코드:
C#
using Fusion;
using UnityEngine;
public class CarControl : NetworkBehaviour
{
public float motorTorque = 2000;
public float brakeTorque = 2000;
public float maxSpeed = 20;
public float steeringRange = 30;
public float steeringRangeAtMaxSpeed = 10;
public float centreOfGravityOffset = -1f;
[Networked] private float vInput { get; set; }
[Networked] private float hInput { get; set; }
WheelControl[] wheels;
Rigidbody rigidBody;
// Start is called before the first frame update
void Start()
{
rigidBody = GetComponent<Rigidbody>();
// Adjust center of mass vertically, to help prevent the car from rolling
rigidBody.centerOfMass += Vector3.up * centreOfGravityOffset;
// Find all child GameObjects that have the WheelControl script attached
wheels = GetComponentsInChildren<WheelControl>();
}
// Update is called once per frame
void FixedUpdate()
{
if (Object.HasStateAuthority)
{
vInput = Input.GetAxis("Vertical");
hInput = Input.GetAxis("Horizontal");
}
// Calculate current speed in relation to the forward direction of the car
// (this returns a negative number when traveling backwards)
float forwardSpeed = Vector3.Dot(transform.forward, rigidBody.velocity);
// Calculate how close the car is to top speed
// as a number from zero to one
float speedFactor = Mathf.InverseLerp(0, maxSpeed, forwardSpeed);
// Use that to calculate how much torque is available
// (zero torque at top speed)
float currentMotorTorque = Mathf.Lerp(motorTorque, 0, speedFactor);
// and to calculate how much to steer
// (the car steers more gently at top speed)
float currentSteerRange = Mathf.Lerp(steeringRange, steeringRangeAtMaxSpeed, speedFactor);
// Check whether the user input is in the same direction
// as the car's velocity
bool isAccelerating = Mathf.Sign(vInput) == Mathf.Sign(forwardSpeed);
foreach (var wheel in wheels)
{
if (!wheel.WheelCollider)
{
continue;
}
// Apply steering to Wheel colliders that have "Steerable" enabled
if (wheel.steerable)
{
wheel.WheelCollider.steerAngle = hInput * currentSteerRange;
}
if (isAccelerating)
{
// Apply torque to Wheel colliders that have "Motorized" enabled
if (wheel.motorized)
{
wheel.WheelCollider.motorTorque = vInput * currentMotorTorque;
}
wheel.WheelCollider.brakeTorque = 0;
}
else
{
// If the user is trying to go in the opposite direction
// apply brakes to all wheels
wheel.WheelCollider.brakeTorque = Mathf.Abs(vInput) * brakeTorque;
wheel.WheelCollider.motorTorque = 0;
}
}
}
}
게임 실행하기
축하합니다! 기존 차량 게임에 Fusion 공유 모드 네트워킹을 성공적으로 적용하셨습니다. 이제 모든 기능이 정상 작동하는지 테스트할 시간입니다.
두 명의 플레이어가 연결된 상태로 테스트하는 가장 간단한 방법은 게임을 빌드 한 후 두 인스턴스를 동시에 실행하는 것입니다. 실행 후, 각 클라이언트는 자신의 차량을 제어하게 됩니다.

다음 단계: 필수 예측 차량 물리 튜토리얼 6 - 다음으로 어디로 갈까?
Back to top