Prosto

따라하는 유니티 2D 프로젝트ⓐ -5 본문

Programing/Unity 3D

따라하는 유니티 2D 프로젝트ⓐ -5

Prosto 2016.09.16 19:14

따라하는 유니티 2D 프로젝트 강좌 다섯 번째 시간입니다.

이번에 다룰 내용은 스코어 부분입니다.

점수를 추가하여 현재 얻는 점수가 몇인지 표시하는 방법을 소개할 것입니다.

또, 점수를 표시할 때 단순하게 점수가 한번에 바뀌는 방법과

Lerp라는 기능을 이용하여 점수가 단계적으로 상승하는(카운팅) 방법을 해보도록 하겠습니다.

아직 점수 부분의 전부를 하지는 못 했지만, 가장 기본이 되는 부분을 구성하는 것이라 생각하시면 됩니다.

 

그럼 시작하겠습니다.

 

가장 먼저 저번에 작업했던 프로젝트를 실행합니다. 그리고 순서대로 직접 해보며 따라오시면 됩니다.

 

Hierarchy 패널에서 우측버튼을 클릭하여 UI - Canvas를 선택하여 생성해줍니다.

 

(Canvas가 생성된 모습입니다.

밑에 EventSystem도 함께 생성된 것을 확인할 수 있습니다.)

 

 

Canvas의 Inspector에서 설정을 해줍니다.

Canvas - Render Mode의 Screen Space - Overlay를 클릭하여

우리가 사용할 Screen Space - Camera로 변경하여 줍니다.

 

그런 다음 Render Camera를 설정하기 위하여

지금은 우리가 사용 중인 Main Camera를 옮겨 넣도록 합시다.

(원래 UI는 별도로 UI Camera를 생성하여 사용합니다만 지금은 편의상 이렇게 하죠.)

 

그럼 가장 먼저 해야하는 Canvas 생성과 설정은 끝났습니다.

다음으로 판인 Panel을 생성해봅시다.

캔버스 위에서 우측클릭 - UI - Panel 순으로 선택하여 생성해줍니다.

 

(Canvas 하위에 Panel이 생성된 모습입니다.)

 

Panel에서는 Image의 체크를 해제해주도록 하죠.

(현재 우리가 쓸 UI에는 Score만 존재하니 채워지지 않은 게 더 낫겠죠?)

 

 

다음으로 패널에서 우측 클릭 후 UI - Text 순으로 선택하여 생성하여줍니다.

 

Text의 Inpector에서

Rect Tranform 부분을 설정하기 위하여

1, 2 순서대로 선택하여 줍니다.

 

다음으로는 세부 항목 셋팅을 해줍니다.

Pos X, Y값을 입력해주고(여기서 x, y 값은 왼쪽의 탑,센터 기준입니다.)

Text 테스트를 위하여 문구도 입력해주고 모두 따라해줍니다.

몇 가지만 설명을 적자면.

Font Size : 잘 알고있듯 폰트의 크기입니다.

 

Paragraph 항목을 볼까요?

Alignment 좌우에서 정렬, 위아래에서 정렬을 지정해줄 수 있습니다.

Horizontal Overflow : 수평(좌우)에 글자 채우기 형식입니다.

Overflow 선택 시 글자가 해당 텍스트 좌우박스 칸을 넘어가도 그대로 나타납니다.

Vertical Overflow : 수직(상하)에 글자 채우기 형식입니다.

Overflow 선택 시 글자가 해당 텍스트 상하박스 칸을 넘어가도 그대로 나타납니다.

Raycast Target : 클릭 대상으로 들어갈지 여부에 대한 부분입니다.

단순 스코어 표시 자리이니 해제해줍니다.

 

이렇게 우리가 입력해준 레이아웃을 따라

Score가 화면에 표시되는 것을 볼 수 있습니다.

(Scene의 하얀색 실선들이 레이아웃 위치들을 나타내고 있습니다.)

 

실제로 게임을 실행해봐도 Score : 30,000이라는 글자가

화면 상단에 고정되어 있는 것을 확인할 수 있습니다.

 

 

그러면 이제 실제 스코어 작동을 시켜볼까요?

먼저 ScoreManager라는 스크립트를 System에 생성해줍니다.

 

 

소스를 따라 입력하는데 새로운 것들이 눈에 띄네요.

하나씩 확인해볼까요?

 

using UnityEngine.UI;

우리가 UI 관련 항목을 사용하고 싶다면 using에 추가해줘야 합니다.

(Text, Canvas, Panel, Button 등등 UI들요!)

 

GameObject.Find("이름")

게임오브젝트를 찾는 함수입니다.

Find뒤에는 string 형식의 이름을 입력받아 찾습니다.

고유한 이름을 사용하면 이름만으로 Hierarchy에 존재하면 GameObject를 찾아내줍니다.

(비용은 전체를 봐야하니 꽤 되겠죠?)

transform.FindChild("이름")

트랜스폼을 찾는 함수입니다. 이 함수의 좋은 점은

해당 자식들 중에 있는지 없는지 확인하기 때문에 비용은 자식들의 수 정도죠.

자식에게 있어야만 얻을 수 있습니다.

 

Find 계열의 함수들은 이름 부분에 오타가 나지 않도록 잘 확인하며 입력해야 합니다.

 

마지막으로 scorePoint.ToString("N0")

이 부분을 보면 스코어포인트를 문자열로 바꾸겠다는거죠?

거기에 ("N0") 타입으로요.

N0타입은 정수형으로 표시하되, 천의 단위는 끊어서 나타내는 형식입니다.

(이 3,000,000 처럼요.)

 

 

다음으로 GameManager에 해당 스크립트를 등록해주는 작업을 해야겠죠?

GameManager 선택 - Scripts - System - ScoreManager스크립트를 게임매니저 아래쪽에 드래그앤드랍해주세요.

 

 

실제 게임 화면에 반응이 온 것을 확인할 수 있습니다.

(글자가 바뀌었죠? 처음 0 셋팅도 해주고요.)

 

 

그럼 실제로 증가하는 모습을 확인해보겠습니다.

음. 가장 기본적인 형태로

1초에 100점씩 스코어 증가가 되도록 만들어보죠.

코루틴을 사용하였죠?

(사용 방법을 모르시면 눌러서 확인바랍니다.)

 

 

정상적으로 100씩 증가되는 모습을 볼 수 있습니다.

이제 게임을 오래할 수록 높은 점수가 나오겠네요!

(게임 끝나는 이벤트가 아직 없어서 오래 켜둘수록이지만...)

 

그럼 이 수치 상승이 더 자연스럽고 멋있게!

카운팅하는 식으로 바꿔봅시다.

코루틴으로 작성된 PlusValue 부분을 작성해주세요.

다른부분은 체크해둔 곳 위주로 확인해보시고요.

우리는 Mathf.Lerp()에 대하여 확인해봅시다.

Mathf.Lerp()함수는 시작과 끝 사이의 값을 알려주는 함수입니다.

예를 들어 시작이 0 끝이 1인데 이 사이 값을 알고싶다. 이럴 때 사용됩니다.

Mathf.Lerp(0, 1, 시간에 따라 변화)

 

Mathf.Lerp(0, 1, 0.1f) -> Mathf.Lerp(0, 1, 0.2f) -> Mathf.Lerp(0, 1, 0.3f) -----> Mathf.Lerp(0, 1, 1f) 이렇게되면 최대치죠.

 

저는 그것을 이용하여 이전에 나타낸 점수와 현재의 점수 차이를 나타냈습니다.

보면 0.033초 간격으로 텍스트에 보여주는 값을 바꾸고 있죠?

 

 

그리고 실제 이 코루틴이 호출될 부분을 추가해줘야 합니다.

PlusScore로 스코어를 추가 습득했을 때 해주면 되겠네요.

 

그리고 plusIng을 통하여 동시에 이 코루틴이 동작하지 않도록 막고 있네요.

 

 

자 이렇게 다 입력한 후 게임을 실행해보면

우리의 SCORE가 아주 잘 작동되고 있는 것을 확인할 수 있습니다.

 

지금은 단순히 숫자가 카운팅식으로 증가하는 것으로 효과를 줬지만

색깔 변화나 이펙트 등으로 더욱 증가의 느낌을 줄 수 있답니다.

이러한 부분은 수정에 가까우니 다음에 더 다뤄보도록 하죠.

 

지금까지 따라하는 유니티 2D 프로젝트ⓐ -5번 강좌를 보셨습니다.

이번 시간에는 UI를 만들어봤죠? 가장 기본적인 UI로 Text뿐이었지만, 이걸 했으니 이제 UI도 표현해봤다!가 되는 것입니다.

UI 부분을 하며 소스 상에서도 어떠한 변화가 있는지 어떻게 Text 변화를 처리하는 지도 확인해봤습니다.

그리고 나름 중요한 부분은 GameObject.Find와 transform.findChild도 둘러봤구요.

코루틴도 또 다시 사용해보며 어떤 느낌인지 감 좀 오셨는지요..

 

 

다음 유니티 2D 프로젝트ⓐ의 여섯 번째 강의에서는..

가능하다면 간단하게 애니메이션에 대하여 다뤄보겠습니다.

그리고 추가 기능들도 같이 작업하고요.

 

 

고생하셨습니다. 따라오며 하니 좀 도움이 되셨나요?

그럼 프로젝트의 다음 단계를 진행하며 새로운 것들에 대해서는 지금과 같이 설명하며 진행하도록 하겠습니다.

 

 

궁금한 점 있으시면 댓글이나 따로 메일로 질문하시면 시간되는 대로 답변드리겠습니다. ( 연락 )

15 Comments
  • 프로필사진 unity5 2016.09.22 19:01 신고 강좌 잘보고 있습니다
    GameManager에 ScoreManager 스크립트를 작성해서 추가까지했는데
    실행시 'Object reference not set to an instance of an object' 에러가 나면서
    스코어가 '0'으로 바뀌지 않네요
    초보라서 문의 드립니다
  • 프로필사진 Prosto 2016.09.23 01:47 신고 안녕하세요. 확인했습니다.

    NullReferenceException오류신가요? scoreTx에서 대상을 제대로 받지 못한 것 같습니다.

    Find, FindChild 모두 대소문자 구분을 하니 Heirarchy 패널에서 이름을 정확히 확인하신 후 작성해보세요.
    (이름 복사해서 붙여넣기로 넣으셔도 됩니다.)

    Heirarchy에 저와 같은 이름으로 하셨다면
    scoreTx = GameObject.Find("NormalUI").transform.FindChild("scoreTx").GetComponent<Text>();
    입니다.

    그래도 안 된다면 소스+유니티 화면 스크린샷 찍어서 메일로 보내주시면 확인하고 답장드리겠습니다.
  • 프로필사진 unity5 2016.09.23 11:03 신고 아.. Hierarchy에서 Panel, Text이름을 바꾸신거였군요
    언어쪽도 시작단계라 눈치를 못챘습니다;
    빠른답변 감사드리며 다음강좌도 잘보겠습니다~
  • 프로필사진 Prosto 2016.09.23 13:05 신고 네 또 궁금한 점 있으시면 말씀해주세요.
    추가적으로..
    GameObject.Find(이름)
    은 그야말로 이름만으로 찾기때문에.. UI든 오브젝트는 생성 후 변경해주셔야 각각 다른 이름으로 구분이 됩니다!
  • 프로필사진 2016.11.23 10:26 비밀댓글입니다
  • 프로필사진 Prosto 2016.11.23 19:31 신고 아 그 부분이 빠져있군요.
    맞습니다!
    int pastScorePoint = 0;
    이라고 선언하신 후 사용하시면 됩니다.
    (선언 위치는 scorePoint 바로 밑이나 편한 곳에 해주시면 되고요!)
    혹 또 문제있으시면 언제든지 댓글이나 메일주세요!
  • 프로필사진 2016.12.12 05:33 비밀댓글입니다
  • 프로필사진 Prosto 2016.12.12 20:40 신고 ScoreManager 스크립트에서 12번째 줄에 어떤 소스가 있는 상황인지요?
    에러 메시지만 가지고 이렇다 말씀드릴 수가 없네요..
    일단 현재 프로젝트의 ScoreManager.cs 12번째 줄이 현재 게시글 그대로였고, 문제가 있다는 점을 토대로 본다면
    참조 이름이 정확한지( NormalUI와 scoreTx)와 상단에 using UnityEngine.UI; 입력해주셨는지
    확인해보시면 좋겠네요.

    그렇게 해도 잘 안 되신다면 현재 스크립트 소스 + 에러 문구 댓글로 달아주시면 다시 답 드리겠습니다~
  • 프로필사진 Devsim 2017.02.17 21:28 신고 안녕하세요 좋은 강의 잘 듣고 있습니다.
    12번째 줄에 scoreTx = GameObject.Find("NormalUI").transform.FindChild("scoreTx").GetComponent<Text>();
    부분이있는데
    scoreTx = GameObject.Find("scoreTx").GetComponent<Text>(); 해도 작동되던데
    굳이 부모를 거쳐서 scoreTx를 찾는 이유가 있나요?
  • 프로필사진 Prosto 2017.02.25 22:39 신고 안녕하세요.
    몇 가지 이유가 있습니다만,
    여기서는 그렇게 사용하셔도 좋습니다.

    부모를 거쳐서 접근하는 경우
    비활성화 상태의 객체도 찾을 수 있기 때문에 만약을 위하여 그렇게 사용하였습니다.

    scoreTx가 비활성화 된 상태의 씬에서 게임이 시작되는 경우.
    GameObject.Find("scoreTx")를 하는 경우 찾지 못하여 null이 반환됩니다.

    ( transform.FindChild() 함수의 경우엔 비활성화 객체도 접근 가능합니다. )
  • 프로필사진 초콜릿 2017.05.20 21:02 신고 Prosto님이 하신 것에서 Hierarchy부분에서는 Text로 나와있고 Text를 클릭했을때 나오는 Inspector 맨위에는 scoreTx라고 나와있는데 어떻게 저것만 바꾸신 건가요?? 그래서인지 저도 첫번째 댓글분과 같은 오류가 나와요;;
  • 프로필사진 Prosto 2017.05.21 23:39 신고 아래쪽 이미지를 보면 scoreTx라고 되어있는 걸 봐서는
    스크린샷을 찍고 올릴 때 순서 상 문제가 있었다고 생각됩니다!
    초콜릿님께서 말씀하신 대로 scoreTx로 변경하면 Hierarchy와 Inspector 모두 scoreTx로 변경된 게 맞습니다!
    (내용 수정해두겠습니다! 감사합니다.)
  • 프로필사진 그레이스톤 2017.08.08 00:25 신고 ScoreManager에서 plusIng가 있는 이유가 뭔가요? 단순히 멈춰주는 역할을 하신다고 설명만 하셨는데, 어차피 PlusValue는 스코어가 변경되고 나면 자동적으로 멈추는 걸로 생각하고 있거든요. 제가 지금 살짝 코루틴의 개념이 다시 헷갈리기 시작하기도 해서 정확히 알고싶습니다.
  • 프로필사진 Prosto 2017.08.09 05:08 신고 안녕하세요.

    일단 이해하신 것과 같이 코루틴은 yield로 지연이 더 이루어지지 않고 함수 끝에 도달하면 종료되는 게 맞습니다!

    이 부분은 코루틴은 중복 호출이 가능하다는 점에 주목하시면 이해하시기 좋겠네요.
    (같은 함수가 여러 번 호출되어 동시에 진행이 가능합니다.)

    plusIng은 그 중복호출을 피하려고 넣어뒀습니다.

    만약 이미 코루틴에 진입하여 점수 카운팅 중인 상태에서 새롭게 점수 증가가 이루어져 또 카운팅을 해주고싶다면,
    현재 사용중이던 코루틴을 종료하고 새로 코루틴을 호출해주면 해당 지점부터 다시 카운팅이 시작될 것 입니다.

    plusIng을 사용하지 않으면 중복하여 코루틴이 실행되는 경우 카운팅이 의도한 바와 다르게 작동하겠죠?
  • 프로필사진 YUN 2018.02.04 23:32 관리자의 승인을 기다리고 있는 댓글입니다
댓글쓰기 폼