ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Parring Sword #50 : [프로그래밍] 메뉴와 상호작용
    유니티 게임 개발/메인 프로젝트: Parrying Sowrd 2024. 1. 12. 06:17

     

    이번 게시글의 주제는 전투 불능 시의 메뉴와 일시 정지 시의 메뉴 제작입니다.

    저번에도 올렸던 것으로 기억하는 클래스 다이어그램입니다.

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class StageTrigger_Interaction : MonoBehaviour
    {
        protected PlayerMain playerMain;
        protected MenuManager menuManager;
        protected FadeFilter fadeFilter;
    
        protected virtual void Awake()
        {
            playerMain = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerMain>();
            menuManager = GameObject.Find("MenuManager").GetComponent<MenuManager>();
            fadeFilter = GameObject.Find("FadeFilter").GetComponent<FadeFilter>();
        }
    
        private void OnTriggerEnter2D(Collider2D collision)
        {
            if( collision.tag == "PlayerBody" )
            {
                playerMain.setInteraction(true);
                playerMain.interactingObject = this;
            }
        }
    
        private void OnTriggerExit2D(Collider2D collision)
        {
            if (collision.tag == "PlayerBody")
            {
                playerMain.setInteraction(false);
                playerMain.interactingObject = null;
            }
        }
    
        public virtual void buttonYes() { }
        public virtual void buttonNo() { }
        public virtual void buttonESC() { }
    
        public virtual void buttonRight() { }
        public virtual void buttonLeft() { }
        public virtual void buttonUp() { }
        public virtual void buttonDown() { }
    
        public void quitGame()
        {
    #if UNITY_EDITOR
            UnityEditor.EditorApplication.isPlaying = false;
    #else
            Application.Quit();
    #endif
        }
    
    }

     

    우선 상호작용 대상에게 부착되는 클래스들의 부모 클래스입니다.

    자식 클래스에서 많이 사용해서 넣어둔 게임 종료 메소드 말고는 일단 두가지 기능이 메인입니다.

     

    첫번째,

    플레이어와 마주치면 플레이어에게 자신의 정보 전달.

    두번째,

    버튼 입력에 매핑될 메소드들의 가상 메소드들

     

    상호작용 대상은 자신의 정보를 전달하고,

    해당 정보를 전달받은 클래스는 각 버튼 입력에 매핑되는 메소드에 접근할 수 있습니다.

     

    예를 들어,

    입력을 받아들이는 클래스에서 Z 를 입력받으면,

    플레이어가 가지고 있는 StageTrigger_Interaction의 하위 클래스가 가지고 있는

    buttonYes()의 내용을 실행시키도록 하는 것입니다.

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class MenuManager : MonoBehaviour
    {
        private PlayerMain playerMain;
        private StageTrigger_Interaction interactingObject;
    
        private void Awake()
        {
            playerCtrl = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>();
            playerMain = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerMain>();
            interactingObject = null;
        }
    
        private void Update()
        {
            interactingObject = playerMain.interactingObject;
            if (interactingObject == null) return;
    
            if( Input.GetKeyDown(KeyCode.Z) )
            {
                interactingObject.buttonYes();
            }
            else if( Input.GetKeyDown(KeyCode.X) )
            {
                interactingObject.buttonNo();
            }
            else if( Input.GetKeyDown(KeyCode.Escape) )
            {
                interactingObject.buttonESC();
            }
            else if (Input.GetKeyDown(KeyCode.RightArrow))
            {
                interactingObject.buttonRight();
            }
            else if (Input.GetKeyDown(KeyCode.LeftArrow))
            {
                interactingObject.buttonLeft();
            }
            else if (Input.GetKeyDown(KeyCode.DownArrow))
            {
                interactingObject.buttonDown();
            }
            else if (Input.GetKeyDown(KeyCode.UpArrow))
            {
                interactingObject.buttonUp();
            }
    
        }
    
        
    }

     

    위의 클래스가 입력을 받아주는 클래스입니다.

    인풋으로 받은 입력으로 현재 가지고 있는 상호작용 물체가 가진 세부 작동을 발동시킵니다.

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Menu_SelectionBoxDead : StageTrigger_Interaction
    {
        public GameObject[] btns;
        private int now = 0;
        private int btnLength;
        private Color orgButtonColor;
        private Transform pos;
        private PlayerController playerCtrl;
    
        private void Start()
        {
            btnLength = btns.Length;
            orgButtonColor = btns[0].GetComponent<SpriteRenderer>().color;
            updateButtonSelection();
            pos = GameObject.Find("Main Camera").transform;
            playerCtrl = GameObject.Find("Player").GetComponent<PlayerController>();
        }
    
        private void Update()
        {
            if (playerCtrl.hp > 0) return;
            transform.position = new Vector3(pos.position.x, pos.position.y, 0.0f);
        }
    
        public override void buttonYes()
        {
            if( now == 0 )
            {
                fadeFilter.fadeOut();
                Invoke("btn0", 1.0f);
            }
            else if( now == 1 )
            {
                fadeFilter.fadeOut();
                Invoke("btn1", 1.0f);
            }
            else if( now == 2 )
            {
                fadeFilter.fadeOut();
                Invoke("btn2", 1.0f);
            }
            else if( now == 3 )
            {
                btn3();
            }
        }
    
        public override void buttonUp()
        {
            now = now - 1 < 0 ? 3 : now - 1;
            updateButtonSelection();
        }
    
        public override void buttonDown()
        {
            now = (now + 1) % 4;
            updateButtonSelection();
        }
    
        private void btn0()
        {
            UnityEngine.SceneManagement.SceneManager.LoadScene("Forest1");
        }
    
        private void btn1()
        {
            UnityEngine.SceneManagement.SceneManager.LoadScene("WatingArea");
        }
    
        private void btn2()
        {
            UnityEngine.SceneManagement.SceneManager.LoadScene("MainMenu");
        }
    
        private void btn3()
        {
            quitGame();
        }
    
        private void updateButtonSelection()
        {
            for (int i = 0; i < btnLength; i++)
            {
                if (i != now)
                {
                    btns[i].GetComponent<SpriteRenderer>().color = new Color(0.5f, 0.5f, 0.5f, 0.3f);
                }
                else
                {
                    btns[i].GetComponent<SpriteRenderer>().color = orgButtonColor;
                }
            }
        }
    }

     

    이것은 세부 동작의 예시를 보이기 위한 자식 클래스입니다.

    버튼을 누르면 어떤 동작을 하는지 확실하게 정의되어 있습니다.

     

     

    정리하자면, 메뉴를 하나의 오브젝트로서 생각하고,

    필요한 대로 바꿔끼는 방식으로 다뤘다는 이야기입니다.

     

    디자인 패턴으로 말하면 스트라티지 패턴입니다.

     

    처음에 메뉴를 오브젝트로 쓸 생각을 안하고 코드를 작성한 바람에

    부모 클래스 이름에 StageTrigger라고 붙어버려 메뉴 오브젝트들과 조금 어울리지 않는게 마음에 들지는 않지만

    작동은 생각한 대로 잘 이루어져 다행입니다.

     

     

     

     

    실행하면 이렇게 작동합니다.

Designed by Tistory.