1 분 소요

Intro

이번 포스팅에서는 보스몬스터와 컷씬을 네트워크 동기화하는 작업을 수행하였습니다.

  • 보스몬스터 소환

  • 컷씬

image

보스몬스터

보스몬스터의 등장과 끝은 다음과 같이 진행됩니다.

image


수정할 보스몬스터와 관련된 스크립트는 다음 5개입니다.

image

  • GruntExplosion, GruntThunderbolt : 플레이어에게 피해를 입히는 부분을 RPC로 호출하도록 하였습니다.

  • GruntRange : 컷씬동안 보스몬스가 초기상태를 유지하도록하고, 컷씬이 끝나면 플레이어를 탐지하도록 하였습니다.

  • BossMonster : 타겟 플레이어를 설정하는 로직을 추가하고, 애니메이션 동기화를위해 RPC 메서드를 추가하였습니다.

  • Grunt : 모든 플레이어화면에서 동일한 공격을 수행하도록 동기화하였습니다.

  • 보스몬스터 관련 코드보기

MultiDungeonManager 클래스


보스몬스터를 소환하고 컷씬을 플레이하는 로직을 추가하였습니다.

// MultiDungeonManager.cs
public class MultiDungeonManager : MonoBehaviourPunCallbacks
{
    [SerializeField] private Transform[] playerSpawnPositions;              // 플레이어 스폰위치
    [SerializeField] private Transform[] monsterSpawnPositions;             // 몬스터 스폰위치
    [SerializeField] private Transform bossSpawnPosition;                   // 보스몬스터 스폰위치
    [SerializeField] private GameObject cutSceneObj;                        // 컷씬 카메라 오브젝트
    [SerializeField] private TimelineAsset[] timelineAsset;                 // 타임라인 에셋

    public int currentMonsterCount = -1;                    // 현재 몬스터 수(기본 -1)
    private GameObject boss;                                // 보스몬스터 오브젝트
    private PlayableDirector pd;                            

    private bool bossSpawned = false;                       // 보스 등장여부

    private static MultiDungeonManager instance;
    public static MultiDungeonManager Instance => instance;
    

    private void Awake()
    {
        if (instance != null && instance != this)
        {
            Destroy(gameObject);
            return;
        }

        instance = this;
        DontDestroyOnLoad(gameObject);
    }

    private void Start()
    {
        SpawnPlayer();
        SpawnMonster();
        Init();
    }

    private void Update()
    {
        if(currentMonsterCount == 0 && PhotonNetwork.IsMasterClient && !bossSpawned)
        {
            SpawnBossMonster();
        }
    }

    // 플레이어 오브젝트 생성
    private void SpawnPlayer()
    {
        var localPlayerIndex = PhotonNetwork.LocalPlayer.ActorNumber - 1;                    // 플레이어 넘버
        var spawnPosition = playerSpawnPositions[localPlayerIndex];                          // 플레이어 위치 설정

        PhotonNetwork.Instantiate("Player/MultiPlayer", spawnPosition.position, spawnPosition.rotation); 
    }

    // 초기화
    private void Init()
    {
        // 데이터 리프레쉬
        GameManager.Instance.FindPlayerObject();
        GameManager.Instance.FindCameraObject();
        DataManager.Instance.LoadPlayerData();
        EquipmentUI.Instance.LoadEquipmentSlotData();

        pd = GetComponent<PlayableDirector>();
        pd.played += OnCutSceneStarted;
        pd.stopped += OnCutSceneEnded;
    }

    // 몬스터 생성
    private void SpawnMonster()
    {
        // 마스터 클라이언트만 
        if (!PhotonNetwork.IsMasterClient) return;

        // 몬스터 소환
        for(int i = 0;i<monsterSpawnPositions.Length;i++)
        {
            PhotonNetwork.Instantiate("Monsters/TurtleShell_Multi",
                monsterSpawnPositions[i].position, monsterSpawnPositions[i].rotation);

            currentMonsterCount = i + 1;
        }
    }

    // 보스몬스터 생성
    private void SpawnBossMonster()
    {
        // 마스터 클라이언트만 
        if (!PhotonNetwork.IsMasterClient) return;

        bossSpawned = true;

        // 보스몬스터 소환
        boss = PhotonNetwork.Instantiate("Monsters/Boss_Grunt_Multi", bossSpawnPosition.position, bossSpawnPosition.rotation);

        // 죽음 이벤트 등록
        boss.GetComponent<BossMonster>().OnBossDied += OnBossDied;

        // 컷씬 플레이
        photonView.RPC(nameof(PlayCutScene), RpcTarget.All);
    }

    // 보스 죽음 이벤트
    private void OnBossDied()
    {

    }

    // 던전 클리어
    private IEnumerator DungeonClear()
    {
        yield return null;
    }

    [PunRPC]
    public void PlayCutScene()
    {
        cutSceneObj.gameObject.SetActive(false);
        pd.Play(timelineAsset[0]);
    }

    // 컷씬 시작
    public void OnCutSceneStarted(PlayableDirector director)
    {
        GameManager.Instance.player.isCutscenePlaying = true;

        GameManager.Instance.player.transform.position = playerSpawnPositions[PhotonNetwork.LocalPlayer.ActorNumber - 1].position;
        GameManager.Instance.player.transform.LookAt(bossSpawnPosition);
    }

    // 컷씬 끝
    public void OnCutSceneEnded(PlayableDirector director)
    {
        GameManager.Instance.player.isCutscenePlaying = false;
    }
}

댓글남기기