본문 바로가기
스파르타 내배캠

스파르타 내배캠 Unity 3기 - 47

by LemongO 2024. 3. 12.

위잉~ 치킨(먹고싶다)

 

 

 


ModuleSystem(InGame Module 생성)

이전에 진행했던 심화주차 개인과제의 연장선인 ModuleSystem.

 

플레이어는 상체 / 하체로 구분되어있는 일명 파츠를 선택하여 플레이 가능하다.

 

 

완성이 되어야하는 구조는 위의 사진과 같지만 이번에 작업한 것은 InGame Scene에서 Module이 생성되는 것이다.

 

때문에 미리 만들어둔 Leg_01, Upper_01 프리팹을 이용해 Resources 폴더내의 파츠들의 정보를 끌어오고,

이를 생성하는 로직을 만들었다.

 

public class ModuleManager

 

전반적인 Module 로직을 담당해줄 ModuleManager.

 

현재 만들어진 기능을 순서대로 나열하면

  1. Resources 폴더 내 각 Part를 저장한다.
  2. (InGame Scene 진입) 모듈 선택창에서 저장된 Part들로 플레이용 Module 생성에 사용한다.
    (현재 1개뿐이라 하드코딩)
  3. 하체의 애니메이션에 의해 상체가 같이 움직여야하므로 하체 생성 시, 하체의 Pivot을 가져온다.
  4. 하체 Pivot에 상체를 장착시킨다.
// Think - 굳이 Key로 Type을 쓸 필요가 있을까?
private Dictionary<Type, BasePart[]> _modules = new Dictionary<Type, BasePart[]>();

public LowerPart CurrentLowerPart { get; private set; }
public UpperPart CurrentUpperPart { get; private set; }

public void Init() // 게임 시작 시 Resources 폴더 내 모든 파츠 담기.
{        
    BasePart[] lowerParts = Resources.LoadAll<LowerPart>("TestPrefab/Parts/Lower");
    BasePart[] upperParts = Resources.LoadAll<UpperPart>("TestPrefab/Parts/Upper");

    _modules.Add(typeof(LowerPart), lowerParts);
    _modules.Add(typeof(UpperPart), upperParts);
}

 

게임이 첫 시작이되면 Init 메서드를 호출 해 Resources 폴더의 각 부위의 Part를
BasePart 배열로 담고, Dictionary에 저장한다.

 

public void CreateEmptyModule() // PlayScene 진입 시 플레이어가 사용할 빈 모듈 생성 : Scene Script에서 처리하는게 맞다고 봄.
{
    GameObject emptyModule = Resources.Load<GameObject>("TestPrefab/Parts/Player_Module");

    UnityEngine.Object.Instantiate(emptyModule);
}

 

InGame Scene에 진입하면 CreateEmptyModule 메서드를 호출 해 PlayerFSM이 적용되어있는 빈 프리팹을 생성한다.

 

 

 

public void CreateModule(Transform createPosition, Module module) // Lower - Upper 순차적 생성 및 Pivot 할당.
{
    // Lower 생성 및 Upper Pivot 할당.
    CurrentLowerPart = CreateAndSetupPart<LowerPart>(createPosition);        
    Transform upperPivot = FindPivot(CurrentLowerPart.transform);
    module.SetPivot(upperPivot);

    // Upper 생성 및 Weapon Pivot 할당.
    CurrentUpperPart = CreateAndSetupPart<UpperPart>(upperPivot);
    Transform weaponPivot = FindPivot(CurrentUpperPart.transform);
    module.SetPivot(weaponPivot);
}

 

그 후, CreateModule 메서드를 호출해 생성위치(부모 오브젝트)를 정하고

LowerPart를 먼저 생성한다.

 

private T CreateAndSetupPart<T>(Transform createPosition , int index = 0) where T : BasePart
{
    BasePart[] parts;
    if (_modules.TryGetValue(typeof(T), out parts) == false)
    {
        Debug.Log("Upper 파츠 정보가 없습니다.");
        return null;
    }        

    GameObject go = UnityEngine.Object.Instantiate(parts[index].gameObject, createPosition);
    T part = go.GetComponent<T>();
    part.Setup();

    return part;
}

 

LowerPart를 생성 시, Part 자체에 있는 Setup 메서드를 호출하여 Setup 시킨 뒤, 만들어진 part를 반환한다.
(현재까진 Setup시킬 내용이 없지만 일단 해둔상태)

 

 

 

여기까지하면 위 사진과 같은 상황이 된다.

 

private Transform FindPivot(Transform part)
{
    Pivot pivot = part.GetComponentInChildren<Pivot>();
    if(pivot == null)
    {
        Debug.Log($"Pivot이 존재하지 않습니다. : {part.name}");
        return null;
    }

    return pivot.transform;
}

 

그 다음 FindPivot 메서드를 호출해 Pivot을 찾고
(이 때 Pivot Object에 이름표 역할의 빈 클래스 Pivot을 컴포넌트로 넣어뒀다.)

 

 

public void CreateModule(Transform createPosition, Module module) // Lower - Upper 순차적 생성 및 Pivot 할당.
{
    // Lower 생성 및 Upper Pivot 할당.
    CurrentLowerPart = CreateAndSetupPart<LowerPart>(createPosition);        
    Transform upperPivot = FindPivot(CurrentLowerPart.transform);
    module.SetPivot(upperPivot);

    // Upper 생성 및 Weapon Pivot 할당.
    CurrentUpperPart = CreateAndSetupPart<UpperPart>(upperPivot);
    Transform weaponPivot = FindPivot(CurrentUpperPart.transform);
    module.SetPivot(weaponPivot);
}

 

찾은 Pivot위치에 UpperPart를 생성한다.