인프런 커뮤니티 질문&답변

Wind mill님의 프로필 이미지
Wind mill

작성한 질문수

[라이브 멘토링] 유니티 뱀파이어 서바이벌 장르 모작

젬 떨구기

스프라이트 로그가 안됩니다. 이유를 모르겠어요...

작성

·

395

0

아래와 같이 강좌를 통해서 이유를 찾고있는데요. 폴더에 있는 최신 참조 파일과도 다른 점이 없었고,

유니티를 재부팅을 통해서도 확인해보았으나 현상은 동일했습니다. 33:40분에 이야기한 소문자 이야기에 계속 돌려서 보았으나 소문자 부분을 찾지 못하였습니다.

 

혹시 문제가 무엇일까요....? 디버그.로그를 통해서 확인해보니 최초에 정상 로드가 확인되지만, 이후 생성할려고 할때 Null 값이 노출되는 것을 확인하였습니다..

 

 

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using Unity.Mathematics;
using Unity.VisualScripting;
using UnityEngine;

public class ObjectManager
{
    public PlayerController Player { get; private set; } // 플레이어는 따로 관리
    public HashSet<MonsterController> Monsters { get; } = new HashSet<MonsterController>(); // 몬스터도 따로 관리
    public HashSet<ProjectileController> Projectiles { get; } = new HashSet<ProjectileController>(); // 발사체도 따로 관리
    public HashSet<GemController> Gems { get; } = new HashSet<GemController>(); // 잼 따로 관리

    public T Spawn<T>( Vector3 position , int templateID = 0) where T : BaceController
    { 
        System.Type type = typeof( T );

        if( type == typeof(PlayerController) )
        {
            GameObject go = Managers.Resource.Intantsiate("Slime_01.prefab", pooling: true);// 프리팹 불러오기
            go.name = "Player";

            ///////////////////////////////////////////////////////////////////////
            ////
            ///
            go.transform.position = position; // 좌표에 배치

            ///////////////////////////////////////////////////////////////////////

            PlayerController pc = go.GetOrAddComponent<PlayerController>(); // 컨트롤러 불러오기
            Player = pc;                                                    // 컨트롤러 붙이기
            pc.Init(); //초기화
            return pc as T;
        }
        else if (type == typeof(MonsterController))
        {
            string name = (templateID == 0 ? "Goblin_01" : "Snake_01"); // 지금은 억지로 부여하지만, 데이터 테이블이 만들어지면 수정할 것

            GameObject go = Managers.Resource.Intantsiate( name + ".prefab" , pooling: true );

            ///////////////////////////////////////////////////////////////////////
            ////
            ///
            go.transform.position = position; // 좌표에 배치

            ///////////////////////////////////////////////////////////////////////

            MonsterController mc = go.GetOrAddComponent<MonsterController>();
            Monsters.Add( mc );  // 만들어지는 동시에 Monsters 안에 관리하에 들어가게 됨.
            mc.Init(); //초기화

            return mc as T;
        }
        else if( type == typeof(ProjectileController))
        {
            return null;
        }
        else if (type == typeof(GemController)) // 잼 컨트롤러 작동원리 
        {
            GameObject go = Managers.Resource.Intantsiate( Define.EXP_GEM_PREFAB , pooling: true);
            go.transform.position = position;

            GemController gc = go.GetOrAddComponent<GemController>(); 
            Gems.Add( gc ); // 폴더에 추가
            gc.Init(); //초기화

            // 아이템 종류 변경하기. ( 하드코딩 : 확인용 )
            string key = UnityEngine.Random.Range(0, 2) == 0 ? "EXPGem_01.sprite" : "EXPGem_02.sprite"; 
            Sprite sprite = Managers.Resource.Load<Sprite>(key);
            go.GetComponent<SpriteRenderer>().sprite = sprite;

            UnityEngine.Debug.Log( sprite );

            //Debug.Log($"sprite Name: {sprite.name}");
            if (sprite) { UnityEngine.Debug.Log($"sprite Name: {sprite.name}"); }


            return gc as T;
        }
        return null;


    }


    //
    public void Despawn<T>(T obj) where T : BaceController
    {
        System.Type type = typeof(T);

        if (type == typeof(PlayerController))
        {
            //?
        }
        else if (type == typeof(MonsterController))
        {
            Monsters.Remove(obj as MonsterController);
            Managers.Resource.Destroy(obj.gameObject);
        }
        else if (type == typeof(ProjectileController))
        {
            Projectiles.Remove(obj as ProjectileController);
            Managers.Resource.Destroy(obj.gameObject);
        }
        else if (type == typeof(GemController))
        {
            Gems.Remove(obj as GemController);
            Managers.Resource.Destroy(obj.gameObject);
        }
    }
}   

 

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

using UnityEngine.AddressableAssets;    // 에셋 가져오고
using UnityEngine.ResourceManagement.AsyncOperations; // 회색은 필요없다느 뜻임
using System;
using Object = UnityEngine.Object;

public class ResourceManager
{
    // 리소스를 계속 들고 있도록 Dictionary로 만든다.
    Dictionary<string, UnityEngine.Object> _resources = new Dictionary<string, UnityEngine.Object>();


    // 리소스 로드 ( 이미 위의 Dictionary에서 이미 로드를 한 상태라 부담이 없다. )
    public T Load<T>(string key) where T : Object
    {
        if (_resources.TryGetValue(key, out Object reource)) 
        {
            return reource as T;
        }
        return null;
    }

       // Load 를 사용하여 리소스 된 후 인스텐션해서 복사본을 만든다.
    public GameObject Intantsiate(string key, Transform parent = null, bool pooling = false)
    {
        ///////////////////////////////////////////////////////////////
        // 원본 프리팹을 가져옴
        GameObject prefab = Load<GameObject>($"{key}");
        if (prefab == null)
        {
            Debug.Log($"Failed to load prefab :{key}");
            return null;
        }
        ///////////////////////////////////////////////////////////////
        // Pooling
        if ( pooling )
        {
            return Managers.Pool.Pop(prefab);
        }

        ///////////////////////////////////////////////////////////////
        /// 부하가 많이 걸리는 부분 => 그래서 오브젝트풀링( 활성/비활성화 )로 진행
        GameObject go = Object.Instantiate( prefab , parent );
        go.name = prefab.name;
        return go;

    }

    // 오브젝트 삭제 용도.(공용) ( 어드레서블로 만들어지지 않은 애들도 삭제됨 )
    public void Destroy(GameObject go)
    { 
        if ( go == null )
            return;

        if ( Managers.Pool.Push(go) ) { return; } // Pool이 있으면 반납

        Object.Destroy(go); // Pool이 없으면 삭제
    }



    #region 어드레서블
    public void LoadAsync<T>( string key, Action<T> callback = null ) where T : UnityEngine.Object //LoadAsysnc<T>( 키값 , 알려줄 무언가  )
    {
        // 캐시 확인
        if (_resources.TryGetValue(key, out Object resource)) // _resources 키값으로 리소스를 찾은적있다.
        {
            callback.Invoke(resource as T);
            return; // 2번째인경우 리턴
        }

        string loadKey = key;
        if (key.Contains(".sprite"))
            loadKey = $"{key}[{key.Replace(".sprite", "")}]";
        //////////////////////////////////////////////////////////////

        // 리로스 비동기 로딩 시작.
        // 아래는 코드가 완성되면 처리가 끝나면 신호줌.
        var asyncOperation = Addressables.LoadAssetAsync<T>(loadKey); // 처음인 경우, 로드함. ( 비동기 방식으로 )
        asyncOperation.Completed += (op) =>
        {
            _resources.Add(key, op.Result);
            callback.Invoke(op.Result);
        };
    }


    // 내가 원하는 라벨을 검색 후,
    public void LoadAllAsync<T>(string label, Action<string, int, int> callback ) where T : UnityEngine.Object //LoadAllAsync<T>( 라벨명 , 알려줄 무언가  )
    {
        var opHandle = Addressables.LoadResourceLocationsAsync(label, typeof(T));
        opHandle.Completed += (op) =>
        {
            int loadCount = 0;
            int totalCount = op.Result.Count;

            foreach (var reult in op.Result)    // 원하는 값이 나올때까지 반복
            {
                LoadAsync<T>(reult.PrimaryKey, (obj) => // PrimaryKey 파일의 이름 // loadCount 몇번째인지
                {
                    loadCount++;
                    callback?.Invoke(reult.PrimaryKey, loadCount, totalCount);
                });
            }
        };
    }
    #endregion
}
/////////////////////////////////
/// 추가함
using System;
/////////////////////////////////
using System.Collections;
using System.Collections.Generic;
/////////////////////////////////
/// 추가함
using Unity.VisualScripting;
/////////////////////////////////
using UnityEngine;
/////////////////////////////////
/// 추가함
using UnityEngine.Diagnostics;
using UnityEngine.EventSystems;



public static class Extension // Extension문법은 (this GameObject go)에서 this를 함으로써 this.GetOrAddComponent와 같이 사용할수있는 문법
{
    public static T GetOrAddComponent<T>(this GameObject go) where T : UnityEngine.Component
    {
        return Utils.GetOrAddComponent<T>(go);
    }

    public static bool isValid(this GameObject go)
    {
        return go != null && go.activeSelf;
    }

    public static bool isValid(this BaceController bc) 
    {
        return bc != null && bc.isActiveAndEnabled;
    }

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

public static class Define
{
    public enum Scene
    { 
        Unknown,
        DevScene,
        GameScene,
    }

    public enum Sound
    { 
        Bgm,
        Effect,
    }

    public enum ObjectType
    {
        Player,
        Monster,
        Projectile,
        Env,
    }


    public const int PLAYER_DATA_ID = 1;
    public const string EXP_GEM_PREFAB = "EXPGem.prefab";
}

답변 1

1

Wind mill님의 프로필 이미지
Wind mill
질문자

문제를 해결하였습니다. 다른 분의 답변 받은게 무슨말인지 몰라서 이것저것 하다가 무슨 말인지 이해하게 되서 아래와 같이 코드 내용을 공유합니다. 다만 이게 정답인지는 모르겠습니다...최적화나 부하나.. 이런거요..

    var asyncOperation = Addressables.LoadAssetAsync<T>(loadKey); // 처음인 경우, 로드함. ( 비동기 방식으로 )
        asyncOperation.Completed += (op) =>
        {

            // 여기서 타입을 확인합니다.
            //Debug.Log($"key: {key}");
            //Debug.Log($"loadKey: {loadKey}");
            //Debug.Log($"op.Result.GetType: {op.Result.GetType().ToString()}");

            // Texture2D로 불러와진 경우, 이를 Sprite로 변환합니다.
            if (op.Result is Texture2D texture)
            {
                // Texture2D를 Sprite로 변환합니다.
                Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));

                // 리소스에 스프라이트를 추가하고 콜백을 호출합니다.
                _resources.Add(key, sprite);
                callback.Invoke(sprite as T);
                return;
            }

            // 일반적인 경우 리소스를 그대로 사용합니다.
            _resources.Add(key, op.Result);
            callback.Invoke(op.Result);
        };
Wind mill님의 프로필 이미지
Wind mill

작성한 질문수

질문하기