반응형

 

 

 

 

에러 현상

- 스킨정보가 있는 SkeletonDataAsset을 교체한 뒤, 스킨 설정 방법에 따라 Material 정보가 없어지는 현상이 있다.

- Skeleton 정보는 정상적으로 적용되고 텍스쳐만 없는 상태로 보여진다.

- 해당 현상은 SkeletonAnimation 컴포넌트에서만 일어나며, SkeletonGraphic 컴포넌트에서는 이상이 없다.

 

 

 

코드

using Spine.Unity;

SkeletonAnimationClass.skeletonDataAsset = SomeSkeletonDataAsset;
SkeletonAnimationClass.Initialize(true);

//필드 값을 변경하면 MeshRenderer의 Material이 로드되지 않음.
SkeletonAnimationClass.initialSkinName = "skin name";
//SetSkin(str) 함수로 스킨을 변경하면 Material이 정상적으로 로드 됨.
SkeletonAnimationClass.skeleton.SetSkin("skin name";);
  • SkeletonGraphic 컴포넌트는 InitialSkinName 필드값을 변경해도 정상적으로 작동한다.

 

 

 

 

 

반응형
반응형

 

 

 

 

FindObjectsOfType<T>()

- 해당 함수로 구해지는 배열 원소들은 하이어라키 배치대로 순서가 보장되지 않는다.

- 즉, 다음과 같이 보여진다.

 

 

 

 

해결 방법

- 위 문제를 해결하기위해서는 2가지 방법이 있다.

  1. 인스펙터에서 직접 드래그 앤 드롭 해준다.

  2. FindObjectsOfType<T>로 배열을 구한 뒤, 정렬을 한다.

- 1번과 같은 경우는 노가다가 심해진다. 따라서, 코드로 정렬을 해주는 방법을 취한다.

- 이 때, 배열의 정렬은 transform.GetSiblingIndex() 값을 비교해서 정렬을 해주면 된다.

- SiblingIndex 값은 하이어라키에 배치된 순서의 값을 반환해준다.

 

 

 

코드

using System;
using UnityEngine;

SomeClass[] arr = FindObjectsOfType<SomeClass>();
Array.Sort(arr, (a, b) =>
{
    return a.transform.GetSiblingIndex().CompareTo(b.transform.GetSiblingIndex());
});
  • 위 코드는 오름차순으로 정렬되기 때문에 내림차순으로 정렬하고 싶으면 return 라인에 a와 b의 위치를 변경하면 된다.

 

 

 

결과

 

 

 

 

 

반응형
반응형

 

 

 

 

제네릭 싱글톤(Generic singleton)

- 싱글톤 : 객체의 인스턴스가 오직 하나인 디자인 패턴

- Generic class : 데이터 형식을 일반화한 클래스를 말한다.

 

 

코드

using UnityEngine;

public abstract class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
    [SerializeField]
    private bool dontDestroy = true;
    private static T instance = null;
    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                instance = InitManager<T>();
            }
            return instance;
        }
    }

    protected static U InitManager<U>() where U : MonoBehaviour
    {
        GameObject go = null;
        U obj = FindObjectOfType<U>();
        if (obj == null)
        {
            go = new GameObject(typeof(U).Name);
            go.AddComponent<U>();
        }
        else
        {
            go = obj.gameObject;
        }

        DontDestroyOnLoad(go);
        return go.GetComponent<U>();
    }

    private void Awake()
    {
        if (instance == null)
        {
            if (dontDestroy)
            {
                Instance.Init();
            }
            else
            {
                instance = GetComponent<T>();
                Init();
            }
        }
        else
        {
            Destroy(gameObject);
        }
    }

    protected abstract void Init();
}
  • DontDestroyOnLoad를 사용하지 않으려면 인스펙터 창에서 해당 bool값을 false로 변경해준다.
  • Init 함수를 추상 함수로 지정해서 싱글톤으로 지정할 클래스의 초기화를 Init에서 하도록 유도한다.

 

 

 

 

반응형
반응형

 

 

 

 

JsonUtility

- 유니티에서 제공하는 JSON 클래스이다.

- 다른 JSON 라이브러리에 비해 기능이 적지만 성능이 좋다.

- 직렬화된 클래스, 구조체만 지원되고 배열, 리스트, 딕셔너리 등의 자료구조는 클래스로 래핑해야 JSON 변환이 가능하다.

 

 

 

직렬화(Serializable)

- C#은 복합 데이터 형식을 쉽게 스트림에 읽기/쓰기를 할 수 있게 하는 직렬화라는 메커니즘을 제공한다.

- 직렬화는 객체의 상태(필드에 저장된 값들)를 메모리에 저장 장치에 저장이 가능한 0과 1의 순서로 바꾸는것을 말한다.

- 직렬화는 원하는 데이터 위에 [Serializable] 어트리뷰트를 작성해주면 된다.

 

 

 

using System;
using UnityEngine;

public struct SomeStruct
{
    [SerializeField]
    private int m_iNum;
    [SerializeField]
    private bool m_bCheck;
    
    public SomeStruct(int i, bool b)
    {
        m_iNum = i;
        m_bCheck = b;
    }
}

//ToJson
SomeStruct ss = new SomeStruct(10, false);
string json = JsonUtility.ToJson(ss, true);

//FromJson
SomeStruct ss2 = JsonUtility.FromJson<SomeStruct>(json);
  • JSON으로 변환 할 클래스나 구조체를 반드시 직렬화 어트리뷰트를 작성해줄 필요는 없지만, 해당 클래스나 구조체가 다른 클래스의 멤버가 되면 반드시 직렬화 어트리뷰트를 작성해줘야한다.
  • 멤버 변수의 접근 지시자를 private로 할 경우 [SerializeField] 어트리뷰트를 붙여줘야 해당 데이터가 JSON으로 변환된다.
  • static, readonly, const 키워드가 붙은 멤버 데이터는 JSON으로 변환되지 않는다.
  • JSON으로 변환하지 못하게 할 멤버는 [NonSerialized] 어트리뷰트를 붙여준다.
  • FromJsonOverwrite(json, object)는 추후 작성할 예정(기능 파악 중..)

 

※※ 직렬화 클래스(혹은 구조체)에 멤버변수가 추가된 경우, 해당 멤버변수에 대한 에러가 발생하지 않고 기본값으로 초기화된다.

 

 

 

래핑 클래스

- 배열이나 리스트 등의 자료구조는 API에 직접 전달하는 기능은 지원되지 않기 때문에, 클래스나 구조체로 래핑 해서 변환한다.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public static class JsonWrapper
{
    #region ARRAY WRAPPER
    [Serializable]
    private class ArrayWrapper<T>
    {
        [SerializeField]
        private T[] m_items;
        public T[] Items { get { return m_items; } }
        public ArrayWrapper(T[] arr)
        {
            m_items = arr;
        }
    }

    public static string ToJson<T>(T[] array, bool prettyPrint = false)
    {
        ArrayWrapper<T> wrapper = new ArrayWrapper<T>(array);
        //bool : 출력 제어 (로그 출력 시, 보기 좋게 출력하는 기능 지원. default : false)
        return JsonUtility.ToJson(wrapper, prettyPrint);
    }

    public static T[] ArrayFromJson<T>(string json)
    {
        ArrayWrapper<T> wrapper = JsonUtility.FromJson<ArrayWrapper<T>>(json);
        return wrapper.Items;
    }
    #endregion

    #region LIST WRAPPER
    [Serializable]
    private class ListWrapper<T>
    {
        [SerializeField]
        private List<T> m_list;
        
        public List<T> ToList()
        {
            return m_list;
        }

        public ListWrapper(List<T> list)
        {
            m_list = list;
        }
    }

    public static string ToJson<T>(List<T> list, bool prettyPrint = false)
    {
        ListWrapper<T> wrapper = new ListWrapper<T>(list);
        return JsonUtility.ToJson(wrapper, prettyPrint);
    }

    public static List<T> ListFromJson<T>(string json)
    {
        ListWrapper<T> wrapper = JsonUtility.FromJson<ListWrapper<T>>(json);
        return wrapper.ToList();
    }
    #endregion
}
  • Dictionary 역시 위와 같은식으로 래핑 클래스를 정의해야한다.

 

 

 

참고

 

JSON 직렬화 - Unity 매뉴얼

JSON 직렬화는 오브젝트와 JSON 포맷을 상호 변환하는 기능입니다. 이 기능은 웹 서비스와 상호작용할 때 유용하거나 단순히 데이터를 텍스트 기반 포맷으로 간편하게 패킹하고 언패킹하는 데 유

docs.unity3d.com

 

 

스크립트 직렬화 - Unity 매뉴얼

직렬화는 데이터 구조나 오브젝트 상태를 Unity 에디터가 저장하고 나중에 재구성할 수 있는 포맷으로 자동으로 변환하는 프로세스를 말합니다. Unity 에디터에서는 저장 및 로딩, 인스펙터 창, 인

docs.unity3d.com

 

 

 

 

 

반응형
반응형

 

 

 

 

 

 

 

제작 기간

- 총 4일

 

 

 

게임 클래스 구성

 

 

 

 

GameManager

- 클래스 멤버는 WordManager, Player, Rank를 가지고있고, 베네치아 이야기를 스크롤링하기 위해 string vector를 멤버로 가지고 있다.

- Main 함수에서 GameManager의 객체를 생성한 뒤, 게임을 실행한다.

- 게임 시작 시, 베니치아 스토리 데이터를 로드해서 저장한다.

- 각 화면은 정적 클래스(Draw)에 화면을 그리는 함수를 정의해서 GameManager에서 호출하여 그린다.

 

 

 

WordManager

- 게임에 사용할 단어들을 로드해서 배열로 저장하고, 게임 중에 사용하기 위한 Word 클래스의 List를 멤버로 가지고 있다.

- 일정 시간을 주기로, 랜덤 확률 체크를 하여 Word 객체를 만들어서 List에 넣는다.

- 단어를 입력하면 맞는 객체의 포인터를 반환한다.

 

 

 

Word

- 좌표, 단어, 아이템 정보를 멤버로 가지고 있다.

- 객체가 생성될 때, 아이템 효과를 랜덤하게 부여한다.

- 아이템 효과는 속도 조절, 숨기기, 화면 비우기 등이 있다.

 

 

 

Rank

- Player 클래스의 List를 멤버로 가지고 있다.

- 랭킹 데이터를 파일 입출력으로 관리한다.

- 랭킹의 순서는 내림차순으로 10개만 보여지지만, 데이터는 플레이한 모든 유저의 데이터를 관리한다.

 

 

 

Player

- 유저 이름, 라이프, 최고 기록(스테이지, 점수)을 멤버로 가지고 있다.

 

 

 

Draw

- 게임 화면을 그리기 위한 함수를 정의해 놓았다.

- 문자열 중앙 정렬로 그리기, 박스 그리기, 지우기 등이 정의되어있다.

 

 

 

저장되어 있는 데이터 구조

- 랭킹, 게임에 사용될 단어 데이터

 

 

 

겪은 문제

- 화면을 그릴때 프레임이 지연되는 문제

- 원인 : 화면의 정보를 반복문으로 문자 1개씩 print하는게 원인.

- 해결 : 문자열로 모든 화면의 정보를 더한 뒤, 문자열을 한번에 그려서 해결.

          특정 구역만 지워야 할 때는 화면 전체를 새로 그리지 않고 해당 구역만 지워서 해결.

 

 

 

 

반응형

'Game > Personal development' 카테고리의 다른 글

[WIN API] 서커스 찰리 게임  (0) 2022.02.05
[WIN API] 카드 맞추기 게임  (0) 2022.01.30
RPG 게임 제작 (C++)  (0) 2022.01.22
뱀 게임 제작 (C++)  (0) 2022.01.22
오목 게임 제작 (C++)  (0) 2022.01.21

+ Recent posts