3 - 이동 & 카메라
개요
Fusion 103 공유에서 기존 씬은 플레이어 입력에 기반한 플레이어 움직임과 올바른 플레이어 객체를 따르는 1인칭 카메라를 추가하여 확장됩니다.
플레이어 이동
Fusion의 경우 이동과 같은 모든 틱을 업데이트하는 게임 플레이 코드가 Update / FixedUpdate
에서 실행되어서는 안 됩니다. 대신 FixedUpdateNetwork
를 사용해야 합니다. 그러면 이동이 원활해지고 모든 클라이언트에 정확하게 보간 됩니다.
새 스크립트를 만들고 이름을 PlayerMovement
로 지정합니다. MonoBehaviour
가 아닌 NetworkBehaviour
에서 상속되도록 하고 다음 코드를 스크립트에 추가합니다:
C#
private CharacterController _controller;
public float PlayerSpeed = 2f;
private void Awake() {
_controller = GetComponent<CharacterController>();
}
public override void FixedUpdateNetwork()
{
// Only move own player and not every other player. Each player controls its own player object.
if (HasStateAuthority == false)
{
return;
}
Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * Runner.DeltaTime * PlayerSpeed;
_controller.Move(move);
if (move != Vector3.zero)
{
gameObject.transform.forward = move;
}
}
HasStateAuthority
는 클라이언트가 객체를 제어하는지를 확인하는 데 사용될 수 있으며, NetworkTransform
은 변경 사항을 StateAuthority
에서 다른 모든 클라이언트에게 동기화할 뿐입니다. 다른 클라이언트가 객체의 위치를 변경하면 해당 변경 사항은 로컬 변경 사항에 불과하며, 향후 네트워크의 데이터로 재정의됩니다.
플레이어 프리팹에 PlayerMovement
컴포넌트를 추가합니다.
카메라
카메라를 설정하는 방법은 여러 가지가 있으며(3인칭, 1인칭 등) 이를 구현하는 방법도 다릅니다. 멀티 플레이어 게임에서는 종종 로컬 플레이어 객체를 따르는 단일 카메라가 필요합니다. 이를 구현하는 일반적인 방법은 두 가지입니다.
- 로컬 플레이어 객체가 생성되면 카메라를 인스턴스화합니다.
- 카메라를 씬의 일부로 가지고 있습니다. 로컬 플레이어 객체가 생성되면 카메라를 찾고 카메라의 대상을 설정합니다.
이 단계에서는 두 번째 접근 방식이 사용됩니다.
새 스크립트를 만들고 FirstPersonCamera
라는 이름으로 저장합니다. 여기에 다음 코드를 추가합니다:
C#
using UnityEngine;
public class FirstPersonCamera : MonoBehaviour
{
public Transform Target;
public float MouseSensitivity = 10f;
private float vertialRotation;
private float horizontalRotation;
void LateUpdate()
{
if (Target == null)
{
return;
}
transform.position = Target.position;
float mouseX = Input.GetAxis("Mouse X");
float mouseY = Input.GetAxis("Mouse Y");
vertialRotation -= mouseY * MouseSensitivity;
vertialRotation = Mathf.Clamp(vertialRotation, -70f, 70f);
horizontalRotation += mouseX * MouseSensitivity;
transform.rotation = Quaternion.Euler(vertialRotation, horizontalRotation, 0);
}
}
이것은 매우 간단한 1인칭 카메라 구현입니다. 코드에는 멀티플레이어 요소가 포함되어 있지 않습니다. 이 카메라를 Cinemachine을 포함한 대상 객체와 함께 작동하는 다른 카메라 설정으로 교체할 수 있습니다.
FirstPersonCamera
를 MainCamera
게임 오브젝트에 올려놓습니다. 대상을 드래그할 필요가 없습니다. 대상은 런타임에 코드에 의해 설정됩니다.
대상을 지정하려면 PlayerMovement
스크립트를 엽니다. 카메라를 저장할 변수를 추가합니다:
C#
public Camera Camera;
그런 다음 플레이어 객체가 생성되면 로컬 플레이어인 경우 카메라를 찾아 설정합니다.
C#
public override void Spawned()
{
if (HasStateAuthority)
{
Camera = Camera.main;
Camera.GetComponent<FirstPersonCamera>().Target = GetComponent<NetworkTransform>().InterpolationTarget;
}
}
NetworkObjects
를 초기화할 때는 항상 Awake/Start
가 아닌 Spawned
를 사용해야 합니다. Awake/Start
에서는 아직 NetworkObject
를 사용할 준비가 되지 않았을 수 있습니다.
HasStateAuthority
플레이어가 제어하는 객체에 대해서만 true이므로 다른 플레이어 객체가 아닌 로컬 플레이어 개체만 true입니다.마지막으로, 1인칭 게임에서 플레이어 캐릭터가 보는 방향으로 움직이므로 움직임을 조금 조정합니다. Vector3 이동
이 계산되는 선을 다음과 같이 대체합니다:
C#
var cameraRotationY = Quaternion.Euler(0, Camera.transform.rotation.eulerAngles.y, 0);
Vector3 move = cameraRotationY * new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * Runner.DeltaTime * PlayerSpeed;
버튼 눌림 처리
Update
시 유니티에서 GetButtonDown
, up 등의 입력이 1회 발생합니다. Fusion에서는 FixedUpdateNetwork
에서 이동 등의 게임 코드를 실행해야 합니다. 이는 버튼 상태를 정확하게 추적하기 위해서는 특별한 처리가 필요하다는 것을 의미합니다.
FixedUpdateNetwork
와 같은 입력을 캡처하는 데는 여러 가지 방법이 있습니다:
Update
에서 버튼 다운을 쿼리 합니다. 결과를 부울 변수에 저장하고 게임 로직에 사용하십시오.FixedUpdateNetwork
의 끝에서 삭제합니다.- Fusion의 NetworkInput을
NetworkButtons
과 함께 사용합니다. - 새 유니티 입력 시스템을 사용하여
업데이트 모드
를수동 업데이트
로 설정하고FixedUpdateNetwork()
에서InputSystem.Update
를 호출합니다.
점프
플레이어에 대한 점프 액션을 구현하여 버튼 누르기를 처리하는 예를 구현합니다. 이 경우 이전 장에 나열된 옵션 중 옵션 1이 사용됩니다.
먼저 PlayerMovement
에 다음 변수를 추가합니다:
C#
public float JumpForce = 5f;
public float GravityValue = -9.81f;
private Vector3 velocity;
private bool _jumpPressed;
_jumpPressed
변수는 버튼 상태를 추적하기 위해 사용됩니다. velocity
는 공중에 떠있는 동안 KCC에 인공 중력을 더해주기 위한 것입니다.
버튼 다운 상태를 폴링 하기 위해 각 Update
는 다음 코드를 추가합니다:
C#
void Update()
{
if (Input.GetButtonDown("Jump"))
{
_jumpPressed = true;
}
}
FixedUpdateNetwork
의 끝에서 점프 상태를 지웁니다:
C#
_jumpPressed = false;
_controller.Move
호출하는 줄을 다음으로 바꿔줍니다:
C#
_velocity.y += GravityValue * Runner.DeltaTime;
if (_jumpPressed && _controller.isGrounded)
{
_velocity.y += JumpForce;
}
_controller.Move(move + _velocity * Runner.DeltaTime);
마지막으로 HasStateAuthority
체크 직후 다음을 추가하여 지상에서 속도를 재설정합니다:
C#
if (_controller.isGrounded)
{
velocity = new Vector3(0, -1, 0);
}
유니티로 돌아가서 게임을 시작하고 공유 클라이언트 시작
을 누릅니다. 스페이스
버튼을 누르면 캐릭터가 점프하는 모습이 나타납니다.