본문 바로가기

무제_LR

스테이지 생성(타일맵)

public class StageDataContainer : MonoBehaviour
{
  [SerializeField] private Transform leftPlayerBeginTransform;
  public Transform LeftPlayerBeginTransform => leftPlayerBeginTransform;

  [SerializeField] private Transform rightPlayerBeginTransform;
  public Transform RightPlayerBeginTransform => rightPlayerBeginTransform;

  [Space(5)]
  [SerializeField] private GameObject staticObstacle;
  public GameObject StaticObstacle => staticObstacle;

  [Space(5)]
  [SerializeField] private Transform triggerTileRoot;
  public List<TriggerTileViewBase> TriggerTiles=> triggerTileRoot.GetComponentsInChildren<TriggerTileViewBase>().ToList();

  [Space(5)]
  [SerializeField] private Transform dynamicObstacleRoot;
  public List<DynamicObstacleBase> DynamicObstacles => dynamicObstacleRoot.GetComponentsInChildren<DynamicObstacleBase>().ToList();
}

이전 게시물대로 타일맵을 프리팹화, 내부 플레이어 시작 위치랑 각종 데이터 보유 타일들을 컨테이너에 넣었습니다.

좌/우 플레이어 시작 포지션에는 기즈모 스크립트를 달아서 씬에서도 확인 가능하게 만들었는데 프리팹 상태라 안 보이네요.

public class LocalManager : MonoBehaviour
{
  public static LocalManager instance;

  private StageManager stageManager;
  public StageManager StageManager => stageManager;

  private void Awake()
  {
    instance = this;
    InitializeManagers();

    StageManager.CreateAsync().Forget();
  }

  private void Update()
  {
    if(Input.GetKeyDown(KeyCode.F1))
      StageManager.ReStartAsync().Forget();
  }

  private void InitializeManagers()
  {
    stageManager = new StageManager();
  }
}
  public async UniTask CreateAsync()
  //StageManager 중략
  {
    var stageDataContainer = await GlobalManager.instance.ResourceManager.CreateAssetAsync<StageDataContainer>("TestStage");

    SetupPlayers(stageDataContainer);
    SetupTriggers(stageDataContainer);
    SetupDynamicObstacles(stageDataContainer);
  }

  private void SetupPlayers(StageDataContainer stageData)
  {
    var leftPosition = stageData.LeftPlayerBeginTransform.position;
    var rightPosition = stageData.RightPlayerBeginTransform.position;
    playerSetupService.SetupAsync(new PlayerSetupService.SetupData(leftPosition,rightPosition)).Forget();
  }

  private void SetupTriggers(StageDataContainer stageData)
  {
    triggerTileSetupService.SetupAsync(new TriggerTileSetupService.SetupData(stageData.TriggerTiles)).Forget();
  }


  private void SetupDynamicObstacles(StageDataContainer stageData)
  {
    foreach (var dynamicObstalce in stageData.DynamicObstacles)
    {

    }
  }

싱글톤 매니저를 기존 전역 씬 싱글톤인 GameManager 명칭을 GlobalManager,
로컬 씬의 싱글톤 매니저인 LocalManager로 구분했습니다.

LocalManager는 씬 시작과 동시에 StageManager를 통해 스테이지를 생성합니다.

ResourceManager에서 위 스크린샷에 나온 TestStage 오브젝트를 생성하는 동시에 컴포넌트로 부착된 StageDataContainer를 가져오고
해당 클래스에서 각 플레이어 시작 위치, 트리거 및 동적 오브젝트 스크립트들을 셋업시킵니다.

그리고 PlayerSetupService.SetupAsync에 인자가 추가되었습니다.

public interface IStageObjectSetupService<T>
{
  public UniTask<List<T>> SetupAsync(object data);

  public void Release();
}
public class PlayerSetupService : IStageObjectSetupService<IPlayerPresenter>
{
  public class SetupData
  {
    public readonly Vector3 leftPosition;
    public readonly Vector3 rightPosition;
    public SetupData(Vector3 leftPosition, Vector3 rightPosition) 
    { 
      this.leftPosition = leftPosition; 
      this.rightPosition = rightPosition; 
    }
  }
  
    public async UniTask<List<IPlayerPresenter>> SetupAsync(object data)
  {
    var setupData = data as SetupData;
    leftPlayer = await CreateLeftPlayer(setupData.leftPosition);
    rightPlayer = await CreateRighPlayer(setupData.rightPosition);

    return new List<IPlayerPresenter>() { leftPlayer, rightPlayer };
  }
  //중략
}

이전에 배운 기법인데 아무래도 가변적으로 인자 종류가 바뀌는 경우가 생길 것 같은 경우 인자를 object로 두고
상속받은 클래스 내부에 간단한 데이터 전달용 모델 클래스를 만든 뒤 박싱 언박싱을 거쳐 인자로 전달해주는 방식입니다.