Preview를 우클릭 했을 때, 취소하는 코드를 추가했다.

private void Update()
{
    if (Input.GetButtonDown("Fire1"))
    {
        Build();
    }
    if (Input.GetButtonDown("Fire2"))
    {
        Cancle();
    }
}

private void Build()
{
    if (isPreviewActivated)
    {
        if (isPreviewActivated)
        {
            Debug.Log("Create");
            Instantiate(varBuildCraft, varPreviewCraft.transform.position, Quaternion.identity);
            Destroy(varPreviewCraft);
            isPreviewActivated = false;
            craftingWindow.SetActive(false);
            varPreviewCraft = null;
            varBuildCraft = null;
            PlayerController.instance.ToggleCursor(false);
        }
    }

}

private void Cancle()
{
    if (isPreviewActivated)
    {
        Destroy(varPreviewCraft);
    }
    isPreviewActivated = false;
    varPreviewCraft = null;
    varBuildCraft = null;

}

 

그리고 구조물을 클릭 했을 때 정보를 불러오며, 제작을 눌렀을 때 해당 버튼의 구조물을 불러온다.

public class CraftTab
{
    public CraftData craft;
}

public class CraftingTable : MonoBehaviour
{
    public GameObject craftingWindow;

    private PlayerController controller;

    [Header("Events")]
    public UnityEvent onOpenCraftingWindow;
    public UnityEvent onCloseCraftingWindow;

    public static CraftingTable instance;

    private void Awake()
    {
        instance = this;
        controller = GetComponent<PlayerController>();
    }

    private void Start()
    {
        
        craftingWindow = GameManager.Instance._UI.transform.Find("Crafting/CraftingCanvas").gameObject;
        craftingWindow.SetActive(false);
    }

    public void OnCraftingTableButton(InputAction.CallbackContext callbackContext)
    {
        if (callbackContext.phase == InputActionPhase.Started)
        {
            Toggle();
        }
    }

    public void Toggle()
    {
        if (craftingWindow.activeInHierarchy)
        {
            craftingWindow.SetActive(false);
            controller.ToggleCursor(false);
            onCloseCraftingWindow?.Invoke();
        }
        else
        {
            craftingWindow.SetActive(true);
            controller.ToggleCursor(true);
            onOpenCraftingWindow?.Invoke();
        }
    }

    public bool IsOpen()
    {
        return craftingWindow.activeInHierarchy;
    }
}
public class CraftTabUI : MonoBehaviour
{
    public Button button;
    public Image icon;
    private Outline outline;
    private CraftTab curTab;
    public int thisIcon;
    [SerializeField]private CraftBuild craftBuild;
    public TMP_Text selectedcraftname;
    public TMP_Text selectedcraftdescription;
    public TMP_Text selectedcraftingrediants;

    public bool equipped;

    public GameObject craftInforPanel;

    private void Awake()
    {
        outline = GetComponent<Outline>();
    }

    private void Start()
    {
        craftInforPanel.SetActive(false);
    }

    private void OnEnable()
    {
        outline.enabled = equipped;
    }

    public void Set(CraftTab tab)
    {
        curTab = tab;
        icon.gameObject.SetActive(true);
        icon.sprite = tab.craft.icon;

        if (outline != null)
        {
            outline.enabled = equipped;
        }
    }

    public void Clear()
    {
        curTab = null;
        icon.gameObject.SetActive(false);
    }

    public void OnButtonClick()
    {
        if (craftInforPanel.activeInHierarchy)
        {
            craftInforPanel.SetActive(false);
        }
        else
        {
            craftInforPanel.SetActive(true);
        }

        craftBuild.craftNum = thisIcon;
        selectedcraftname.text = craftBuild.crafts[thisIcon].craft.craftName;
        selectedcraftdescription.text = craftBuild.crafts[thisIcon].craft.description;
        selectedcraftingrediants.text = craftBuild.crafts[thisIcon].craft.ingrediants;

    }
}

 

 

유니티에서 연결이 헷갈리고 구조물과 상호작용을 구현하지 못해서 아쉽다. 다들 똑같은 시간에 개발했기 때문에 시간이 부족하다는건 핑계이고 코드 설계하는데 시간이 오래 걸리는걸 보면 공부량이 부족한게 맞다. 연휴에 강의 좀 재수강해야겠다.

이전에 공부했던 3D Suvival 게임을 기반으로 기능을 추가하여 만들기로 했다.

내가 맡은 부분은 건축으로, 여러 가지 구조물과 아이템을 제작하는 부분을 맡았다.

 

제작창

Input System으로 캐릭터 컨트롤러 스크립트를 불러와서 R키를 누르면 제작창이 키고 꺼지도록 하였다. 

public GameObject craftingWindow;

private PlayerController controller;

private void Awake()
{
    controller = GetComponent<PlayerController>();
}

private void Start()
{
    craftingWindow.SetActive(false);
}

public void OnCraftingTableButton(InputAction.CallbackContext callbackContext)
{
    if (callbackContext.phase == InputActionPhase.Started)
    {
        Toggle();
    }
}

public void Toggle()
{
    if (craftingWindow.activeInHierarchy)
    {
        craftingWindow.SetActive(false);
        controller.ToggleCursor(false);
    }
    else
    {
        craftingWindow.SetActive(true);
        controller.ToggleCursor(true);
    }
}

public bool IsOpen()
{
    return craftingWindow.activeInHierarchy;
}

 

제작창에서 제작할 구조물이나 아이템을 클릭하면 설명과 함께 제작 버튼이 활성화 된다.

private Button craftTabSelectBtn;
[SerializeField] private GameObject craftInforPanel;

private void Start()
{
    craftInforPanel.SetActive(false);
    craftTabSelectBtn = GetComponent<Button>();
    craftTabSelectBtn?.onClick.AddListener(() => OpenPanel());
}

public void OpenPanel()
{
    craftInforPanel.SetActive(true);
}

 

 

구조물 및 건물 건축

제작버튼을 누르면 제작창이 닫히고 미리보기 프리팹이 보이면서 플레이어를 따라가고, 좌클릭하면 프리팹이 사라지고 실제 구조물이 설치된다.

여러 개를 제작할 수 있도록 배열로 구조물들을 저장한다.

[System.Serializable]
public class Craft
{
    public string craftName;
    public GameObject buildCraft; // 실제 설치되는 구조물
    public GameObject previewCraft; // 설치 미리보기
}

public class CraftBuild : MonoBehaviour
{
    private bool isPreviewActivated = false;

    [SerializeField] private Craft[] craftCampfire;
    private GameObject varPreviewCraft; // 미리보기 변수
    private GameObject varBuildCraft; // 실제 설치되는 구조물 변수

    [SerializeField] private Transform playerPosition;
    private RaycastHit hitInfor;
    [SerializeField] private LayerMask layerMask;
    [SerializeField] private float range;

    [SerializeField] private GameObject craftingWindow;

    private void Update()
    {
        if (Input.GetButtonDown("Fire1"))
        {
            Build();
        }
    }

    private void Build()
    {
        if (isPreviewActivated)
        {
            Debug.Log("Create");
            Instantiate(varBuildCraft, varPreviewCraft.transform.position, Quaternion.identity);
            Destroy(varPreviewCraft);
            isPreviewActivated = false;
            craftingWindow.SetActive(false);
            varPreviewCraft = null;
            varBuildCraft = null;
        }
    }

    public void CreateBtnClick(int craftNum)
    {        
        varPreviewCraft = Instantiate(craftCampfire[craftNum].previewCraft, playerPosition.position + playerPosition.forward, Quaternion.identity);
        varPreviewCraft.transform.parent = playerPosition;
        varBuildCraft = craftCampfire[craftNum].buildCraft;
        isPreviewActivated = true;
        craftingWindow.SetActive(false);
        PlayerController.instance.ToggleCursor(false);
    }
}

 

 

다른 구조물도 추가할 예정인데 코드가 효율적이진 않은 것 같다. 실전과 이론을 함께 병행하며 좀 더 고민해보면 좋을 것 같은데 시간에 대한 아쉬움이 많고 이해력도 좋지 못해서 생각이 오래 걸려서 아쉽다. 구현하고 싶은 건 정말 많은데 어떤 식으로 방향을 잡아야할지 막막하다. 금방 뚝딱 만들 수 있는 경지까진 바라지 않아도 어떻게 구현할지 감을 잡을 수 있으면 좋겠다.

팀 프로젝트 발표를 마치며 프로젝트가 마무리 됐다.

필수 구현은 모두 했기 때문에 뿌듯하면서도 시간 부족으로 버그를 잡지 못하고 싱글톤으로 하나의 스크립트로 데이터를 관리하며 다른 곳에서 사용하도록 하지 못해서 단위 테스트가 어려웠으며 전체적으로 객체지향적인 프로그래밍이 아니었다는 점이 아쉬웠다.

비둘기가 날 때 날게 하긴 했는데 날개로 나는게 아니라 머리로 날게 만들었다는 비유가 딱 맞는 것 같다.

다음에 팀프로젝트를 진행할 때, GameManager 부분을 맡으면 전체적으로 자신이 맡은 코드 뿐만 아니라 다른 분들의 코드까지 이해하고(물론 다른 역할을 맡았을 때도 중요하지만) 전체적인 구조를 파악해야하기 때문에 공부하기에 좋을 것 같다.

최종적으로 프로젝트를 합치는 과정에 게임 완성도를 높이기 위해 추가구현으로 메인 화면에 Animation을 넣고 메인화면씬과 게임플레이 씬에 Audio를 추가했다.

 

그리고 발표를 맡게 되어 코드에 대해 전체적인 이해를 위해 다른 분들의 코드를 공부했다. 

ppt를 만들고 대본을 쓰는 중인데 완성이 늦어 리허설을 못해서 걱정이 많이 된다.

일단 대본을 완성하고 내일 오전에 팀원분들과 잠깐이라도 리허설을 해봐야겠다.

 

이번 프로젝트를 하며 사람 간의 협업과 의사소통에 대한 많은 생각을 하게 되었고 실력에 대한 고민도 많이 들었다. 이론을 이해했다고 착각한 상태로 혼자 응용해보려니까 힘들었다. 내가 맞게 공부하고 있는지, 어느 것을 모르는 상태인지 확실히 알고 공부 방법에 대해서도 다시 생각해보아야겠다.

+ Recent posts