게임 개발 메모장
[ UE5 ] 캐릭터 공격 구현 예시 본문
1. 언리얼에서는 클라이언트에서 서버로 패킷을 보내는 방법은 서버RPC가 유일하기 때문이다.
서버에 보낼 명령의 중요도에 따라 Reliable 인지 Unreliable 인지 판단해서 RPC 함수를 선언해주면 된다.
2. 게임 플레이 판정은 서버에서 무조건 처리하는 것 게임을 구현할 때
가끔식은 서버의 부하를 줄이고 게임의 쾌적한 반응성을 위해서
클라이언트에서 중요한 기능을 처리하는 경우가 종종 있다.
하지만, 최종 판정은 항상 서버에서 진행되도록 원칙을 지켜줘야 된다.
3. 게임 플레이에 영향을 주는 중요한 정보는 프로퍼티 리플리케이션을 사용하는 것이다.
예를 들어, 모바일 게임을 하고 있는데 엘리베이터를 타서 접속이 잠시 끊어진 상황이라면
엘리베이터에서 내리면 다시 재접속을 하게 될 텐데 이렇게 재접속한 상황에서
마치 접속이 끊어진 적이 없었던 것처럼 게임이 진행되어야 한다.
이때 필요한 데이터가 게임 플레이에 영향을 주는 중요한 데이터이다.
이러한 데이터들은 프로퍼티 리플리케이션으로 관리해주는 것 좋다.
4. 게임 플레이에 무관한 클라이언트의 단순 시각적인 효과를 재생하는 기능.
클라이언트 RPC 혹은 멀티캐스트 RPC를 사용하는 것이 좋다.
이 중에서 가급적이면 멀티캐스트 RPC 보다 클라이언트 RPC를 사용하는 것이 좋다.
FLOW ( 흐름 )
클라이언트의 입력에서부터 공격이 시작된다.
서버가 이것을 처리하도록 서버 RPC를 호출한다.
서버 RPC의 호출을 받은 서버는 _Implementation 함수를 실행할 것이다.
이 함수에서는 NetMulticastRPC를 호출해서 서버와 모든 클라이언트에게 명령을 보낸다.
이 서버의 멀티캐스트 RPC의 구현부에는 서버에서 동작하는 특별한 로직을 넣어준다.
현재 폰의 공격 상태를 관리할 수 있도록 서버에서 공격이 시작되었을을 체크하는
프로퍼티를 설정하고, 공격이 끝날 때 발동하는 타이머를 걸어준다.
이 타이머가 발동되면 서버는 공격이 끝났다고 판정해서 해당 프로퍼티를
다시 갱신 해 줄것이다.
그리고 나서 서버와 모든 클라이언트가 모션을 재생하도록
몽타주를 재생하는 로직을 구현한다.
따라서, 이 멀티캐스트 RPC 신호를 받은 모든 컴퓨터들은 자신의 화면에서
공격 명령을 내린 폰에 공격 애니메이션을 재생하게 된다.
공격 애니메이션을 재생하면 몽타주에 설정된 애님 노티파이 기능에 의해서 특정
시점에서 이벤트가 발생한다.
클라이언트에서 발생한 애님 노티파이는 모두 무시하고
서버에서 발생한 애님 노티파이만 처리하도록 하자.
그래서, 서버에서 발생한 이벤트 타이밍에 다른 유저가 공격에 맞았는지를
체크하는 레이캐스팅 함수를 호출하여 공격 판정을 처리하고 맞은 유저에게
데미지를 전달 한다.
서버에서는 전달된 데미지를 통해 유저의 현재 HP 값이 깍일 텐데
나머지 클라이언트에서도 이 깍인 데이터를 동기화 하는 기능을 이후에 구현한다.
그 다음에 설정된 타이머에서 공격이 종료되면 캐릭터의 공격 상태가 업데이트 될 것
이것을 클라이언트에 보내가지고 클라이언트의 공격 프로퍼티를 최종적으로 업데이트 하면
기본적인 공격 기능을 구현 할 수 있다.
ServerRPCAttack() 함수를 '클라이언트' 쪽에서 호출이 되면 '서버' 에서 실행을 한다.
공격을 할 수 있는지 없는지 여부를 체크 하고 그 이후에 행동
OnRap 함수, 이벤트 함수를 사용하는 경우에는 항상 클라이언트에서만 호출이된다.
서버에서는 자동으로 호출되지 않기 때문에 서버 로직의 경우
이 함수를 명시적으로 호출해 주는 것이 필요하다.
무조건 구현해줘야 하는 GetLifeTimeReplicatedProps
채널의 라이프 타임, 채널이 계속 활성화 되어 있다면 활성화되는 시작부터 끝까지
프로퍼티 리플리케이션이 계속 활성화 된다.
언리얼 엔진은 액터가 아닌 다른 언리얼 오브젝트에도 리플리케이션을 사용할 수 있도록 기능을 제공한다.
이러한 액터가 아닌 액터에 종속된 언리얼 오브젝트를 서브 오브젝트라고 한다.
이러한 서브 오브젝트 중에서 액터 컴포넌트를 리플리케이션하는 방법은
먼저 액터 컴포넌트의 생성자에서 SetReplicated라는 함수의 true 값을 전달해서
리플리케이션을 활성화 시켜줘야 된다.
이를 통해서 액터 컴퍼넌트의 리플리케이션 기능이 활성화 되었다면
언리얼엔진은 액터 컴퍼넌트의 ReadyForReplication 이라는 이벤트 함수를 준비가
될때 자동으로 호출해준다.
ReadyForReplication 함수는 ActorComponent의 기본 설계 기능이 완료되는
타이밍에 호출되는 InitializeComponent 함수보다 늦게 호출이 되고,
게임 참여할 때 실행되는 BeginPlay 함수보다 먼저 호출되는 특징을 가진다.
이는 PostInitializedComponents 함수와 BeginPlay 사이에서 호출되는
PostNetInit 함수와 유사하다.
액터 컴포넌트의 리플리케이션을 활성화하고, 액터 컴포넌트의
현재 HP 프로퍼티가 모든 클라잉너트에 잘 동기화 되도록 구현
이미 캐릭터가 준비가 될 때 활성화 된 것을 볼수가 있다.
클라이언트를 추가 해보고 실행 시점을 다시 보면
PostInitializedComponents 플레이어 컨트롤러의 초기화가 진행이 되었고
PostNetInit 함수를 통해 가지고 네트워크로부터 전달 받은 데이터가 있으면 모두 다
전달 받아서 이 함수를 호출 했다.
그리고 나서 Owner에 대한 값도 변경이 잘 확인이 된다.
첫 번째(나), 두 번째(서버) 플레이어에 대한 프로퍼티도 지금 전달 받은 상황이다.
그 상황에서 BeginPlay가 실행이 되었는데 컨트롤러는 이미 시작을 했고,
그런데 플레이어를 시작하기 전에
BeginPlay가 시작하기 전에 ReadyForReplication이 이렇게 호출된 것을 볼 수 있다.
우선 패킷 렉이 발생하게 되면 입력이 서버로 전달되는 과정에서 시간이 오래 소요가 됨.
그리고 또 서버에서 클라이언트로 다시 전달되는 과정에서 시간이 또 중복으로 소요
이 중복으로 소요되는 기간 동안에 입력을 넣었지만 애니메이션이
재생하지 않고 대기하고 있는 상황이 발생한다.
공격을 입력 했는데 서버로부터 응답이 올 때까지 대기하고 있어야 한다.
클라이언트의 공격 명령을 판정하는 타이밍도 이때 입력을 했지만 한참 뒤에서나
판정을 할 수 밖에 없다.
-> 그래서 서버에서 모든 것을 처리하는 방식이 데이터 관리 측면에서는
안전한 방법일 수도 있지만 통신 상태가 나쁜 상황에서 사용자는 한 박자 늦은
플레이를 진행할 수밖에 없어서 공정한 플레이를 진행하기가 어렵고
정확한 판정을 내기가 어렵다.
1. 클라이언트에 입력 명령이 들어오면 바로 애니메이션을 재생
2. 동시에 서버에 RPC도 호출
3. 서버는 패킷을 받으면 클라이언트와 동일한 작업을 수행함.
4. 전송 과정에서 렉이 있다 보다 한 박자 늦게 시작할 것.
5. 애니메이션의 재생 타이밍은 두 컴퓨터가 다르게 동작함.
6. 하지만 이때 중요한 정보는 동기화 되도록 설정
7. 클라이언트가 RPC를 보낼 때 현재 클라이언트에서의 시간 정보를 보내고
서버가 패킷을 받은 시간과 비교해서 얼마나 렉이 걸렸는지를 측정한다.
8. 이를 반영해서 최대한 클라이언트와 동일한 타이밍에 서버에서의 공격이 마치도록 구성
9. 판정의 경우도 서버에서 진행하지 않고 클라이언트에서 진행하도록 변경
10. 현재 판정하는 타이밍은 재생하는 애니메이션에 따라 결정이 되는데
클라이언트와 서버가 서로 다른 타이밍의 애니메이션을 재생하고 있다.
그렇기 때문에 서버의 판정 타이밍을 사용하지 않고 클라이언트의 판정 타이밍을 사용해야
보다 공정한 게임이 될 것이다.
하지만, 클라이언트의 판정을 사용한다고 클라이언트에서 판정을 확정해버리면
클라이언트가 악의적으로 위조했을 때 게임 플레이에 문제가 발생한다.
그래서 클라이언트에서 판정을 수행할 때, 판정 결과를 서버로 보내고,
서버에서 보낸 판정 결과를 수용할지 판단하도록 구성함.
만일 서버가 클라이언트가 보낸 판정 결과를 수용한다면 액터에게 데미지를 전달하도록
설계함
----------
< 이후 글 개선... >
'언리얼 엔진 > Network' 카테고리의 다른 글
[ UE5 ] 액터의 역할과 커넥션 핸드셰이킹 (0) | 2024.01.06 |
---|---|
[ UE5 ] RPC (1) | 2024.01.05 |
[ UE5 ] 액터 리플리케이션 (0) | 2023.12.25 |
[ UE5 ] 커넥션과 오너십 (0) | 2023.12.25 |
[ UE5 ] 게임 모드와 로그인 (0) | 2023.12.25 |