Unity/Dev

[Unity] 물방울을 뿌리면 식물이 자라는 interaction 구현하기 (3)

_GyC_ 2023. 1. 21. 13:15

1편, 2편에서 물방울을 얻는 interaction을 구현했었다.

 

다음은 그 물방울을 새싹에 떨어뜨려 식물이 자라나게 하는 interaction이다.

 

먼저, 물방울을 떨어뜨리려면 grab한 물방울을 release했을 때 떨어지는 물방울이 자연스러워야 한다. 

 이 때는 Oculus Integration SDK에서 제공하는 Physics Grabbable을 사용해야 하는데, 자세한 건 아래 링크에서 알 수 있다. 

https://gycblog.tistory.com/13

 

[Unity][Trial&Error] 오브젝트를 grab 후 release할 때 아래로 빠르게 떨어지는 현상

먼저, Oculus Integration SDK를 사용하여 물체를 grab하는 방법은 다음 글을 참고하라. https://gycblog.tistory.com/6 [Unity] Player Grab Interaction with Oculus Integration SDK [Interaction Setting - InputOVR] 1. Hierarchy에 InputOVR을

gycblog.tistory.com


물방울이 식물에 뿌려졌는지 감지하기.

파란 큐브가 물, 바닥과 빨간 큐브가 Terrain, 초록 Cylinder가 식물

식물 주변에 Collider를 배치하고, 물방울이 해당 Collider와 충돌하면 식물에 뿌려졌다고 할 수 있다.

추가적으로, 물방울이 식물외에 다른 곳(Terrain)에 떨어지면 파괴되도록 할 것이다.

 

물방울(WaterSphere)에 부착한 스크립트는 다음과 같다. (더보기 Click)

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class WaterSphere : MonoBehaviour
{
    public int terrainLayerNum;
    public bool waterSphereGrabbed = false;
    public UnityEvent GrowPlant;
    private bool plantCollided = false;

    void Start()
    {
        gameObject.SetActive(false);
    }

    void OnTriggerEnter(Collider other)
    {
        // 1. release된 상태에서 식물과 collide - grow plant
        // waterSphereGrabbed = false && plantCollided = true;
        // 2. grab된 상태에서 식물과 collide - grow plant
        // waterSphereGrabbed = true && plantCollided = true;
        if (other.gameObject.name == "PlantCollider")
        {
            plantCollided = true;
            GrowPlant.Invoke();
            gameObject.SetActive(false);
        }
        // 3. release된 상태에서 다른 것과 collide - destroy water sphere
        // waterSphereGrabbed = false && plantCollided = false;
        else if (other.gameObject.layer == terrainLayerNum && !waterSphereGrabbed)
        {
            gameObject.SetActive(false);
        }
        // 4. grab된 상태에서 다른 것과 collider - nothing happens
    }

    public void waterSphereUnGrab()
    {
        waterSphereGrabbed = false;
    }
}

코드에서 볼 수 있듯이 4가지로 구분했다.

1. 물방울을 놓고 물방울이 식물과 Collide했을 때. >>> 식물이 자란다.

 

2. 물방울을 잡은 상태에서 물방울이 식물과 Collide했을 때. >>> 식물이 자란다.

 

3. 물방울을 놓았는데 Terrain에 Collide했을 때. >>> 물방울이 파괴된다.

 

4. 물방울을잡은 상태에서 Terrain에 Collide했을 떄. >>> 아무일도 일어나지 않는다.


코드를 하나하나 뜯어보자.

먼저 1,2번의 경우가 일어나면 식물이 자라는 Event를 발생시킬 것이기 때문에 UnityEngine.Events를 사용한다.

 

총 3개의 변수가 있다.

 

terrainLayerNum은 물방울이 Terrain가 충돌하는지 확인하기 위해 Terrain Layer의 number를 입력받는다. Tag와는 다르게 Layer는 string이 아니라 int로 받더라. Layer는 언제든지 바뀔 수 있기 때문에 직접 number를 입력하도록 했다.

 

waterSphereGrabbed는 물방울이 grab된 상태인지 release된 상태인지를 알려준다.

 

GrowPlant는 UnityEvent로, 1,2번의 경우에 Invoke할 것이다.


먼저, 물방울은 처음에는 비활성화 되어야한다. 왜냐하면 물과 상호작용시에만 활성화되어야하기 때문이다.


OnTriggerEnter를 통해 물방울이 어떤 오브젝트(other)와 충돌했는지 알 수 있다.

 

만약 물방울이 PlantCollider와 충돌했다면 1, 2번의 경우이므로 GrowPlant 이벤트를 invoke하고, 물방울은 비활성화된다.

 

그게 아니라 물방울이 release된 상태에서 Terrain과 충돌하면 파괴되어야 하므로 바로 비활성화된다.

 

*여기서 왜 물방울이 release된 상태여야할까? 바로, 물방울을 잡고있는 상태에서 모르고 물방울이 주변 지형과 충돌할 경우도 있기 때문이다. 이럴때는 아무일도 일어나면 안되므로 꼭 물방울이 release된 상태에서 지형과 부딪혀야 파괴되도록한 것이다.


 

waterSphereUnGrab 함수는 물방울이 release되었을 때 waterSphereGrabbed bool을 false로 바꿔준다. 이건 물방울의 Pointable Unity Event Wrapper에서 사용하는 함수인데, 이 부분은 따로 다룰 예정이다.


결과 동영상