게임 리팩토링 - 문 오브젝트 + 가구 상호작용 개선

찡완이·2023년 10월 15일
1

서론

  • 방을 넘어갈 수 있는 문 기능을 다룬 내용입니다.
  • 문 기능을 추가하면서 현 상호작용 기능의 허점을 발견, 이를 개선하였습니다.

1. 문

1.1. 기존 시스템

  • 문 상호작용 범위를 나타내는 DoorCollider를 부모로, 실제 문 오브젝트를 Door로 자식으로 설정.

    +) 프리팹 설정도 하지 않은 모습

  • DoorCollider에 DoorManager.cs를 추가, DoorCollider의 범위에서 플레이어가 상호작용을 실행하면 Door을 비활성화시킨 후 Update()에서 시간을 측정, 2초 후에 다시 활성화시키는 방식.

    • 기존 소스코드
// DoorManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DoorManager : MonoBehaviour
{
    public GameObject Door;
    public GameObject Player;
    public float time = 0f;
    public bool isOpen;
    public GameObject Ghost;

    void Start()
    {
        Ghost = GameObject.Find("Ghost_Mother");
        Door = transform.GetChild(0).gameObject;
        Player = GameObject.Find("Player_Body");
        isOpen = false;
    }

    void Update()
    {

        if (Vector2.Distance(Ghost.transform.position, Door.transform.position) < 2f) // 적과의 상호작용 부분(자동으로 문이 열리게 설정)
            isOpen = true;
        if (time >= 2) {
            time = 0f;
            isOpen = false;
        }

        if (!isOpen)
            Door.SetActive(true);
        else if (isOpen)
        {
            time += Time.deltaTime;
            Door.SetActive(false);
        }
    }
    void OnTriggerStay2D(Collider2D col)
    {
        if (col.gameObject.tag == "Player" && Input.GetKey(KeyCode.Space)) // 플레이어와의 상호작용
        {
            isOpen = true;
            time = 0f;
            Mother_Move.D = true;
            Mother_Move.Door = Door;
        }

        if (col.gameObject.tag == "Ghost")
            Mother_Move.D = false;
    }
}

1.2. 수정 방향

  • 문 오브젝트 또한 자주 쓰이는 오브젝트기에 프리팹으로 만들 필요가 있음.
  • 다른 상호작용 오브젝트와 작동방식이 유사하기에 상호작용 오브젝트로 통합하면 좋을 것 같음.
  • 문이 열린 후 2초 쯤 뒤에 자동으로 닫히도록 코루틴을 사용하고자 함.(기존 방식은 Update에서 시간을 체크했기에 비효율적.)

1.2.1. 문제점

  • 상호작용 오브젝트의 기능 부분을 맡는 스크립트는 오브젝트 자체에 존재.
    -> 오브젝트를 비활성화시키면 상호작용 기능또한 비활성화됨.
    -> 이를 해결하기 위해 실제 기능을 담은 스크립트를 따로 만들어두기로 함.(한 19선배님의 조언을 적극 수용했음)

1.3. 해결 과정

  1. 문 오브젝트를 스프라이트에서 가져와 생성, 콜라이더와 상호작용 오브젝트 설정(태그 설정, Type 설정)을 해준다.

    * Type의 경우, InteractiveObject의 Enum 부분에 Door을 추가해주었다.

  • 문은 두 종류로 만들어 각각 콜라이더만 다르게 설정해주었음.
  1. 상호작용 시스템의 실제 기능을 담는 InteractionManager.cs를 생성, 오브젝트를 따로 만들어 스크립트를 추가한다.

    -> GameManager에서 가져올 예정.

  2. GameManager에서 가져와 사용하기 위해 GameManager에 public로 관련 변수를 생성, 추가한다.

public InteractionManager interManager; // Inspector에서 받음.


4. 문의 기능을 함수로 구현, InteractionManager에 작성한다.

//InteractionManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InteractionManager : MonoBehaviour // 상호작용 기능 함수들을 담고 있는 매니저
{

    public void Open_Door(GameObject door) // InteractiveObject.cs에서 호출.
    {
        door.SetActive(false); // 문 오브젝트 비활성화
        StartCoroutine(Close_Door(door)); 
    }

    IEnumerator Close_Door(GameObject door) // 2초 뒤에 문 오브젝트 활성화, 코루틴.
    {
        yield return new WaitForSeconds(2);
        door.SetActive(true);
    }
}
  1. Open_Door을 InteractiveObject.cs에서 받아오도록 코드를 추가한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InteractiveObject : MonoBehaviour // 상호작용 호출이 들어오면 자신의 태그에 맞는 함수를 호출
{
    public enum ObjTypes { Closet, Drawer, Safe, Door}
    public ObjTypes type;

    public void Interaction()
    {
        switch(type)
        {
            case ObjTypes.Closet:
                Debug.Log("옷장 상호작용");
                break;
            case ObjTypes.Drawer:
                Debug.Log("서랍 상호작용");
                break;
            case ObjTypes.Safe:
                Debug.Log("금고 상호작용");
                break;
            case ObjTypes.Door: // GameManager를 통해 문 기능 함수 호출, 현재 오브젝트를 매개변수로 함.
                Debug.Log("문 상호작용");
                GameManager.instance.interManager.Open_Door(this.gameObject);
                break;
        }

    }
}

1.4. 게임 내 모습

  • 문 상호작용 기능이 잘 작동하는 모습.
profile
코딩공부합니다

0개의 댓글