Life Archive
article thumbnail

INTRO

Unity XR Interaction Toolkit을 공부하던 중 LeftHand Direct Interactor에 Kill Log나
HP 등을 표시할 UI를 부착해보기로 했습니다.

이전 제페토 월드를 제작할 때 말풍선에 사용했던 코드를 비교하면서 새로운 방법과 기존 방법과의 차이를 비교해보려고 합니다.


CONTENT

미리 Prefab화 해둔 UI Offset를 Hierachy에 Instantiate하고 LeftHand Direct Interactor의 Child로 넣어주었습니다.

UI Info

중요한 것은 UI의 Rotation이 플레이어의 카메라 Rotation에 맞춰 실시간으로 변해야 한다는 것이죠

제페토 프로젝트를 진행하면서 NPC의 말풍선에도 똑같은 기능을 적용시켜야 했으며,
그 당시에는 LookAtConstraint 클래스의 존재를 몰랐기에 transform.LookAt을 이용하여 직접 구현하였습니다.

Update() {
        if (!this.cam) {
            this.cam =
                GameObject.Find(
                    'CameraParent'
                ).GetComponentInChildren<Camera>();
        } else {
            if (this.NPC_Chat.length === 0) {
                this.SetProperties();
            } else if (this._npcCnt === 0) {
                this.CreateNPCs();
            } else {
                for (let i = 0; i < this.NPC_Chat.length; i++) {
                    this.NPC_Chat[i].transform.LookAt(
                        this.cam.transform,
                        new Vector3(0, 1, 0)
                    );
                }
            }
        }
    }

간단하게 설명하자면, Hierarchy 내에 Local Camera를 찾고 NPC_Chat이 카메라를 따라가도록 설정했습니다.
말풍선인만큼 NPC 머리 위에 위치해야하므로 new Vector3(0, 1, 0)을 사용하여 이동시켜주었습니다.

아래 사진처럼 LookAtConstraint Component를 NPC_Chat GameObject에 붙여주고
Source를 Local Camera로 설정해준다면, 코드작성없이 엔진 내에서 쉽게 구현할 수 있습니다! 

그럼 제페토에서 LookAtConstraint Class를 제페토에서 사용할 수 있을까요?

개발 당시 제페토에선 AddComponent를 지원하지 않았기에,
미리 말풍선 Prefab을 Scene 내에 적절한 Transform으로 배치하고 LookAtConstraint Component를 추가해주었습니다.


또한, Is Active를 체크해준 후 미리 만들어둔 SubLookAtConstraint.ts도 추가하였습니다.
SubLookAtConstraint.ts는 아래와 같습니다.

(23/7/7수정 : AddComponent Method는 지원하지 않는게 아니라 Instantiate하려는 Prefab내에 존재하는 Script가
AddComponent Method를 사용할 경우 오류가 나는 경우가 있어 미리 씬 내부에 배치한 것입니다!)

import {ZepetoScriptBehaviour} from 'ZEPETO.Script';
import {Camera, GameObject} from 'UnityEngine';
import {LookAtConstraint, ConstraintSource} from 'UnityEngine.Animations';
export default class SubLookAtConstraint extends ZepetoScriptBehaviour {
    public cam: Camera;
    public cameraSource: ConstraintSource;

    Start() {
        if (!this.cam) {
            this.cam =
                GameObject.Find(
                    'CameraParent'
                ).GetComponentInChildren<Camera>();
        }
        this.cameraSource.sourceTransform = this.cam.transform;
        this.cameraSource.weight = 1;

        this.transform
            .GetComponent<LookAtConstraint>()
            .AddSource(this.cameraSource);
    }
}

Public으로 cam(Camera)와 cameraSource(ConstraintSource)를 선언하고 Start에서 정의해줍니다.

이 때, cameraSource는 ConstraintSource 타입이기에 cam의 transform으로 설정해둡니다.
또한, weight를 1로 설정해줘야 Scene 내에서 정상적으로 작동합니다.

마지막으로, AddSource를 해주면 위에서 LookAt을 사용했을 때와 동일하게 작동합니다.


RESULT

기존에 사용한 방법은 말풍선 Prefab을 Instantiate하고
Update Method에서 매 프레임마다 말풍선의 Transform이 변경됐습니다.

물론 LookAtConstraint가 작동하는 방식도 Update Method와 비슷하게 작동하겠지만, Instantiate할 필요가 없고,
Transform을 코드 내에서 지정해주지 않아도 되며 모든 NPC들의 말풍선을 반복문으로 돌릴 필요가 없다는 점이
장점이라 생각합니다!

또한, LookAtConstraint 내에서 Source를 List 형식으로 저장할 수 있으며,
말풍선이 카메라를 따라가는 상황뿐만 아니라 다양한 상황에서도 적용시킬 수 있을 것이죠.

프로젝트 혹은 공모전을 진행하면서 LookAtConstraint를 사용한 사례가 있으면 추후에 업데이트할 예정입니다 ㅎ