게임 리팩토링 - 가구 상호작용

찡완이·2023년 10월 1일
0

서론

  • 가구와의 상호작용 구현에 관한 내용입니다.

1. 상호작용 가구

1.1. 기존 시스템

  • 가구 기능을 장롱(1가지)만 구현할 생각으로 코드를 작성(가장 큰 문제)
    • 추가적인 기능 추가에 제한이 있음.

      -> 추가적인 기능 구현을 생각하지 않고 스크립트 이름을 가구 이름으로 설정한 모습..

  • 상호작용 입력 코드, 상호작용 기능 코드를 구분해두지 않아 수정이 힘들고 난잡함.
    • 기존 소스코드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Wardrobe : MonoBehaviour
{
    public GameObject Ward; // 장롱 오브젝트
    public GameObject Player_Body;
    public GameObject Player_Light;
    public GameObject Player_Flash;
    public GameObject Ghost;

    public static float time = 0f;
    public static bool Hide = false;
    public static bool success = false;
    void Start()
    {
        Ward = this.gameObject;
        Player_Body = GameObject.Find("Player_Body");
        Player_Light = GameObject.Find("Player_Light");
        Ghost = GameObject.Find("Ghost_Mother");
    }

    void Update()
    {
     // 플레이어 상호작용 입력
        if(Vector2.Distance(Ward.transform.position , Player_Body.transform.position) < 2f && Input.GetKeyDown(KeyCode.Space)) {
            Hide = !Hide;
        }
        // 상호작용 기능 구현
        if (Hide) {
            Active(false);
            Player_Flash.SetActive(false);
        } else {
            Active(true);
        }
        // 상호작용시 가구 기능(장롱) 구현
        if(Hide && Vector2.Distance(Player_Body.transform.position, Ghost.transform.position) > 6f && Mother_Move.encounter) { // 숨기 성공
            success = true;
            Mother_Move.encounter = false;
        } else if(Mother_Move.encounter && Hide) { // 실패
            if(time > 3.1f)
                time = 0f;
        }

        if (success) {
            time += Time.deltaTime;

            if (!Hide && time < 30f) {
                Mother_Move.encounter = true;
                success = false;
            } else if (Hide && time > 30f) {
                success = false;
            }
        }
        if (!success && Hide) {
            time += Time.deltaTime;
            if(time > 3f)
                SceneManager.LoadScene("Gameover");
        }
    }

    void Active(bool b) {
        Player_Body.SetActive(b);
        Player_Light.SetActive(b);
    }
}

1.2. 수정 방향

  • 기존 코드는 기능 추가에 한계가 있고 너무 복잡하기에 코드를 아예 새로 짜야함.
  • 기능 구현이 용이하도록 유연하게 구성해야함.
  • 되도록 최소한으로 스크립트를 만들어 구현하고 싶었음.
  1. 플레이어와 가구간 상호작용
    BoxCollider를 통해 플레이어와 가구가 일정 거리 내에 있을 때 상호작용이 되도록 설정.
    -> 가구나 플레이어에 일정 범위를 가진 콜라이더 오브젝트를 추가할 필요가 있음.(약간 떨어져있어도 상호작용이 가능하도록)
    오브젝트가 다양한 가구보단 단일 개체인 플레이어에 이를 추가하는 것이 효율적이라고 판단.
  2. 스크립트 구성
    가구, 플레이어에 각각 스크립트를 추가하여 플레이어는 상호작용키 활성화, 상호작용 가능 오브젝트 판단을, 가구는 상호작용 기능 수행을 맡을 예정
  3. 가구별 기능 구별
    스크립트 사용을 최소화하려면 한 스크립트로 가구 기능을 다양화하여 구분할 필요가 있음.
    -> Enum을 사용하여 이를 구분하여 사용할 예정.

1.3. 해결 과정

  1. 상호작용 가구에 달 스크립트, 플레이어에 달 스크립트, GameManager을 생성한다.

    Interaction Controller, Interactive Object, GameManager 생성

  2. 프리팹에서 상호작용 가구들의 tag를 "Interactable"로 지정한다.

  3. 플레이어의 자식 오브젝트로 Interaction Range를 생성, Circle Collider2D를 컴포넌트로 추가하여 상호작용 범위를 설정한다.

    플레이어 주위를 둘러싼 초록 원이 상호작용 가능 범위를 나타냄.

  4. 스크립트를 작성한다.

  • Player 스크립트에 아래 스크립트를 추가하여 상호작용 키 입력을 구현.
private void Update()
    {
        if (Input.GetKey(KeyCode.Space)) // 물체 상호작용 키
            GameManager.instance.interCon.getSign(true);
        else
            GameManager.instance.interCon.getSign(false);
    }
  • Interactive Object에서 가구의 기능 구현(할 예정)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InteractiveObject : MonoBehaviour
{
    public enum ObjTypes { Closet, Drawer, Safe} // Enum을 사용하여 가구 구분
    public ObjTypes type; // 현재 가구 타입을 담는 변수

    private void Update()
    {
        
    }

    public void Interaction() // 플레이어가 상호작용시 호출할 함수
    {
        switch(type) // 각 기능은 switch문에서 구별
        {
            case ObjTypes.Closet:
                Debug.Log("옷장 상호작용");
                break;
            case ObjTypes.Drawer:
                Debug.Log("서랍 상호작용");
                break;
            case ObjTypes.Safe:
                Debug.Log("금고 상호작용");
                break;
        }
    }
}
  • Interaction Controller에서 주변 상호작용 가구 확인
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InteractionController : MonoBehaviour
{
    [SerializeField]GameObject InteractableObj = null; // 주변 상호작용 가능한 가구 오브젝트를 담는 객체
    [SerializeField] bool onInteraction = false; // 상호작용 키 활성화 여부

    private void Update()
    {
        if (onInteraction && InteractableObj) 
            InteractableObj.GetComponent<InteractiveObject>().Interaction(); // 상호작용 기능 호출
    }
    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Interactable") && !InteractableObj) // 상호작용 가구가 상호작용 범위에 들어오면
            InteractableObj = other.gameObject;
    }

    private void OnTriggerExit2D(Collider2D other)
    {
        if (InteractableObj && other.CompareTag(InteractableObj.tag)) // 상호작용 가구가 상호작용 범위에서 나가면
            InteractableObj = null;
    }

    public bool getOnInteraction()
    {
        return onInteraction;
    }
    public void getSign(bool b)
    {
        onInteraction = b;
    }
    public void changeSign()
    {
        onInteraction = !onInteraction;
    }
}
  • GameManager에서 Interaction Controller과 Player을 연결시켜줌.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameManager : MonoBehaviour
{
    public static GameManager instance;
    public InteractionController interCon;

    private void Awake()
    {
        if (!instance) // 싱글톤
            instance = this;
    }
}
  1. 만든 스크립트를 각 오브젝트에 추가한다.



    -> 프리팹에 스크립트를 추가할 때 각 가구에 맞는 Type으로 값을 설정해줌.

1.3.1 참고자료

1.4 게임 내 모습


  • 상호작용한 오브젝트에 따라 해당하는 기능이 호출되는 모습을 볼 수 있다.
  • 상호작용이 반복 호출되는 부분은 추후 해결할 예정.
profile
코딩공부합니다

0개의 댓글