[Unity2D] 새콤달콤 딸기농장 메인 오브젝트 개발(5) - 잡초 구현

SHG·2022년 4월 25일
0

잡초 구현

저번에 구현한 벌레에 이어 딸기 성장에 다른 방식으로 악영향을 주는 잡초를 구현하였다.

잡초 Prefab은 Weed 스크립트, Animator, Capsule Collider가 주된 역할을 수행한다. 벌레 때와 마찬가지로 Collider끼리 겹침을 최소화하기 위해 각 상황 별로 나누어 Collider 처리를 해주었다.

위 이미지에서 대부분의 상황을 볼 수 있다.

  1. 맨 땅에 자란 잡초는 단순히 밭의 Collider를 없애고 자라난다. 이 때 잡초를 제거해야 밭의 Collider가 다시 활성화된다! 즉 잡초를 제거하기 전까진 딸기를 심을 수 없다.

  2. 딸기가 자라고 있는 밭에 자란 잡초는 기존 자라고 있던 딸기에는 Collider가 없었으므로 따로 Collider 처리는 없다. 대신 잡초를 제거하지 않으면 딸기의 성장이 멈춘다.

  3. 수확 가능한 딸기 밭에도 잡초가 자랄 수 있다. 잡초가 자라면 (1)의 상황과 마찬가지로 잡초를 제거하기 전까지는 수확을 진행할 수 없다.

  4. 벌레와 잡초는 공존이 가능하다. 따라서 두 가지 요소가 제거되어야만 정상 상태로 돌아온다.

따라서 크게 본다면 잡초가 Collider를 키는 상황은 1, 3이고, 켜지 않아도 되는 상황은 2라는 것을 알 수 있다!

Weed 스크립트

공통적으로 잡초가 발생되는 코드는 Weed 스크립트에 구현 돼 있다.

public void GenerateWeed() // 잡초 생성
{
    float prob = Random.Range(0, 100);
        
    //scale = Random.Range(1.3f, 1.8f);
    if (prob < DataController.instance.gameData.berryFieldData[weedIdx].weedProb)
    {
        this.gameObject.SetActive(true); // 나 자신(잡초)를 활성화

        farmColl.enabled = false; // 밭의 콜라이더 비활성화
        DataController.instance.gameData.berryFieldData[weedIdx].hasWeed = true; // 잡초보유여부를 확인하는 변수
        DataController.instance.gameData.berryFieldData[weedIdx].canGrow = false; // 딸기의 성장 제어

        xPos = Random.Range(-0.35f, 0.35f); // 밭의 X축의 랜덤한 위치에 잡초 생성
        transform.position = new Vector2(farm.transform.position.x + xPos, farm.transform.position.y + 0.07f);            
    }
}

또한 잡초가 제거 될 때 각 (1), (2), (3) 상황마다 알맞게 처리를 해줘야 하므로 그에 따른 처리를 해줘야 한다.

public void DeleteWeed()
{
    anim.SetTrigger("Delete");

    if (this.gameObject.activeSelf)
    {
        StartCoroutine(DisableWeed(0.25f)); // 애니메이션이 끝난 후 비활성화
    }      
}
IEnumerator DisableWeed(float time)
{
    yield return new WaitForSeconds(time);
     
    float creatTime = DataController.instance.gameData.berryFieldData[weedIdx].createTime; // 딸기가 생성된 시간변수 참조
    if (creatTime == 0f || creatTime >= DataController.instance.gameData.stemLevel[4]) // 맨 땅이거나 딸기가 수확가능한 상태라면
    {
        farmColl.enabled = true; // 밭의 Collider를 켠다.
    }
    else // 아니라면
    {
        farmColl.enabled = false; // 끈다.
    }
    DataController.instance.gameData.berryFieldData[weedIdx].hasWeed = false; // 잡초 제거됨
    if (!DataController.instance.gameData.berryFieldData[weedIdx].hasBug) // 벌레가 없다면
    {
        DataController.instance.gameData.berryFieldData[weedIdx].canGrow = true; // 딸기는 다시 자랄 수 있다.
    }
    this.gameObject.SetActive(false); // 잡초 비활성화
}

발생한 문제와 해결 방법

위의 코드들을 통해 간단하게 잡초의 발생과 제거에 관한 함수들을 살펴보았다. 지금부터는 코딩을 하면서 어려웠던 부분에 대해 얘기 해보려 한다!!

첫 번째로는 Awake() 함수에 관한 얘기이다.

void Awake()
{        
    anim = GetComponent<Animator>();
    farm = transform.parent.gameObject.GetComponent<Farm>();        
    farmColl = farm.GetComponent<BoxCollider2D>();       
}

위 코드는 Weed의 Awake() 함수로써 잡초가 밭과 심어진 딸기에 영향을 주므로 반드시 접근 해야 하는 오브젝트들이다. 근데 자꾸 NullReferenceException 오류가 나길래 한참을 어디가 잘못된 지 몰라 한참을 고민했는데,,, 계속 돌려보다가 알게 된 사실이 있었다. 그것은 바로~

this.gameObject.SetActive(true); // 나 자신(잡초)를 활성화

farmColl.enabled = false; // 밭의 콜라이더 비활성화
DataController.instance.gameData.berryFieldData[weedIdx].hasWeed = true; // 잡초보유여부를 확인하는 변수
DataController.instance.gameData.berryFieldData[weedIdx].canGrow = false; // 딸기의 성장 제어

xPos = Random.Range(-0.35f, 0.35f); // 밭의 X축의 랜덤한 위치에 잡초 생성
transform.position = new Vector2(farm.transform.position.x + xPos, farm.transform.position.y + 0.07f);

위 상황처럼 만약 생성 되지 않았거나 생성되었더라도 한번도 SetActive(true)인 적이 없었다면 Awake()함수가 실행되지 않는다는 것이었다..!🤦‍♂️ 들으면 되게 당연한 말인 것 같은데 은근히 놓치기 쉬운 부분인 것 같다. 나의 코드는 처음엔

farmColl.enabled = false; // 밭의 콜라이더 비활성화
DataController.instance.gameData.berryFieldData[weedIdx].hasWeed = true; // 잡초보유여부를 확인하는 변수
DataController.instance.gameData.berryFieldData[weedIdx].canGrow = false; // 딸기의 성장 제어

xPos = Random.Range(-0.35f, 0.35f); // 밭의 X축의 랜덤한 위치에 잡초 생성
transform.position = new Vector2(farm.transform.position.x + xPos, farm.transform.position.y + 0.07f);

this.gameObject.SetActive(true); // 나 자신(잡초)를 활성화

이런 상황이었고 그에 따라 Awake()함수가 실행되지 않음으로써 farm에 접근이 불가능했기 때문에 발생한 오류였다. 😢

두 번째로는 DeleteWeed() 함수에 관한 얘기이다.

잡초를 터치해 없애려고 하니 또 NullReferenceException 오류가 났었는데 이번엔 꺼진 오브젝트를 참조했다는 오류였었다. 그래서 오류 메세지로 구글링을 해보니 잡초가 activeSelf가 아닐 때 참조하려고 했기 때문에 오류가 발생한다는 것을 알게되었다. 따라서 잡초가 켜져있을 때만 비활성화 시켜주는 조건문을 추가했다!

public void DeleteWeed()
{
    anim.SetTrigger("Delete");

    if (this.gameObject.activeSelf) // 활성화 되어 있다면
    {
        StartCoroutine(DisableWeed(0.25f)); // 애니메이션이 끝난 후 비활성화
    }      
}

마지막으로 GameManager의 Collider를 On/Off 해주는 함수 두 가지를 수정하고 마쳤다.

public void DisableObjColliderAll() // 모든 오브젝트의 collider 비활성화
{
    BoxCollider2D coll;
    isblackPanelOn = true;
    for (int i = 0; i < farmList.Count; i++)
    {
        coll = farmList[i].GetComponent<BoxCollider2D>();
        coll.enabled = false;
        bugList[i].GetComponent<CircleCollider2D>().enabled = false;
        farmList[i].weed.GetComponent<CapsuleCollider2D>().enabled = false;       
    }
}

public void EnableObjColliderAll() // 모든 오브젝트의 collider 활성화
{
    BoxCollider2D coll;
    isblackPanelOn = false;
    for (int i = 0; i < farmList.Count; i++)
    {
        coll = farmList[i].GetComponent<BoxCollider2D>();
        if (!DataController.instance.gameData.berryFieldData[i].isPlant && !DataController.instance.gameData.berryFieldData[i].hasWeed) // 잡초가 없을 때만 빈 밭의 Collider활성화
        {
            coll.enabled = true;
        }
        if (!DataController.instance.gameData.berryFieldData[i].hasBug && !DataController.instance.gameData.berryFieldData[i].hasWeed && DataController.instance.gameData.berryFieldData[i].createTime >= DataController.instance.gameData.stemLevel[4]) // (4)의 상황, 즉 벌레와 잡초 둘 다 없을 때 다 자란 딸기밭의 콜라이더를 켜준다.
        {
            coll.enabled = true;
        }
        bugList[i].GetComponent<CircleCollider2D>().enabled = true;
        farmList[i].weed.GetComponent<CapsuleCollider2D>().enabled = true; // 잡초의 Collider 활성화
    }
}
profile
기록에 익숙해지자...!

4개의 댓글

comment-user-thumbnail
2022년 4월 29일

와 대박이다... 개임개발 ..... 멋지네요...

답글 달기
comment-user-thumbnail
2022년 4월 29일

와 대박이다... 개임개발 ..... 멋지네요...

답글 달기
comment-user-thumbnail
2022년 4월 30일

다음 게시물은 언제 올라오나요?

1개의 답글