카테고리 없음

TIL260527 - 챕터2 프로젝트 - 1

옆집히드라 2026. 5. 27. 23:44

요구사항


  • IGameState는 모든 virtual을 override한다. Enter에 이미지 로드를 추가한다.(기본이미지 dragon.png)
  • enum으로 플레이어에 직업 추가 정의 필요(기본, 탱커, 힐러)
  • Packet과 NetworkManager 정의 시 #pragma region COOP으로 묶어서 작성

클래스 정의


  • COOPManager: 싱글턴, 플레이어들의 스테이터스 기록, 보스 몬스터 기록, 전투 로직 담당
  • COOPReadyState, COOPSelectJobState, COOPBattleState, COOPRewardState extends IGameState

상태 정의


  • COOPReadyState
    • 직업 선택 시 COOPSelectJobState로 클라 상태 전환
    • PKT_C2S_COOP_ReadyPKT_C2S_COOP_Update_Status 도 전송
    • 모든 플레이어가 PKT_C2S_COOP_Ready 전송하면 PKT_S2C_CHANGE_STATE COOPBattleState
  • COOPSelectJobState
    • 1, 2, 3 직업선택, 0 돌아가기
  • COOPBattleState
    • Ready 순서로 플레이어 턴 순서 결정 PKT_S2C_COOP_Update_Turn 시 플레이어는 턴 시작(아니면 턴 대기)
    • 플레이어는 PKT_C2S_COOP_Use_Attack PKT_C2S_COOP_Use_Block PKT_C2S_COOP_Use_Heal PKT_C2S_COOP_Use_Item 중 1가지 선택 가능(Block은 탱커, Heal은 힐러 클래스만 제공됨)
    • 서버에서는 PKT_C2S_COOP_Use_Attack 시 몬스터 데미지 갱신, PKT_C2S_COOP_Use_Block 을 받았다면 block 대상자에게 가는 공격을 block 시전자로 갱신
    • 계산이 끝나면 PKT_C2S_COOP_Update_Status PKT_S2C_COOP_Update_Monster 로 각각 전장 갱신
    • 만약 isDead인 플레이어면 관전 전환
    • 만약 보스 사망 시 PKT_S2C_CHANGE_STATE 로 COOPRewardState
  • COOPRewardState
    • 각 플레이어들 PKT_C2S_COOP_Update_Status로 체력 업데이트, PKT_S2C_COOP_Take_Item 으로 레이드 보상
    • PKT_S2C_CHANGE_STATE 로 GameStartState

패킷 정의


name은 최대 32바이트 char

C2S

  • PKT_C2S_COOP_Ready bool isReady
  • PKT_C2S_COOP_Update_Status int atk, int hp, enum job, bool isDead
  • PKT_C2S_COOP_Use_Item targetName , int amount
  • PKT_C2S_COOP_Use_Attack sourceName, targetName, int amount
  • PKT_C2S_COOP_Use_Block sourceName, targetName
  • PKT_C2S_COOP_Use_Heal sourceName, targetName, int amount

S2C

  • PKT_S2C_CHANGE_STATE EGameState targetState
  • PKT_S2C_COOP_Update_Status int atk, int hp, enum job
  • PKT_S2C_COOP_Update_Turn targetName, int turn
  • PKT_S2C_COOP_Update_Monster targetName, int hp
  • PKT_S2C_COOP_Take_Item targetName, itemName

개인 참고용


 

사전 준비: 패킷 구조체 정의

가장 먼저 Packet.h에 통신할 데이터를 정의해야 합니다.

  1. PacketType Enum에 PKT_C2S_...PKT_S2C_... 추가
  2. C2S와 S2C 각각에 사용할 패킷 구조체(struct) 정의 (Header 상속 및 사이즈 지정)

1단계: C2S (Client to Server) 파이프라인 구현

클라이언트가 "나 이거 할게"라고 서버에 요청하고, 서버가 이를 처리하는 과정입니다.

  1. Send... 함수 작성 (요청 발송)
    • 위치: NetworkManager
    • 역할: UI State에서 호출되는 진입점입니다. 패킷 구조체를 채웁니다.
    • 주의: 방장 최적화 로직이 반드시 들어가야 합니다.C++
    • if (Client::isServer) { OnHost새기능(INVALID_SOCKET, pkt); // 방장은 통신 생략 } else { SendToServer(&pkt, pkt.header.size); // 게스트는 패킷 전송 }
  2. ProcessPacket 분기 추가 (서버 수신부)
    • 위치: NetworkManager::ProcessPacket
    • 역할: switch문에 PKT_C2S_... 케이스를 추가하고, 데이터 캐스팅 후 OnHost... 함수로 넘겨줍니다. 방장(Client::isServer)만 이 분기를 타도록 방어 코드가 필요합니다.
  3. OnHost... 함수 작성 (서버 로직 처리)
    • 위치: NetworkManager
    • 역할: 패킷을 받은 서버가 실행하는 핵심 로직입니다.
    • 구현 내용: * 데이터 유효성 검사 (턴이 맞는지, 쿨타임인지, 살아있는지 등)
      • 내부 데이터 상태 갱신 (데미지 적용 등)
      • 처리가 끝난 후 결과를 클라이언트들에게 알리기 위해 S2C 1단계의 Broadcast... 함수를 호출합니다.

2단계: S2C (Server to Client) 파이프라인 구현

서버가 "이런 결과가 나왔으니 화면을 업데이트해라"라고 모든 클라이언트에게 전파하는 과정입니다.

  1. Broadcast... 함수 작성 (결과 전파)
    • 위치: NetworkManager
    • 역할: OnHost... 처리 직후 호출됩니다. S2C 패킷 구조체를 조립합니다.
    • 구현 내용:
      • BroadcastToClients()를 호출하여 접속 중인 모든 게스트 소켓에 전송합니다.
      • 방장 로컬 화면도 업데이트해야 하므로 Notify... 함수를 함께 호출합니다.
  2. ProcessPacket 분기 추가 (클라이언트 수신부)
    • 위치: NetworkManager::ProcessPacket
    • 역할: 게스트가 PKT_S2C_... 케이스를 수신했을 때의 처리입니다. 서버 로직이 아니므로 Client::isServer일 때는 무시(break)하도록 합니다. 수신한 패킷을 Notify... 함수로 넘깁니다.
  3. Notify... 함수 작성 (로컬 옵저버 알림)
    • 위치: NetworkManager
    • 역할: 네트워크 계층에서 수신된 데이터를 게임(UI) 계층으로 밀어 넣습니다.
    • 구현 내용: GameManager를 통해 현재 State 포인터를 가져온 뒤, dynamic_cast로 타겟 State(예: ArenaBattleState)인지 확인하고, 타겟 State의 On... 함수를 호출합니다.
  4. On... 함수 작성 (UI 및 상태 갱신)
    • 위치: 타겟 State 클래스 (예: ArenaBattleState)
    • 역할: 전달받은 네트워크 결과를 멤버 변수에 저장하고, Update() 루프를 통해 화면에 렌더링되도록 합니다.