0428 월드 좌표를 로컬 좌표로 변환하기(+ DOTween)

2021. 4. 28. 15:40unity

왼쪽: 인게임 뷰 안, 오른쪽: 씬 뷰 안

ui상의 보스 체력을 나타내는 게이지를 월드 좌표 안에 있는 캐릭터의 머리 위에 띄우려고 한다.

1. 플레이어 캐릭터의 좌표 먼저 선정해주고 (월드 좌표 기준),

 

2. 플레이어의 월드 좌표를 저장해줄 수 있는 빈게임 오브젝트 생성

using UnityEngine;

public class Hero : MonoBehaviour
{
    public Transform hudGaugeTrans;
    public Transform hudDamageTrans;

    public GameObject gaugeGo;
    // Start is called before the first frame update
    void Start()
    {
        Debug.LogFormat("{0}", UICamera.mainCamera);
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 overlay = NGUIMath.WorldToLocalPoint(this.hudGaugeTrans.position, Camera.main, UICamera.mainCamera, gaugeGo.transform);
        overlay.z = 0f;
        gaugeGo.transform.localPosition = overlay;
    }
}

게임 오브젝트인 gaugeGo.position(ui좌표)을 플레이어의 월드 좌표 hudGaugeTrans로 옮기는 스크립트 작성

NGUIMath.WorldToLocalPoint( 옮겨져야 할 좌표, 메인 카메라, ui카메라, 옮겨야 할 대상)

위와 같은 경우엔 
gaugeGo.transform(옮겨야 할 대상: ui좌표)이 this.hudGaugeTrans.position(옮겨져야 할 좌표: 월드 좌표)이다.   

3. GuageGo = ui 좌표 상의 게임 오브젝트, hudGauge 월드 좌표 상의 게임 오브젝트 

 


 

DOTween 

오브젝트의 애니메이션 혹은 부드러운 값 변경 시 기존의 유니티 내에서 제공하는 애니메이션 기능이나 번거로운 스크립트 작성 대신 함수 몇개로 쉽고 다양한 모션을 줄 수 있는 간편한 API

유니티 에셋 스토어에서 'DOTween' 에셋 import 후에 using.DG.Tweening을 사용할 수 있다.

 

버튼을 누르면 플레이어의 머리 위로 문구가 나타나서 사라지는 모션 만들기

using UnityEngine;
using DG.Tweening;

public class HudText : MonoBehaviour
{
    public UILabel label;

    public void Init(int damage) 
    {
        //게임 오브젝트를 현재 위치에서 이곳 위치로 이동
        this.label.text = damage.ToString();
        var endPos=this.label.transform.position.y + 200;

        //페이드 아웃
        float myfloat = 1f;
        var color = this.label.color;
        DOTween.To(() => myfloat, x => myfloat = x, 0f, 0.5f).onUpdate = () =>
         {
             color.a = myfloat;
             this.label.color = color;
         };

        //스케일 변환
        this.label.transform.DOScale(2, 0.2f).onComplete = () =>
        {
            this.label.transform.DOScale(1, 0.2f);
        };

        //부드럽게 움직이는 애니메이션
        this.label.transform.DOLocalMoveY(endPos,0.5f).SetEase(Ease.OutQuad).onComplete=()=> 
        {
            Debug.Log("easing complete!");
            Destroy(this.gameObject);
        };
    }
}

DOLocalMoveY(이동되는 포지션, 걸리는 시간).SetEase(Ease.모션명).onComplete=()=>{콜백 함수};

easings.net/ko

 

Easing Functions Cheat Sheet

Easing functions specify the speed of animation to make the movement more natural. Real objects don’t just move at a constant speed, and do not start and stop in an instant. This page helps you choose the right easing function.

easings.net

Easing 함수 모션명은 위에서 확인 가능하다.

using UnityEngine;

public class Test : MonoBehaviour
{
    public GameObject GaugeGo;
    public Hero hero;
    public UIButton btn;
    public GameObject labelPrefab;
    public UIPanel panel;
    // Start is called before the first frame update
    void Start()
    {
        this.btn.onClick.Add(new EventDelegate(() =>
        {
            GameObject go = NGUITools.AddChild(this.panel.gameObject, labelPrefab);
            Vector3 overlay = NGUIMath.WorldToLocalPoint(this.hero.hudDamageTrans.position,
                Camera.main,
                UICamera.mainCamera,
                go.transform);  

            overlay.z = 0f;
            go.transform.localPosition = overlay;

            var hud = go.GetComponent<HudText>();
            hud.Init(9999);
        }));
    }
using UnityEngine;

public class Hero : MonoBehaviour
{
    public Transform hudGaugeTrans;
    public Transform hudDamageTrans;

    public GameObject gaugeGo;
    // Start is called before the first frame update
    void Start()
    {
        Debug.LogFormat("{0}", UICamera.mainCamera);
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 overlay = NGUIMath.WorldToLocalPoint(this.hudGaugeTrans.position, Camera.main, UICamera.mainCamera, gaugeGo.transform);
        overlay.z = 0f;
        gaugeGo.transform.localPosition = overlay;
    }
}

 


마우스 클릭하는 곳으로 캐릭터 이동(2D)

배경에 box collider2D가 붙어야 Physics2D.Raycast가 제대로 작동된다.


그리고 뻘한 거지만… 오브젝트 자체에 이미 애니메이터가 구현 되어있다면, 그걸 묶어둔 빈 오브젝트를 assign 해놓고 GetComponent로 부르지 말자. 계속 오류 뜬다 ㅅㅂ

using UnityEngine;

public class Test : MonoBehaviour
{
    public GameObject GaugeGo;
    public Hero hero;
    public UIButton btn;
    public GameObject labelPrefab;
    public UIPanel panel;
    // Start is called before the first frame update
    void Start()
    {
        this.btn.onClick.Add(new EventDelegate(() =>
        {
            GameObject go = NGUITools.AddChild(this.panel.gameObject, labelPrefab);
            Vector3 overlay = NGUIMath.WorldToLocalPoint(this.hero.hudDamageTrans.position,
                Camera.main,
                UICamera.mainCamera,
                go.transform);  

            overlay.z = 0f;
            go.transform.localPosition = overlay;

            var hud = go.GetComponent<HudText>();
            hud.Init(9999);
        }));
    }

    // Update is called once per frame
    void Update()
    {
    //클릭한 곳에 ray 빨간선 긋기
        if (Input.GetMouseButtonDown(0)) 
        {
            var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            Debug.DrawRay(ray.origin, ray.direction * 1000, Color.red, 1.5f);

        }
    }
}
using UnityEngine;

public class Hero : MonoBehaviour
{
    public Transform hudGaugeTrans;
    public Transform hudDamageTrans;

    public GameObject hero;
    public float moveSpeed = 2f;

    private Vector3 targetPos;
    private bool isMove;
    public Animator anim;

    public GameObject gaugeGo;
    private Coroutine routine;


    // Start is called before the first frame update
    void Start()
    {
        this.anim.Play("idle");
    }


    // Update is called once per frame
    void Update()
    {
        Vector3 overlay = NGUIMath.WorldToLocalPoint(this.hudGaugeTrans.position, Camera.main, UICamera.mainCamera, gaugeGo.transform);
        overlay.z = 0f;
        gaugeGo.transform.localPosition = overlay;

    }

    public void Move(Vector3 targetPos)
    {
        if (this.routine != null)
        {
            StopCoroutine(this.routine);
        }
        this.routine = StartCoroutine(this.MoveImpl(targetPos));
    }

    private IEnumerator MoveImpl(Vector3 targetPos) 
    {
        this.anim.Play("run");
        if (this.transform.position.x < targetPos.x)
        {
            this.transform.localScale = Vector3.one;
        }
        else
        {
            this.transform.localScale = new Vector3(-1f, 1f, 1f);
        }
        while (true)
        {
            var dir = (targetPos - this.transform.position).normalized;
            this.transform.Translate(dir * moveSpeed * Time.deltaTime);
            var distance = Vector3.Distance(targetPos, this.transform.position);
            if (distance <= 0.1f)
            {
                this.anim.Play("idle");
                break;
            }
            yield return null;
        }
        
    }        
}