Unity/Unity Study

[Unity] 3D Surviver 팀 프로젝트 중, 다른 타입으로 발생한 null

Jee-U 2025. 3. 14. 21:14

문제가 발생한 처음 시작

 

 

플레이어나 NPC, 적 등 공통적으로 필요한 HP와 같은 스탯을 관리하기 위해 StatManager를 만들어 스탯(Health, Stamina 등)을 관리할수 있게 해주었다

그리고 플레이어만의 스탯 관리를 위해 PlayerCondition을 만들어주고 여러 스탯 계산을 용이하게 하기 위해 위해 Condition을 만들어 계산하기 편하게 메서드를 만들어주었다.

public class Condition : MonoBehaviour
{
    public float curValue;
    public float maxValue;

    public void Add(float Value)
    {
        curValue = Mathf.Min(curValue + Value, maxValue);
    }
}

Condition 클래스에서 현재값(curValue)을 최대값(maxValue)에 맞춰 계산하는 Add 메서드를 만들었다. 이 메서드는 curValue에 값을 더하되, maxVaule를 넘지 않도록 해주었다.

이걸 PlayerCondition에서 Condition타입으로 _health와 같은 인스턴스를 만들어 스탯 계산을 쉽게 할 수 있도록 했다.

 

public class PlayerCondition : MonoBehaviour
{
    public Condition _health;
    public Condition _hunger;
    public Condition _stamina;
    
    private void Update()
    {
        _hunger.Subtract(_hunger.passiveValue * Time.deltaTime);
        _stamina.Add(_stamina.passiveValue * Time.deltaTime);
    }

SubTract는 감소 함수이며 Condition에서 작성한 함수를 PlayerCondition에서 이런식으로 사용하려고 하였는데.. 처음엔 뭐가 문제지 싶어 컴포넌트나 오브젝트, 스크립트 등을 막 수정도 해보고 했는데 해결이 되지 않았고 타입이 달라 변경이 어렵다는건 나중에 깨달았다... 

public class PlayerCondition : MonoBehaviour
{
    public Condition _health;
    public Condition _hunger;
    public Condition _stamina;

	private void Awake()
    {
        if (statManager != null)
        {
            _health = statManager.health;
        }
    }
}

문제의 코드, _health는 Condition 클래스의 인스턴스인데 statManager.health는 float 값이기 때문에 타입 불일치로 오류가 나는것

하지만 Condition을 가져와야하는 이유는 curValue등의 상태 정보를 포함하고 있기 때문이다.

    private void Awake()
    {
        if (statManager != null)
        {
            _health.curValue = statManager.health;
        }
    }

그리하여 이렇게 하면 둘다 float 값이기 때문에 가능해진다.

 

조금 길어지지만 이렇게해서 다 된줄 알았...다? 근데 자꾸 null 오류가 뜨는게 아닌가..

뭐가 문젠가...

_health와 같이 Condition에서 가져온 애들만 null로 뜨고있다.

해결을 위해 이것저것 다시한번 수정해보고 했는데 나중에서야 해답을 찾게 되었다.

 

이유는 Condition이 클래스이기 때문에 인스턴스를 만들지 않으면 기본적으로 null 상태였을 거고

curValue 같은 속성에 접근하려고 할때 null이 발생했을 가능성이 높다.

    private void Awake()
    {
        _health = new Condition();
        _health.curValue = statManager.health;
        _health.startValue = statManager.health;   
        _health.maxValue = statManager.health;
        
        _hunger = new Condition();
        _hunger.curValue = statManager.hunger;
        _hunger.startValue = statManager.hunger;
        _hunger.maxValue = statManager.hunger;

        _stamina = new Condition();
        _stamina.curValue = statManager.stamina;
        _stamina.startValue = statManager.stamina;
        _stamina.maxValue = statManager.stamina;
    }

 

그리하여 =new Condition();을 하면 새로운 Condition 객체가 힙(Heap) 메모리에 생성되고, _health와 같은 Condition의 스탯들은 null이 아닌 실제 객체를 가리키고 있으므로 오류가 사라진 것이었다.

 

- 값 타입(Value Type) : int, float, boll 같은 기본형은 값을 직접 저장함

- 참조 타입(Reference Type) : class로 만든 객체는 실제 데이터가 힙(Heap) 메모리에 있고, 변수가 그 주소(참조)를 저장

 

예시로

Condition a; // 참조 타입
a = new Condition(); // a는 힙 메모리에 있는 Condition 객체를 참조
a.curValue = 10; // 정상

만약 = new Condition(); 을 하지않고 바로 a.curValue = 10;을 하면 a가 null이 발생한다.

 

이렇게해서 스탯 문제는 끝.

- 이었으나 작성 이후 이 스크립트는 뒤엎게 되었다.