https://parkcy723.tistory.com/95
UE5 멀티플레이 채팅 야구게임만들기(1)
이번에 구현할것은 언리얼에서 멀티플레이 채팅 야구게임을 구현할 것이다. 그리고 스스로 판단하기에 C++로 멀티플레이 채팅을 구현하는 과정은 검색이나 GPT나 Grok등의 AI를 이용하면 간단히
parkcy723.tistory.com
지난번 글에 이어서 작성하는 내용이다.
실시간 점수 연동
플레이어의 Strike, Ball, Out, Count를 구현했으니 이걸 플레이어 화면에 띄워서 현재 상태를 알 수 있도록 하겠다.
지난번에 Player State에서 Strike, Ball, Out, Count변수를 구현하였으니 이 값을가지고 위젯 블루프린트 안에서 띄워주면 된다.
위젯 블루프린트인 WBP_ChatPanel에 디자이너에서 TextBlock를 추가하고 디테을 창을 확인하자
아래에 사진처럼 디테일창에 콘텐츠 > 텍스트칸이 있다.
텍스트칸에 원하는 글이나 숫자를 적어서 텍스트블럭의 상태를 바꿀 수 있지만 한번 적고나면 적은 내용이 계속 지속되기때문에 현재 상태를 알 수 없다.
하지만 오른쪽에 잘 보면 쇠사슬모양의 버튼이 있다. 눌러보자
버튼을 누르면 바인딩 생성과, 위젯 블루프린트안에 있는 함수와 변수들이 나타나게 된다.
이제 연동해줄 변수값을 클릭하여 넣어주거나 바인딩 생성으로 TextBlock에 넣어줄 함수를 생성하여 PlayerState나 GameState등 다른 블루프린트에있는 값을 연동하여 넣어줄 수도 있다.
그럼 이걸 활용하여 Strike, Ball, Out, Count에 상태를 알리는 TextBlock에 PlayerState에있는 값을 바인딩하여 넣어주면 현재 상태를 알 수 있을 것이다.
Strike값 연동 예시
새로운 바인딩을 생성하여 PlayerState에있는 Strike값을 연동해주었다.
이러한 원리 그대로 Ball, Out, Count도 똑같이 연동해주었다.
힌트 구현
문제를 풀때 내 채팅과 상대 채팅으로만 정답을 맞추는게 어려울 수도 있을 것 같아서 게임을 시작했을때 버튼을 추가하여 버튼을 클릭했을 때 랜덤으로 한자리 숫자를 보여주고 몇 초 뒤에 사라지는 방식으로 구현해 보았다.
우선 버튼을 눌렀을때 실행되야하니까 버튼을 추가하고
변수 여부에 클릭을 하고 클릭 시 이벤트를 생성해준다.
그럼 이벤트 그래프에서 On Clicked라는 이벤트가 생성된다.
그럼 이제 버튼을 눌렀을때 실행되는 것들을 구현해야한다.
버튼을 눌렀을때 실행되야하는건 랜덤으로 1 부터 3까지의 수 중 하나를 가져와서 가져온 값을 가지고 1이면 1번째 자리에있는 수를 보여줄 것이고 2면 2번째 자리, 3이면 3번째 자리를 보여주는 원리로 설계하였다.
첫 번째로 랜덤 수를 들고오는 것으로
새로운 변수를 integer타입으로 생성하고, 변수를 Set노드로 들고와서 랜덤값을 넣어줘서 초기화 시켜준다.
Random integer노드는 0부터 Max에 넣은 값에 미만까지의 값을 랜덤으로 선택하는 노드로 Max에 위에 사진처럼 3이라는 숫자를 넣으면 0 부터 2까지의 수에서 하나를 랜덤으로 return하게 된다.
그럼 Random integer노드에서 랜덤으로 된 숫자를 integer변수값으로 초기화 시켜주었다.
그럼 이후에 integer변수를 Get으로 들고와서 사용해 줄 수 있게 된다.
두 번째로 랜덤 수는 들고왔으니 랜덤 수에 맞는 자리에 수를 보여줘야한다.
integer변수에 들어있는 값을 가지고 0이냐 1이냐 2냐라는 branch문을 사용하였다.
0일때 SecretNumber에 들어있는 0번째 자리에 값은 보여주고, 나머지 자리에있는 숫자는 " X "로 표시한 다음 이 값들을 strgin타입 변수값으로 설정
1일때 SecretNumber에 들어있는 1번째 자리에 값은 보여주고, 나머지 자리에있는 숫자는 " X "로 표시한 다음 이 값들을 strgin타입 변수값으로 설정
2일때 SecretNumber에 들어있는 2번째 자리에 값은 보여주고, 나머지 자리에있는 숫자는 " X "로 표시한 다음 이 값들을 strgin타입 변수값으로 설정
그럼 이제 string타입 변수를 Get으로 들고와서 위젯 블루프린트에있는 디자이너에서 텍스트 박스에 실시간 연동 방식과 똑같이 텍스트에 바인딩을 해주면 된다.
이제 힌트를 보여줬으니 사라지게 구현해야한다.
Delay노드를 사용해 2초 뒤에 Set Visibility노드를 사용해 보여지는 힌트 텍스트 블럭을 Hidden으로 설정해주면 2초간 보여주고 숨김처리되어 안보이게 될 것이다.
버튼 클릭 시 전체 구조
버튼은 1회성이라 한 번 누르면 사라지게 구현하였다.
게임종료 위젯 바꾸기
서버클이나 노멀클에서 Strike가 3이되거나 Out이 3이되거나 Count가 0이되면 승 / 패가 나눠지며 새로운 위젯블루프린트를 생성하고 기존에있는 위젯블루프린트는 없애는 구조로 설계하였다.
기존에 플레이되고있는 위젯 블루프린트인 WBP_ChatPanel에서 플레이어가 입력을 하고 GameState에 Strike, Out, Count변수값을 가져온 위젯블루프린트 변수인copy Strike, copy Out, copy Count변수값이 각각 조건에 맞으면 PlayerController에있는 SR_GameEnd이벤트를 실행하게 되는데
PlayerControoler에서 SR_GameEnd는 모든 클라이언트에게 MC_NewWidget을 실행하며 MC_NewWidget은 WBP_ChatPanel에있는 OpenNewWidget을 실행한다.
Remove from Parent노드의 Target이 Self로 설정되어 현재 위젯블루프린트인 WBP_ChatPanel이 사라지고, Create Widget노드에 생성되는 위젯을 WBP_End로 설정한다음 Owning Player핀에 Get Owning Player노드를 연결해주고 Add to Viewport노드를 연결해주어 화면에 보이게 설정한다.
작동원리 간단하게 설명
1. WBP_Chatpanel > PlayerController
WBP_ChatPanel에서 서버클이든 노멀클이든 채팅으로 입력한 값들을 Strike, Out, Count변수들이 Branch노드에서 조건이 True가 될때까지 확인
2. WBP_ChatPanel > PlayerController
True가 되면 PlayerController에있는 SR_GameEnd이벤트를 실행
3. PlayerController > PlayerController
SR_GameEnd이벤트는 모든 클라이언트가 PlayerController에 있는 MC_NewWidget을 실행하도록함
4. PlayerController > WBP_ChatPanel
MC_NewWidget이벤트는 WBP_ChatPanel에있는 OpenNewWidget이벤트를 실행
5. WBP_ChatPanel > WBP_End
WBP_ChatPanel에 OpenNewWidget이벤트는 현재 위젯인 WBP_ChatPanel을 없애고 WBP_End위젯을 생성해서 뷰포트에 보이게함
실행 영상
승 / 패 조건
개인적으로 승 / 패 조건을 구현하는 원리를 생각하고 접목시키는데 3일이 걸려서 매우 힘들었다.
대략적인 원리를 설명하기위해 현재 구현한 리슨서버 플레이어 2명으로 설정한 곳에서 서버를 가진 클라이언트는 서버클, 클라이언트를 가진 클라이언트는 노멀클이라고 부르겠다.
1. GameState에서 Custom Event인 SR_Who Win을 생성
Stirke 판정
- 서버클에서 Strike가 3이되면 GameState에 있는 Is Strike변수가 True로 바뀌고, 서버클과 노멀클에 Is Stirke변수가 True가 됨
- 노멀클에서 Strike가 3이되면 GameState에 있는 Is Stirke변수는 초기값인 False상태이고, 서버클과 노멀클 모두 Is Stirke변수는 False상태이다.
Out 판정
- 서버클에서 Out이 3이되면 GameState에 있는 Is Out변수가 True로 바뀌고, 서버클과 노멀클에 Is Out변수가 True가 됨.
- 노멀클에서 Out이 3이되면 GameState에 있는 Is Out변수는 초기값인 False상태이고, 서버클과 노멀클 모두 Is Out변수는 False상태이다.
Count 판정
- 서버클에서 Count가 0이되면 GameState에 있는 Is Out변수가 True로 바뀌고, 서버클과 노멀클에 Is Count변수가 True가 됨.
- 노멀클에서 Count가 0이되면 GameState에 있는 Is Out변수는 초기값인 False상태이고, 서버클과 노멀클 모두 Is Count변수는 False상태이다.
요약
서버클에서 조건이 참이면 서버클, 노멀클 모두 True
노멀클에서 조건이 참이면 서버클, 노멀클 모두 False
2. Is Strike, Is Out, Is Count변수를 서버클과 노멀클에 비교해서 True일때와 False일때를 구별
Game State에서 함수를 만들어준다. 이름은 Who Strike
Switch has Authority노드를 사용하여 Is Stirke에 변수값을 가지고 서버클은 XOR boolean노드를 False로 설정하고 노멀클은 XOR boolean노드를 True로 설정한다.
Who Strike함수가 실행되면
Is Strike가 True일때
- 서버클 = True가 리턴
- 노멀클 = False가 리턴
Is Strike가 False일때
- 서버클 = False가 리턴
- 노멀클 = True가 리턴
이렇게 각 클라이언트에서 실행되고 나오는 결과값은 서버클과 노멀클에서 각각 다르게 설정할 수 있다.
그럼 Who Strike말고도 Who Out과 Who Count함수도 똑같이 만들어 주자.
3. Who Strike함수와 똑같이 Who Out, Who Count함수 생성
간단 요약
1. 서버클에서 Player State에 있는 Stirke변수가 3이 됐을 때
- 서버클에서 PlayerState에 있는 Stirke변수가 3이되면 서버클과 노멀클에 Is Strike변수가 True가 되고,
- Who Strike함수에서 IsStrike변수를 가져다가 서버클에서는 True가 리턴되고, 노멀클에서는 False가 리턴되게 하였다.
2. 노멀클에서 Player State에 있는 Strike변수가 3이 됐을 때.
- 노멀클에서 PlayerState에 있는 Strike변수가 3이되면 서버클과 노멀클에 IsStirke변수가 Flase가 되고
- WhoStirke함수에서 IsStrike변수를 가져다가 서버클에서는 False가 리턴되고, 노멀클에서는 True가 리턴되게 하였다.
3. Who Out, Who Count도 같은 원리
상황정리
그럼 이제 WBP_End가 실행되면 GameState에 있는 SR_WhoWin커스텀이벤트를 실행
WBP_End위젯 블루프린트에서에서 Who Strike를 실행하면 서버클과 노멀클에 IsStrike를 확인하여 각각 다른 결과값을 가져올 수 있다.
근데 여기서 문제는 Strike에 조건이거나 Out에 조건이거나 Count에 조건일수도있는 3가지의 경우의 수가 생겨버린다.
경우의 수 설명
1. Strike가 조건에 걸려서 승/패를 판정
2. Out이 조건에 걸려서 승/패를 판정
3. Count가 조건에 걸려서 승/패를 판정
그럼 이걸 또 판단하는 bool변수가 필요하다.
이 bool변수에 초기값은 False로 설정해주고,
1. Strike가 조건에 걸리면 Strike Boolean = True
2. Out이 조건에 걸리면 Out Boolean = True
3. Count가 조건에 걸리면 Count Boolean = True
이런식으로 boolean변수를 3가지를 만들어서
1. Strike Boolean = True라면 WhoStrike를 실행
2. Out Boolean = True라면 Who Out을 실행
3. Count Boolean = True라면 Who Count를 실행
이런식으로 또 조건을 걸어주어야 각각의 상황에서 정확하게 동작하게 된다.
여기서 또 문제는 이 Boolean값들을 서버클에서 실행하든 노멀클에서 실행하든 모든 클라이언트에 Boolean변수값이 똑같아져야한다는것이다. 그러니까 클라이언트에서 바뀐 Boolean값을 서버에 호출하고 그 값을 서버가 모든 클라이언트에 보내서 모든 클라이언트에 Boolean값이 똑같아져야한다.
그럼 Boolean변수를 어디다 만들어야 하냐인데 답은 GameState에서 Boolean을 3개 만들어주고, 서버에 호출과 서버에서 모든 클라이언트로 멀티캐스트는 PlayerController에서 구현해 줘야한다.
각각 변수들은 Public으로 설정해주고, 리플리케이션도 Replicated로 설정해준다.
그런다음 PlayerController에서 서버에서 실행 이벤트와 멀티캐스트 이벤트를 생성하여 이어준다.
1. SR_IsStrike이벤트를 실행하면 모든 클라이언트들이 MC_Str을 실행하게 된다.
2. MC_Str이 실행되면 GameState에있는 Strike Boolean변수가 True로 바뀌게 된다.
SR_IsStrike이벤트가 실행되면 모든 클라이언트에 GameState에있는 Strike Boolean값이 True로 바뀌게된다.
이런 방식으로 Out Boolean과 Count Boolean에 값을 바꾸는 이벤트들을 각각 만들어 준다.
그럼 이제 SR_IsStrike이벤트는 PlayerState에있는 Strike가 3이되면 실행해주면 되므로 간단하게 WBP_ChatPanel에서 실행해 주었다.
PlayerState에 있는 Strike, Out, Count값을 WBP_ChatPanel에 copy Strike, copy Out, copy Count변수를 만들어 연동시켜주었다.
copy Strike가 3이되면 SR_IsStrike가 실행
copy Out이 3이되면 SR_IsOut이 실행
copy Count가 3이되면 SR_IsCount가 실행되는 구조이다.
그럼 Strike, Out, Count가 각각 조건이 True가됐을 때 그거에 맞는 GameState에 있는 Strike Boolean, Out Boolean, Count Boolean이 True가 될 것이다.
그럼 이제 어떤 조건이 참인지를 판단하는 건 해결했으니 아까 위에서 구현한 GameState에 있는 WhoStrike, WhoOut, Who Count함수를 사용하여 서버클과 노멀클에 이겼는지 졌는지를 판단해주자.
WBP_End
WBP_End위젯 블루프린트가 생성되면 GameState에 있는 Strike Boolean, Out Boolean, Count Boolean값을 들고와 True인지 False인지 판단하는 Branch노드를 사용해준다.
Strike Boolean이 True면 GameState에 Who Strike함수가 실행
Out Boolean이 True면 GameState에 Who Out함수가 실행
Count Boolean이 True면 GameState에 Who Count함수가 실행
하나라도 True가 있다면 Branch노드에서 True로 실행이되게 된다.
Who Stirke, Who Out, Who Count함수가 실행되면서 True값과 False값으로 서버클과 노멀클에 승/패 판정이 나눠지게 되며 각각 실행되는 Winner와 Loser함수는
Set Visibility를 통해 Winner함수는 Win텍스트블럭이 보이게하고, Loser함수는 Lose텍스트 블럭이 보이게한다.
플레이 영상
'Unreal Engine 5 > UE5 멀티채팅 야구 게임' 카테고리의 다른 글
UE5 멀티플레이 채팅 야구게임만들기(1) (0) | 2025.03.24 |
---|---|
UE5 Blueprint로 멀티플레이 채팅 구현 (0) | 2025.03.16 |