ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [TIL] Interface 상속과 Json에 관하여
    TIL 2024. 5. 17. 22:02

    Interface

    인터페이스란?

    클래스와 비슷하게 메서드, 속성, 이벤트 등을 갖지만 인터페이스는 이를 직접 구현하지 않고 단지 정의만 갖는다.

    클래스와 다르게 다중 상속이 가능하며, 인터페이스를 상속받은 클래스는 해당 인터페이스의 모든 멤버에 대한 구현을 설정해야 한다.

     

    예전 글에도 몇 번 언급했던 기능이다.

    이론만 알고  직접 써보지 못했었는데 이번에 팀 프로젝트를 하면서 충돌 처리를 인터페이스로 구현해보자는 말이 나왔고 

    그에 따라서 Interface를 복습해보고 적용해봤다.

     

    using UnityEngine;
    
    public class Item : MonoBehaviour
    {
        protected virtual void ItemEffect(GameObject ball)
        {
            Debug.Log("아이템 효과 발동");
        }
        protected void ItemDestroy()
        {
            Destroy(this.gameObject);
        }
        private void OnTriggerEnter2D(Collision2D collision)
        {
            ItemEffect(collision.gameObject);
        }
    
    }

    이 코드는 원래 사용 했던 Item 클래스이다. 

    사실 이 코드를 적용한다는 가정을하면 내가 만들려는 게임(벽돌 깨기)에서 볼이아닌 다른 오브젝트와 충돌하게 되어도 아이템 효과가 실행될 수 있을 것 같다는 생각이 들었다

     

    그렇다면 충돌한 오브젝트의 tag를 구분하거나 이름을 비교하여 어떤 오브젝트와 충돌했는지 구분해야 하는데.

    지금은 그렇다 쳐도 나중에 구분해야하는 오브젝트가 많아질수록 if else나 switch 문을 길게 작성해야 한다.

     

    그러나 인터페이스에 충돌을 선언하면 인터페이스를 상속한 다른 오브젝트들이 인식이되서 충돌한 함수를 호출하게 된다.

    (사실 이렇게 설명하는게 맞는지 모르겠다.)

    인터페이스를 상속받아서 설계한 클래스 구조이다. Icollidable은 아이템이 상속받는다.

    using UnityEngine;
    public interface Icollidable //Iterface를 선언할 때 I대문자 붙이기
    {
        public void OnCollide(GameObject Ball);
    }

    선언한 인터페이스다. 

    내부에 함수를 선언만 해주고 실질적인 작동은 작성해 주지 않는다.

     

    겪은 문제

    더보기

    위에 올린 인터페이스는 팀원분께 몇 가지 여쭤본 후 수정한 인터페이스로 

    내가 처음에 또 다른 팀원분께 받은 Interface 스크립트는 이것이였다.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public interface Icollidable
    {
        void OnCollisionEnter2D(GameObject Ball) { }
    }

     

    이 Interface를 사용하려다가 문제점이 발생했다.

     

    1. OnCollisionEnter2D

    이 함수는 유니티의 내장 함수이다. 충돌을 감지하는 함수로 Collider가 붙어있다면 자동으로 감지 해준다.

    그런데 이렇게 유니티 내장함수와 이름이 겹쳐도. 별 다른 에러가 뜨지 않았다.

     

    내 생각에는 매개 변수가 달라서 다른 함수로 구분하는 것 같지만

    이름이 유사하면 다른 팀원들도 헷갈리기 때문에 수정하기로 결정했다.

     

    2. 접근 지정자

    함수를 선언할 때 Public이 아니면 상속을 받아도 상속받은 클래스에서 정의할 수 없다.

    상속받는다는 개념 때문에 Protected는 될 줄 알았지만 안된다.

    인터페이스에 Public으로 선언하고 상속받은 함수를 구현할 때도 Public으로 해줘야 한다.

     

    3. 인터페이스에 선언한 함수 옆 {} (소괄호)

    왜인지 모르지만... 선언한 함수 옆에 {}를 붙여둔 경우

    인터페이스를 상속받은 클래스는 무조건 함수를 정의해야함에도 에러가 뜨지 않는다.

     

    이 내용 또한 팀원분께 물어봤다가 C# 8.0 부터는 디폴트 인터페이스 멤버가 생겼다.

    따라서 인터페이스 내에서도 구현을 할 수 있고, 이렇게 구현된 함수는 상속받은 멤버가 꼭 정의할 필요가 없는것 같았다.

     

    https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods

     

    Default interface methods - C# feature specifications

    This feature specification describe the syntax updates necessary to support default interface methods. This includes declaring bodies in interface declarations, and supporting modifiers on declarations.

    learn.microsoft.com

     

    //Ball.cs
    .
    .
    . 생략
    
    private void OnCollisionEnter2D(Collision2D other)
        {
            var nall = other.gameObject.GetComponent<Icollidable>();
            if (nall != null)
            {
                nall.OnCollisionEnter2D(this.gameObject);
            }
            var speed = lastVelocity.magnitude;
            var dir = Vector2.Reflect(lastVelocity.normalized, other.contacts[0].normal);
            rb.velocity = dir * Mathf.Max(speed, 0f);
        }

    만약 공이 충돌한 오브젝트가 Interface를 상속받았다면 그 상속받아 정의한 함수를 자동으로 실행 시켜준다.

    //Item.cs
    using UnityEngine;
    
    public class Item : MonoBehaviour, Icollidable
    {
        protected virtual void ItemEffect(GameObject ball)
        {
            Debug.Log("아이템 효과 발동");
        }
        protected void ItemDestroy()
        {
            Destroy(this.gameObject);
        }
        
        public void OnCollide(GameObject ball)
        {
            ItemEffect(ball);
        }
    
    }

    내가 작성한 Item 스크리트는 Interface를 상속 받았기때문에

    공과 충돌하게 되면 자동으로 OnCollide가 실행되며 아이템 효과가 발동하게 된다.

     

    참고로 Item을 상속받은 자식 클래스들은 따로 선언해 주지 않아도 부모가 정의한 인터페이스 함수를 받아오게 된다.

    지금은 내가 아이템만 담당했지만, 충돌체의 구분과 호출은 블록도 처리를 받고. 블록은 블록만의 효과가 발생할 것이다(사라진다던가, 데미지를 입는다던가)

     

    Json

    데이터를 저장할 때 주로 Json을 쓴다. 

    Unity에서도 저장하는 기능인 PlayePrefs가 있지만. 팀원분의 말씀으로는 PlayerPrefs는 보안상 문제가 있기 때문에 주로 간단한 사용자 정의(예를 들어 음량 조절?) 같은 거를 저장할 때만 쓴다고 했다.

     

    지금 작업하는 팀 프로젝트에도 Json은 활용하여 저장과 불러오기를 활용하고 그러다가 다른 팀원분이 Json에 대해 질문하시다가  Json 파일을 사용할 수 있는 라이브러리가 여러가지라는 것을 알게되었고

    감사하게도 또 팀원분이 이런 라이브러리의 특징과 성능을 적은 논문지를 공유해 주셔서 정리해봤다..

     

     

    Unity에서 게임 데이터 리와 관리를 위해 주로 사용되고 있는 JSON 라이브러리

    JsonUtility

    다른 라이브러리에 비하여 빠른 성능을 보였다.

    그러나 기본적인 데이터 타입만 지원하기 때문에 배열을 바로 사용할 수 없어 Json객체를 감싸는 Wrapper클래스를 따로 만들어야하고, Dictionary는 지원하지 않는다는 한계가 있다.

     

    LitJson

    JsonUtility와 마찬가지로 가볍게 사용할 수 있지만, 무조건 Public 변수를 사용해야한다.

     

    Newtonsoft.Json

    C#에서 사용할 수 있는 기술인 LINQ를 지원하기 때문에 배열, 컬렉션 등 원하는 데이터만 가져오고 싶은 경우 편리하게 사용할 수 있고 많은 기능을 제공한다.

     

    직렬화 역직렬화 속도

    JsonUtility >> Newtonsoft.Json > LitJson

     

    결론

    직렬화, 역 직렬화의 속도가 중요할 때 : JsonUtility

    기본저긴 데이터 타입 외에 가볍게 추가 기능이 필요 : LitJson

    더 많은 기능이 필요할 때 : Newtonsoft.Json

     

    내가 직접 사용해본 적은 없지만 나중에 사용할 일이 있으면 참고하려고 정리 해봤다.

    정보를 찾아준 팀원분께 감사를....

    'TIL' 카테고리의 다른 글

    [TIL] VS Code / VisualStudio  (0) 2024.05.21
    [TIL] DOTween 사용  (0) 2024.05.20
    [TIL] 객체지향 코드 설계 1  (0) 2024.05.16
    [TIL] 유니티 개인과제 2  (0) 2024.05.14
    [TIL] 유니티로 개인과제 1  (0) 2024.05.13
Designed by Tistory.