지금까지 작업했던 UI를 Main씬을 저장하고 01.Scenes/Play 씬을 더블클릭해 연다.

Canvas를 하나 만들고 다음과 같이 설정한다.

Canvas를 선택하고 + 버튼을 클릭한 후 UI>Panel을 추가하다. "Panel-Hpbar"로 이름을 바꾼다. Panel의 이미지를 04.Image>Menu폴더의 Button-Tab으로 선택한다.

Panel아래 TextMeshPro를 추가하고 HP로 내용을 바꾼다.

Panel아래 Image를 추가하고 이름을 Image-Hpbar로 수정후 Source Image에 04.Images/Menu폴더에 있는 HpBar를 연결한다.Sprite로 변경후 연결해야한다.

Fill Amount의 슬라이드 바를 조정하면 좌우로 채워지는 걸 확인할 수 있다. TAG를 HP_BAR를 만들어 지정해준다.

PlayerCtrl 스크립트를 다음과 같이 수정한다.

UI에 접근하기 위해 using UnityEngine.UI;를 선언한다.

HP_BAR TAG를 이용해 오브젝트를 hpBar와 연결해준다. ?는 null이 아니면 뒤쪽 GetComponent()을 실행한다는 뜻이다.

hpBar= GameObject.FindGameObjectWithTag("HP_BAR")?.GetComponent<Image>();

트리거가 발생하면 HP를 10빼주고 HP바를 갱신할 DisplayHealth()를 실행한다.

void OnTriggerEnter(Collider coll) {
    if(curHP >= 0.0f && coll.CompareTag("PUNCH")) {
        curHP -= 10.0f;
        DisplayHealth();
        //Debug.Log($"Player hp = { curHP / initHP }");
        if (curHP <= 0.0f) {
            PlayerDie();
        }
    }
}

fillAmount의 값을 조정해 바의 상태를 갱신한다. 0~1f의값을 갖는다

    void DisplayHealth() {
        hpBar.fillAmount = curHP / initHP;
    }

PlayerCtrl 전체코드

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PlayerCtrl : MonoBehaviour {
    // Start is called before the first frame update
    

    Transform tr;
    private Animation anim;

    private float moveSpeed = 10f; //이동속도
    private float turnSpeed = 80f;  //회전속도

    private readonly float initHP = 100.0f;  //초기 생명값
    public float curHP; //현재생명값
    public Image hpBar;

    public delegate void PlayerDieHandler();  //델리게이트타입 선언
    public static event PlayerDieHandler OnPlayerDie; //델리게이트 변수선언
    public
    IEnumerator  Start() {  //start()함수는 코루틴으로 실행할 수 있다.
        //Hpbar연결
        hpBar= GameObject.FindGameObjectWithTag("HP_BAR")?.GetComponent<Image>();
        curHP = initHP;
        DisplayHealth();
        tr = GetComponent<Transform>();
        anim = GetComponent<Animation>();  //추가된 코드
        anim.Play("Idle");
        turnSpeed = 0.0f;  //프로그램 기동시 가비지 마우스값을 막기위해
        yield return new WaitForSeconds(0.3f);  //0.3초 기다린후
        turnSpeed = 300f;  //변수값을 설정
    }

    // Update is called once per frame
    void Update() {
        float h = Input.GetAxis("Horizontal");  //AD 입력 좌우
        float v = Input.GetAxis("Vertical");  //WS 입력 전후
        if (Mathf.Abs(h) > float.Epsilon || Mathf.Abs(v) > float.Epsilon) {  //움직임이 없다면 불필요한 동작을 안한다.
            Vector3 dir = Vector3.right * h + Vector3.forward * v;
            tr.Translate(dir.normalized * moveSpeed * Time.deltaTime);
            PlayerAnim(h, v);
        }
        float r = Input.GetAxis("Mouse X");  //마우스 x축 입력 
        tr.Rotate(Vector3.up * turnSpeed * Time.deltaTime * r);
    }
    void PlayerAnim(float h, float v) {
        if (v >= 0.1f) {  //앞으로 달림
            anim.CrossFade("RunF",0.25f);
        } else if(v <= -0.1f) { //뒤로 움직임
            anim.CrossFade("RunB", 0.25f);
        } else if(h >= 0.1f) { //오른쪽으로 움직임
            anim.CrossFade("RunR", 0.25f);
        } else if (h <= -0.1f) { //왼쪽으로 움직임
            anim.CrossFade("RunL", 0.25f);
        } else { //제자리대기
            anim.CrossFade("Idle", 0.25f);
        }
    }
    void OnTriggerEnter(Collider coll) {
        if(curHP >= 0.0f && coll.CompareTag("PUNCH")) {
            curHP -= 10.0f;
            DisplayHealth();
            //Debug.Log($"Player hp = { curHP / initHP }");
            if (curHP <= 0.0f) {
                PlayerDie();
            }
        }
    }
    void PlayerDie() {
        //MONSTER 태그를 가진 모든 게임오브젝트를 찾아옴
        /*
        GameObject[] monsters = GameObject.FindGameObjectsWithTag("MONSTER");
        foreach(GameObject monster in monsters) {  //모든 오브젝트를 순차적으로 불러옴
            monster.SendMessage("OnPlayerDie", SendMessageOptions.DontRequireReceiver);
        }
        */
        OnPlayerDie();  //주인공 사망 이벤트 호출(발생)
    }
    void DisplayHealth() {
        hpBar.fillAmount = curHP / initHP;
    }
}

TextMeshPro는 유료에셋이었던 모양인데 현재는 설치안해도 사용할 수 있지만 SDF포맷의 폰트에셋을 직접 생성해야 한다.

TextMesh Pro는 Legacy Text보다 다양한 속성을 제공한다.

Menu-UI-Text-Text Mesh Pro를 추가한다.

TextMeshPro-Text(UI)뷰에 텍스트를 입력한다.

<font="LiberationSans SDF"><color=#ff0000><b>S</b></color>pace
Shooter</font>
스페이스슈터

입력하면 한글은 깨져나올것이다. 다음 사이트 http://hangeul.naver.com  에서 나눔체를 다운받아 NanumGothic.ttf폰트를 프로젝트뷰의 "TexMesh Pro/Fonts"폴더로 드래그해 임포트 한다. 

메뉴 Window>TextMeshPro>FontAssetCreator를 선택해 Font Asset Creator뷰를 연다. Source Font File에 생성할 폰트를 연결한다. 브라우저 버튼을 클릭해 나눔고딕을 선택한다.

Character Set을 Custom Range로 해서 특정범위를 지정할 수도 있지만 Custom Characters로 지정해 필요한 폰트만 적을 수도 있다.  설정후 Atlas Resolution을 적절히 조정하고 

Generate Font Atlas를 누르면 인코딩이 시작하고 저장할 수 있다. 

Main Setting에서 폰트를 선택한다.

KSX1001.txt파일을 카피해서 KS X 1001규격의 한글 2350자 만들수도 있다.

 

Rect Transform은 게임오브젝트의 Transform과 같이 위치정보로 UI항목에 기본적으로 추가되어 있다.

GameObject>UI>Panel을  추가한다. 주된용도는 UI항목을 그룹화하는거다

씬뷰 오른쪽 위  2D를 눌러준다 

판넬이 보이게 조정한다.

Panel은 기본적으로 Image컴포넌트가 추가되어 있다

앵커프리셋

앵커프리셋은 Shift, ALT, ALT+SHIFT키의 조합에 따라 여러 모드가 있다.

 

기본앵커프리셋

Panel의 앵커프리셋 옵션은 가로세로가 모두 stretch모드로 되어있다. 판넬의 크기에 자동으로 맞춰진다.

정중앙 정렬, 왼쪽 상단 정렬  왼쪽 상하 리사이즈 정렬 

ALT키 조합의 앵커 프리셋 - 선택된 UI항목을 프리셋으로 이동시켜준다.

SHIFT키 조합의 앵커 프리셋  -  선택된 UI항목의 Pivot위치 변경

ALT+SHIFT - 2가지를 동시에 변경

앵커포지션 속성 - Rect Transform 속성 맨위에 있는 Pos X Y Z는 해당 UI 항목의 앵커 포인트를 기준으로 피벗 좌표가 얼마만큼 떨어져 있는지 나타내는 anchoredPosition이다. 

 

Image Component - Sprite만 사용가능하다.

04.Images/menu폴더에 있는 SF window파일을 Image컴포넌트의 Source Image속성으로 연결한다.

 

다음과 같이 앵커프리셋을 적용한다.

UI-Button을 하나 만든다. Button-Start라고 한다.

크기를 적당히 조정한다.

인스펙터의 Transition을 Animation으로 하고 Auto Generation을 누르면 자동으로 컨트롤러가 만들어진다.

Animator Button컨트롤러를 눌러보면 다음과 같이 애니메이터가 자동으로 생성되어 있다.

이제 마우스가 버튼위로 Roll-Over되었을때 약간 커지는 효과를 만들기 위해 Button을 고른후 Windows-Animation을 누르면 애니메이션클립을 수정할수 있다. 애니메이션뷰가 열리면 Normal에서 Highlighted로 변경한후 녹화버튼을 누른다.

Add Property>Rect Transform>Scale을 누러 추가한다.

스케일을 아래로 펼치고 약간 크게하기 위해 X Y Z를 1.1로 변경후 첫번째 프레임외는 우클릭 Delete를 하고 녹화버튼을 눌러 저장을 한다.

버튼의 이미지도 동그라미를 눌러 Button-Trimmed Image를 선택해 변경한다. 색도 바꿔준다.

버튼을 판넬에 2개더 추가하고 이름을 바꾸고 다음과 같이 배치한다. 버튼의 자식인 텍스트도 적당해 바꾼다.

게임 실행시 첫번째 버튼이 선택되도록 EventSystems의 First Selected 속성에 Button-Start를 끌어다 놓는다.

Button Event

버튼이 눌렸을대 어떤 작업을 할것인지 지정할 수 있다. Button컴포넌트 밑에 +버튼을 이용해 추가할 수 있다.

우선 빈게임오브젝트를 만들고 UIMgr로 이름짓고, UIManager 스크립트를 만든다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager : MonoBehaviour
{
    public void OnButtonClick(string msg) {
        Debug.Log($"Click Button : {msg}");
    }
}

Button 컴포넌트에서 +를 클릭후 UIMgr을 끌어다 연결해주고 OnButtonClick()을 선택한다.

위와 같이 Button-Start를 클릭했을때 호출할 함수를 인스펙터뷰에서 연결하는 방법은 귀찮고 제약이 있다.

따라서 스크립트에서 연결해 보겠다. 일단 호출할 함수를 No Function으로 한다.

UIManager 에 버튼의 동작을 정의한다.

특정 이벤트가 발생하면 호출할 함수를 연결하기 위해 AddListner(UnityAction call)함수를 사용한다. 함수를 연결하는 3가지 방법을 각 버튼마다 다르게 적용하였다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;

public class UIManager : MonoBehaviour
{
    public Button startBtn;
    public Button optionBtn;
    public Button stopBtn;
    private UnityAction action;
    // Start is called before the first frame update
    void Start() {
        action = () => OnButtonClick(startBtn.name);
        startBtn.onClick.AddListener(action);
        optionBtn.onClick.AddListener(delegate{ OnButtonClick(optionBtn.name); });
        stopBtn.onClick.AddListener(() => OnButtonClick(stopBtn.name));
    }
    public void OnButtonClick(string msg) {
        Debug.Log($"Click Button : {msg}");
    }
}

 

 

준비

01.Scene 폴더를 선택후 메뉴에서 File>New Scene 선택후 새로운 씬을 생성한다. Basic을 선택하고 Create 버튼을 누른다. 씬의 이름은 Main으로 변경한다. 다운로드한 Resources/Texture폴더의 Menu 폴더를 04.Images폴더로 끌어다 놓는다.

 

Canvas 객체는 Canva 컴포넌트를 포함하고 있는 게임오브젝트의 일종이다. UI항목은 반듯이 이 Canvas 객체의 하위에 있어야 한다. 

GameObject>UI>Canvas를 선택 Canvas를 하나 만든다. 입력정보들을 Canvas에 전달해주는 EventSystem 객체도 자동으로 생성된다. 

EventSystem객체

Canvas 객체의 컴포넌트

 

Canvas 컴포넌트

UI항목을 화면에 배치하고 렌더링하는 역할 Render Mode옵션에 따라 UI항목의 화면 배치방식을 결정할 수 있다

Screen Space - Overlay

기본 설정값으로 최 상위 계층에 표현되고 일반적은 UI구성이며 어떤 3D 객체에 의해서도 가려지지 않는다. 화면 해상도에 맞춰 자동 조정된다.

 

Screen Space - Camera

UI 항목을 렌더링하는 별도의 카메라 설정 메뉴가 나타난다. 기본 Main Camera와의 충돌이 없도록 Clear Flag, Culling Mask, Depth속성을 적절히 설정해야 한다.

 

World Space

특정 게임 오브젝트에 Canvas객체를 추가하면 더는 Rect Transform의 영향을 받지 않으며 해당 게임 오브젝트의 위치에 영향을 받는다. 

유니티에서 제공하는 UI는 3가지가 있다.

  • IMGUI (Immediate Made GUI) : 코드를 이용해서 UI를 표시하는 방법
  • UI Toolkit : 현재 개방중, 속성을 수치로 관리
  • UNIT UI (UGUI) : 게임 오브젝트 기반의 UI, UI요소를 컴포넌트로 구현

 

+ Recent posts