< Return to Video

The Unity Tutorial For Complete Beginners

  • 0:00 - 0:06
    안녕하세요, 제 이름은 Mark입니다.
    저는 수년동안 Unity같은 소프트웨어를 이용하여
  • 0:06 - 0:13
    게임을 만들고 싶었습니다. Unity는 "컵헤드" ,"네온 화이트",
    "튜닉";
  • 0:13 - 0:19
    "아우터 와일즈", "하스스톤", "파이어워치",
    심지어 포켓몬 다이다몬드 리메이크에도 사용되었습니다.
  • 0:19 - 0:26
    그런데 저는 항상 긴 튜토리얼 영상을 볼 때마다 잠이 오더군요
  • 0:26 - 0:31
    전 다른 사람이 하는걸 보면서 따라하는 것보다
    직접 시도해보는게 적성에 더 맞더라고요
  • 0:31 - 0:38
    그래서 작년에 3단계로 구성된 해결법을 만들었는데,
    꽤 효과가 좋았습니다
  • 0:38 - 0:45
    1. Unity의 기본'만' 배우기,
    2. 간단한 시험으로 기본 익히기,
  • 0:45 - 0:51
    3. 나머지는 게임을 만들면서 알아서 배우기.
    제가 해봤더니 정말로 되더군요!
  • 0:51 - 0:57
    다른 모바일 게임을 배끼는 것부터 시작해서,
    자석을 이용한 저만의 퍼즐 플랫포머 게임을;
  • 0:57 - 1:03
    만들기까지 1년정도 걸렸습니다
  • 1:03 - 1:09
    그런데 Unity같이 복잡한 소프트웨어의 기본을
    어떻게 배워야 하는지
  • 1:09 - 1:12
    의문점이 들겁니다
  • 1:12 - 1:15
    저는 대부분의 게임의 들어가는
    공통적인 요소를 리스트로 만들었습니다
  • 1:15 - 1:20
    캐릭터를 화면에 띄우는 방법;
  • 1:20 - 1:24
    캐릭터를 움직이게 하는 방법,
    뭔갈 생성하거나 없애는 방법;
  • 1:24 - 1:29
    캐릭터의 판정, 게임 오버, 애니매이션, 사운드 등등;
  • 1:29 - 1:34
    전 이 방법들을
    긴 튜토리얼 영상, Unity 문서;
  • 1:34 - 1:37
    검색, 그리고 수많은 시행착오를 겪으면서 배웠습니다
  • 1:37 - 1:42
    이 영상의 목적은 여러분이 그걸 겪지 않게 만드는 것입니다
  • 1:42 - 1:46
    이 영상은 제가 Unity를 배울 적에 봤다면
    좋았을 영상입니다
  • 1:46 - 1:52
    앞으로 40분동안 우리는 Unity를 이용해
    플래피 버드를 만들겁니다
  • 1:52 - 1:57
    플래피 버드를 만들고 싶어서가 아니라,
    플래피 버드를 만들려면
  • 1:57 - 2:02
    제가 아까 말한 요소인 뭔갈 생성하는 것부터
    게임 오버까지 전부 필요하기 때문입니다
  • 2:02 - 2:08
    이 튜토리얼에서는 Unity 설치부터 UI 이해;
  • 2:08 - 2:14
    프로그래밍, 그리고 당신의 지인들과 공유할 수 있도록
    게임을 빌드하는 것까지 배우게 됩니다
  • 2:14 - 2:19
    그리고 튜토리얼이 끝난 후, 간단한 시험을 통해
    기본을 익히게 되고,
  • 2:19 - 2:26
    그 후로는 스스로 배우는게 가능해질겁니다
    괜찮은 것 같나요? 그렇다면 이제 시작하죠.
  • 2:27 - 2:34
    Unity를 다운받는 것부터 시작합시다.
    다운로드 후 Unity Hub를 설치하세요
  • 2:35 - 2:40
    Unity를 사용하려면 계정이 필요합니다.
    계정을 만든 후,
  • 2:40 - 2:46
    Unity 에디터 설치 창이 나올겁니다.
    설치하세요
  • 2:46 - 2:49
    *(이 영상에선 2021.3을 사용했지만,
    2022를 사용해도 상관없습니다)
  • 2:49 - 2:52
    *(설치 시 약 15분정도 걸립니다
    너무 오래 걸리면, Unity Hub를 관리자 권한으로 실행해보세요)
  • 2:52 - 2:59
    아직 끝난게 아닙니다. 옆에 톱니바퀴 아이콘을 누르고 모듈을 누르면
  • 3:00 - 3:05
    Visual Studio가 체크되어있는게 보일겁니다
    저희는 이 프로그램으로
  • 3:05 - 3:11
    코드를 작성할 겁니다
    Visual Studio를 설치한 후, 이 화면에서
  • 3:11 - 3:15
    아래로 스크롤하고
    "Unity를 활용한 게임 개발"은 체크하고, Unity Hub는 해제합니다
  • 3:15 - 3:20
    왜냐면 Hub는 이미 설치 되있으니까요.
    Visual Studio는 계정이 필요없으니 이건 스킵하고,
  • 3:20 - 3:24
    어차피 나중에 열거니 이 창은 닫아도 됩니다
  • 3:24 - 3:31
    이제 Unity Hub에서 '새 프로젝트'를 누르고,
    '모든 템플릿'을 선택하고 '2D 코어'를 선택합니다
  • 3:31 - 3:36
    '2D 코어'는 2D 게임을 만드는데 적합한
    빈 프로젝트입니다
  • 3:36 - 3:41
    이름을 정하고, '프로젝트 생성' 버튼을 누르세요
  • 3:43 - 3:49
    첫번째로, 우리는 Unity의 UI를 배울겁니다
  • 3:49 - 3:52
    다른 패널들을 탐방하면서, 화면에 새를 띄울겁니다
  • 3:52 - 3:59
    이게 Unity의 기본 레이아웃입니다
    4개의 패널로 나뉘어져 있죠
  • 4:00 - 4:05
    아래에는 프로젝트 패널이 있습니다
    여기에는 게임에 들어가는 모든 요소가 포함됩니다
  • 4:05 - 4:13
    예를 들면 스프라이트, 사운드, 스크립트, 타일, 폰트 등이 있습니다
    이중 일부는 Unity에서 직접 만들거지만
  • 4:13 - 4:18
    다른 곳에서 파일을 드래그해도 됩니다
  • 4:18 - 4:23
    저는 포토샵에서 새와 파이프의 스프라이트를 만든 후
  • 4:23 - 4:28
    이걸 프로젝트에 드래그했습니다
    전 여러분이 스프라이트를 직접 만들면 좋겠지만
  • 4:28 - 4:32
    만약 그림을 잘 못그리겠다면
    설명에 에셋 다운로드 링크를 확인하세요
  • 4:32 - 4:39
    왼쪽에는 계층 구조 패널이 있습니다
    여기에는 현재 '장면'에 있는 것들이 포함되며
  • 4:39 - 4:43
    '장면'은 대부분의 게임에서 레벨의 역할을 합니다.
    우선 새를 만드는 것부터 시작합시다
  • 4:43 - 4:50
    계층 구조에서 빈 오브젝트 생성을 누르면
    빈 GameObject가 생성됩니다
  • 4:50 - 4:57
    GameObject는 투명한 컨테이너와 같습니다
    위치를 지정하거나 회전할 수 있고;
  • 4:57 - 5:03
    크기를 조절할수도 있습니다. 그리고
    컨테이너 안에 컴포넌트를 넣어 기능을 추가할 수 있죠
  • 5:03 - 5:08
    예를 들어, '스프라이트 렌더러' 컴포넌트를 넣으면
    GameObject에 이미지를 넣을 수 있죠
  • 5:08 - 5:13
    이 게임의 모든 것들은 '컴포넌트가 있는 GameObject'로
    구성되어 있습니다
  • 5:13 - 5:16
    새, 파이프, 심지어 UI와 카메라까지
  • 5:16 - 5:23
    이 모든 것들은 오른쪽의 인스펙터에서 관리할 수 있습니다
  • 5:23 - 5:28
    빈 GameObject를 선택한 후, 위에서 이름을 정할 수 있습니다
  • 5:28 - 5:35
    이름은 그냥 Bird라고 하죠
    그리고 Transform에서 위치, 기울기, 크기를 조절할 수 있습니다
  • 5:35 - 5:42
    이제 '컴포넌트 추가'를 누르고, Rendering을 누르고
    Sprite Renderer를 선택하세요
  • 5:42 - 5:46
    이걸 작동하게 하려면, 스프라이트를 선택해야 하는데,
    그냥 프로젝트 패널에서 새 이미지를
  • 5:46 - 5:50
    빈칸에 드래그하면, 그래픽이 생겼네요!
  • 5:50 - 5:53
    그래픽은 중앙에 있는 씬 패널에 나타납니다
  • 5:53 - 5:57
    씬에서는 현재 씬에 무엇이 있는지 볼 수 있고,
  • 5:57 - 6:02
    이 기능들을 이용하여 움직이거나 회전시킬 수 있습니다
  • 6:02 - 6:07
    이 섹션에는 '게임'이라는 탭이 있는데,
    여기선 게임을 실행할때 메인 카메라에서
  • 6:07 - 6:13
    어떻게 보이는지 확인할 수 있습니다
    그리고 여기에선 해상도나 화면비를 설정할 수 있습니다
  • 6:13 - 6:19
    다른 화면에서 어떻게 보이는지 알 수 있죠
    - 저는 1920x1080을 선택하겠습니다
  • 6:19 - 6:24
    새가 너무 많은 공간을 차지하네요
    새의 크기를 줄일 수도 있지만, 저희는
  • 6:24 - 6:30
    카메라를 축소할 겁니다. 카메라 또한
    계층 구조에 있는 GameObject이기에 이를 선택하면
  • 6:30 - 6:36
    Camera 컴포넌트에서 수치를 조절할 수 있습니다
    '크기'를 높이면 카메라가 축소됩니다
  • 6:36 - 6:39
    그리고 배경 색도 바꾸겠습니다.
    좋네요
  • 6:39 - 6:44
    이제 위에 있는 Play 버튼을 누르면
    세상에서 가장
  • 6:44 - 6:48
    지루한 게임이 시작됩니다
    네. 이제 덜 지루하게 만들어 보죠
  • 6:49 - 6:55
    잠깐 되돌아봅시다
    Unity에는 4개의 패널이 있고 그중 프로젝트에는 모든 요소가 들어가고,
  • 6:55 - 7:01
    계층 구조에는 현재 레벨에 있는 GameObject가 표시되고,
    인스펙터에는
  • 7:01 - 7:05
    GameObject를 마음대로 조절할 수 있고,
    씬에서는 레벨을 볼 수 있다.
  • 7:05 - 7:11
    그리고 GameObject는 Sprite Renderer같은
    컴포넌트를 담을 수 있는 투명한 컨테이너다.
  • 7:12 - 7:16
    두번째로, 저희는 더 많은 컴포넌트를 이용하여
  • 7:16 - 7:19
    새를 중력에 영향을 받는 물리 오브젝트로 만들고
  • 7:19 - 7:23
    코드를 이용하여 스페이스 바를 누를 떄마다
    새를 위로 날게 만들겁니다
  • 7:23 - 7:30
    이제 새에다가 Rigidbody2D 컴포넌트를 추가합시다.
  • 7:30 - 7:37
    이 컴포넌트는 새를 물리 오브젝트로 만들어 줍니다.
    그래서 Play 버튼을 누르면 새가 화면 밖으로 떨어집니다.
  • 7:37 - 7:42
    이 새가 다른 오브젝트와 상호작용하게 만들려면
    Collider가 필요합니다
  • 7:42 - 7:44
    Circle Collider 2D를 추가합시다
  • 7:44 - 7:50
    씬을 보면 초록색으로 된 선이 보입니다
    중심이 약간 안맞기 때문에;
  • 7:50 - 7:55
    오프셋을 조절해서 움직이겠습니다
    여기서 게임 디자인 팁을 주자면
  • 7:55 - 8:01
    Collider(판정)를 이미지보다 조금 작게 만들면
    플레이어가 파이프에 아주 살짝 닿았더라도
  • 8:01 - 8:05
    게임 오버가 되지 않기에
    빡센 느낌이 줄어들게 됩니다
  • 8:05 - 8:11
    마지막으로, 스크립트를 추가하겠습니다
    스크립트를 활용하면 사실상 나만의 컴포넌트를
  • 8:11 - 8:17
    만들 수 있게 되지만, 우리가 코드를 이용해서 직접 만들어야 합니다
    컴포넌트 추가에서 New Script를 선택하고,
  • 8:17 - 8:22
    이름은 BirdScript라고 하겠습니다.
    만든 후, 스크립트를 더블클릭하면
  • 8:22 - 8:27
    전에 설치한 Visual Studio가 열릴겁니다
  • 8:27 - 8:31
    프로그래밍의 세계에 온걸 환영합니다!
    너무 무섭게 생각하지 마세요;
  • 8:31 - 8:35
    천천히 설명해드릴 겁니다.
    저희는 C#으로 코드를 작성할겁니다
  • 8:35 - 8:41
    먼저 Start와 Update, 이 2개에 대해
    알아보겠습니다
  • 8:41 - 8:47
    Start는 (이 스크립트가 활성화 돼있으면) 처음으로 실행되는 코드이고,
  • 8:47 - 8:53
    단 한번만 실행됩니다.
    Update는 (이 스크립트가 활성화 돼있으면) 항상 실행되는 코드이고,
  • 8:53 - 8:57
    매 프레임마다 코드가 실행됩니다.
  • 8:58 - 9:03
    아무튼, 저희가 코드로 작성할 건
    - Unity로 다시 돌아가보면
  • 9:03 - 9:08
    컴포넌트에 있는 숫자들이나 텍스트를 마음대로 조절할 수 있죠
  • 9:08 - 9:13
    저희는 코드를 이용하여
    게임이 실행되는 동안 이것들을 조절할 겁니다
  • 9:13 - 9:18
    간단한 예시를 들자면
  • 9:18 - 9:25
    Start에 gameObject(오른쪽 위에 있는걸 의미함)를 치고,
    점[.]을 치면 리스트가 보일겁니다
  • 9:25 - 9:26
    *(리스트가 안보이면, Unity 위에 '창'->'패키지 관리자'->아래로 내려서 'Visual Studio Editor' 선택 후 설치
    그후 Unity 위에 '편집'->'환경 설정'->'외부 툴'->Visual Studio 선택 후 전부 체크하고 재실행)
  • 9:26 - 9:31
    이중 대부분은 인스펙터에 있는걸 나타냅니다
    예를 들면 정적(isStatic);
  • 9:31 - 9:39
    태그, 레이어, 이름이 있죠
    name을 선택하고, [=] 쓰고, 큰따옴표[" "]로
  • 9:39 - 9:45
    새의 이름을 넣으면 됩니다.
    마지막으로, 명령 끝엔 항상 세미콜론[;]이 있어야 합니다
  • 9:45 - 9:50
    그리고 스크립트를 저장하는것도 잊지 마세요
  • 9:50 - 9:54
    이제 게임을 실행하면... GameObject의 이름이
    바뀌였네요. 좋습니다
  • 9:55 - 9:59
    네, 이제 그 코드는 지우세요.
    방금 쓴 코드는 우리가 코드로
  • 9:59 - 10:03
    게임과 대화할 수 있다는 걸 알려줍니다
    저희는 코드를 작성하여 누구와 대화할지
  • 10:03 - 10:08
    대상을 정할 수 있고, 대화의 주제도 정하고,
  • 10:08 - 10:14
    그 후 명령을 정할 수 있습니다
    저희는 이 짓을 많이 하게 될겁니다.
  • 10:15 - 10:20
    아무튼 저희가 진짜로 해야할 일은,
    Rigidbody2D 컴포넌트에서 Info 아래에 보면
  • 10:20 - 10:23
    Velocity가 회색으로 표시된게 보일겁니다
  • 10:23 - 10:27
    저희는 위쪽으로 Velocity를 주는 코드를 작성해서
    새가 하늘로 날 수 있게 만들겁니다
  • 10:27 - 10:33
    문제는, 이 스크립트는 GameObject의
    윗부분과 Transform끼리만 대화할 수 있고
  • 10:33 - 10:37
    다른 컴포넌트의 존재도 모릅니다
  • 10:37 - 10:42
    그래서 이 스크립트에 RigidBody2D를 위한 공간을 만들어야 합니다
  • 10:42 - 10:48
    그러면 대화를 할 수 있게 되고 명령을 보낼 수 있게 되며
    이를 '레퍼런스'라 부릅니다
  • 10:48 - 10:52
    Class와 Start 사이에 레퍼런스를 작성할 겁니다:
  • 10:52 - 10:58
    public RigidBody2D myRigidBody;
  • 11:01 - 11:06
    이제 RigidBody2D를 보관할 공간이 생겼고,
    다른 Rigidbody2D와 구분하기 위해
  • 11:06 - 11:12
    공간의 이름도 정했습니다
    public으로 정했기 때문에 스크립트 밖에서도
  • 11:12 - 11:18
    공간을 건드릴 수 있습니다
    저장하고 Unity로 돌아가면, 스크립트 컴포넌트에
  • 11:18 - 11:25
    RigidBody2D를 위한 공간이 생긴걸 볼 수 있습니다
    이제 RigidBody2D 컴포넌트를 빈칸에 드래그하면,
  • 11:25 - 11:29
    이제 스크립트와 RigidBody간의 통신선이 생겼습니다.
  • 11:29 - 11:36
    다시 Visual Studio로 돌아와서, Update에
    myRigidBody 그리고 점[.]을 치면
  • 11:36 - 11:40
    이 많은 대화 주제들을 보세요
    angularDrag, gravityScale, mass;
  • 11:40 - 11:46
    이것들이 전부 RigidBody2D에 있는 속성들입니다
    우리가 원하는건 velocity죠
  • 11:46 - 11:51
    전에 했던 것처럼 [=]을 쓰고,
  • 11:51 - 11:57
    여기에서는 Vector라는 2D 공간에서 위치를 나타내는
    값을 이용할 겁니다
  • 11:57 - 12:02
    여기서 Vector는 새가 나는 방향을 나타내는데 사용할겁니다
  • 12:02 - 12:09
    저희는 새가 위로 나는걸 원하기 때문에,
    (0,1)이 좋겠네요. 저는 Vector2.up을 이용할 겁니다
  • 12:09 - 12:14
    *Vector2.up은 Vector2(0,1)과 같은 의미입니다
    그리고 힘을 주려면
  • 12:14 - 12:20
    Vector에 힘을 곱하면 됩니다
    힘은 대충 10 정도면 충분할 겁니다
  • 12:20 - 12:25
    그리고, 전에 말했지만, Update 안에 있는 코드는
    매 프레임마다 실행되기 때문에
  • 12:25 - 12:32
    저장하고 플레이 해보면... 영원히 날아갑니다
  • 12:32 - 12:36
    하지만 저희가 원하는건 스페이스 바를 누를 때만
    새가 날아가게 하는 것이죠
  • 12:36 - 12:41
    이제 프로그래밍에서 가장 중요한 요소를 사용할 때입니다:
    바로 if 입니다.
  • 12:41 - 12:43
    if는 마치 관문과도 같습니다
  • 12:43 - 12:48
    게임이 특정 조건을 만족하지 못한다면,
    매 프레임마다 그 코드는 완전히 무시됩니다
  • 12:48 - 12:52
    반대로, 관문에 적혀 있는 특정 조건을 만족한다면,
  • 12:52 - 12:57
    통과할 수 있게 되고 코드가 실행됩니다.
  • 12:57 - 13:01
    저희가 원하는건 "만약 플레이어가 스페이스 바를 누르면,
    위쪽으로 velocity를 더한다"죠
  • 13:01 - 13:06
    if를 적고 괄호 안에 조건을 적으면 됩니다
  • 13:06 - 13:12
    여기서는 컴포넌트와 대화하는게 아니라 Unity와 대화하게 됩니다
    정확히는 Unity의 인풋 시스템이죠
  • 13:12 - 13:20
    (Input.GetKeyDown, 그리고 괄호 안에 KeyCode.Space)
    이렇게 하면 Unity에게
  • 13:20 - 13:25
    이 프레임에 스페이스를 눌렀는지 물어볼 수 있습니다
    그리고 마지막에 ==true 로 마무리합시다
  • 13:25 - 13:31
    참고로 등호를 1개[=] 만 사용하면
    왼쪽에 있는 걸
  • 13:31 - 13:35
    오른쪽과 같게 만들라는 의미이고,
    2개[==]를 사용하면 왼쪽에 있는게 오른쪽에 있는것과 같은지
  • 13:35 - 13:39
    여부를 확인하라는 의미입니다.
    괜찮죠?
  • 13:39 - 13:44
    아무튼, "만약 스페이스가 눌리면..."
  • 13:44 - 13:49
    그 후는 중괄호{}를 사용해야 합니다.
    중괄호 안에 위로 velocity를 주는 코드를 쓰면 됩니다
  • 13:50 - 13:54
    이제 Update에서 - 매 프레임마다 게임이 관문에 가서
  • 13:54 - 13:59
    "스페이스가 눌렸니?"라는 질문을 받은 후, 만약 맞다면
    코드가 실행되고 새는 날게 되겠죠, 아니라면
  • 13:59 - 14:03
    중괄호 안에 있는 코드는 무시하고,
    다음 프레임에 다시 시도하게 될겁니다
  • 14:03 - 14:08
    이제 저장하고 Unity로 돌아와서 플레이해보면, 짜잔:
  • 14:08 - 14:11
    이제 스페이스를 누를 때마다 새가 위로 올라가네요
  • 14:11 - 14:17
    이제 저희는 Input에 반응하는 캐릭터를 만들었습니다.
    이것은 게임입니다. 좋아요!
  • 14:17 - 14:23
    그런데, 조작감이 좀 쓰레기같네요
    원작 플래피 버드와는 전혀 다른 느낌입니다
  • 14:23 - 14:32
    그러니 숫자를 좀 바꿔볼까요
    저장, 플레이, 그래도 별로네, 정지, 숫자 번경;
  • 14:32 - 14:37
    저장,... 그런데 이건 너무 느리고 바보같네요
    덜 바보같은 짓을 해봅시다
  • 14:37 - 14:42
    먼저, 함수를 만들겁니다. 스크립트의 윗부분의
    RigidBody 레퍼런스 바로 밑에
  • 14:42 - 14:47
    public float flapStrength를 만듭시다
  • 14:47 - 14:52
    float란 부동소수점(floating point number)를 뜻합니다.
    간단히 말하면 소수점이 있는 숫자라는 의미입니다
  • 14:52 - 14:58
    다시 Update로 돌아와서, Vector2.up에 10이 아니라
    flapStrength를 곱할겁니다
  • 14:58 - 15:02
    이제 스크립트 컴포넌트를 보면 새로운 공간이 보일겁니다:
  • 15:02 - 15:07
    Flap Strength. 그리고 이건 언제든지 번경할 수 있습니다;
  • 15:07 - 15:11
    심지어 플레이 중에도 번경할 수 있습니다
    참고로 플레이 중 번경한 값은
  • 15:11 - 15:15
    저장되지 않기 때문에,
    게임의 중요한 요소를 다룰 때에도
  • 15:15 - 15:19
    아무 숫자나 막 집어넣어도 상관없습니다
  • 15:19 - 15:23
    그래서, flapStrength와 RigidBody의 중력 스케일이나
  • 15:23 - 15:27
    질량을 적당히 조절하다 보면 언젠가는
    좋은 값을 찾을 수 있을 겁니다
  • 15:27 - 15:30
    숫자 계속 바꾸기,
    이게 게임 디자인이죠
  • 15:30 - 15:31
    잠깐 되돌아봅시다
  • 15:31 - 15:36
    코드를 활용하여 플레이 중에도 컴포넌트의 속성을 바꿀 수 있다.
  • 15:36 - 15:41
    스크립트는 기본적으로 gameObject에 있는 다른 컴포넌트들과
    대화할 수 없고, 할려면
  • 15:41 - 15:45
    원하는 컴포넌트의 레퍼런스(공간)를 만들어야 한다.
  • 15:45 - 15:50
    레퍼런스(공간)는 코딩으로 만들고, 빈 공간은 Unity에서
    드래그 앤 드롭으로 채운다
  • 15:50 - 15:56
    Start에 있는 코드는 (스크립트가 존재할 때) 한번만 실행되고
    Update에 있는 코드는
  • 15:56 - 16:02
    매 프레임마다 계속 실행된다. 하지만 if를 사용하여
    조건 미충족시 코드를 스킵할 수도 있다
  • 16:02 - 16:05
    그리고 public을 사용하면
    *(팁: [SerializeField]를 사용하면 private여도 Unity에서 값 바꿀수 있음)
  • 16:05 - 16:08
    Unity의 인스펙터에서 값을 바꿀 수 있다.
    *(팁: [SerializeField]를 사용하면 private여도 Unity에서 값 바꿀수 있음)
  • 16:09 - 16:14
    플래피 버드의 비밀을 하나 말씀드리자면
  • 16:14 - 16:18
    새가 파이프를 지나는 것처럼 보이지만
  • 16:18 - 16:24
    새는 가만히 있고 파이프가 움직이는 겁니다
    그래서 이번에는
  • 16:24 - 16:29
    파이프 생성, 그리고 파이프를 움직이게 하고
    없애는것까지 배울겁니다
  • 16:29 - 16:32
    우선 생성할 오브젝트를 만듭시다
  • 16:32 - 16:35
    오른쪽에서 왼쪽으로 가는 파이프 2개를요
  • 16:35 - 16:40
    빈 오브젝트를 만들고, 이름은 pipe로 합시다
    일단은 파이프 크기를 맞추기 위해
  • 16:40 - 16:45
    새 중앙에 놓겠습니다.
    그 다음 pipe 안에 빈 오브젝트를 만들고
  • 16:45 - 16:51
    이름은 top pipe로 하겠습니다
    이런 걸 GameObject의 "자식"(child) 이라고 합니다
  • 16:51 - 16:55
    자식을 이용하면 GameObejct 여러 개를 한 곳에 모와,
    "부모"를 움직이면 자식도 함께 움직이게 할 수 있습니다
  • 16:56 - 17:00
    새를 만들 때 했었던 짓을 또 하겠습니다
    이미지를 넣기 위해 Sprite Renderer를 추가하고
  • 17:01 - 17:07
    판정을 위해 Box Collider 2D를 넣겠습니다
    Rigidbody는 필요 없습니다
  • 17:07 - 17:13
    물리의 영향을 받을 필요가 없으니까요.
    파이프를 위로 올리겠습니다 - 단, X좌표는 0으로 하세요
  • 17:13 - 17:19
    그 후, 이걸 복사하고
    이름을 bottom pipe로 바꾼 후,
  • 17:19 - 17:24
    180도 회전하고 아래로 내리겠습니다
  • 17:24 - 17:31
    여기서 부모 GameObject를 움직여 보면,
    파이프 2개가 부모를 중심으로
  • 17:31 - 17:35
    동시에 움직이는걸 볼 수 있습니다
  • 17:35 - 17:39
    이제 움직이게 하기 위해
    부모에 스크립트를 추가하겠습니다
  • 17:41 - 17:46
    우선 이동 속도를 위한 변수를 하나 만듭시다
    여기에 값을 부여하면,
  • 17:46 - 17:51
    Unity에서 그 값이 기본으로 설정됩니다
    물론 Unity에서 언제든지 바꿀 수 있긴 합니다
  • 17:51 - 17:56
    이제 Update에 오브젝트를 움직이는 코드를 작성합시다
    여기서
  • 17:56 - 18:03
    그냥 transform.position.x로 할 수 있다면 좋겠지만
    아쉽게도 안됩니다
  • 18:03 - 18:09
    Vector 전체를 한번에 바꿔야 합니다
    그리고 이번엔 Vector2 대신 Vector3를 쓸 겁니다
  • 18:09 - 18:15
    transform은 값 3개가 필요하기 때문이죠
    이 게임은 2D이긴 하지만
  • 18:15 - 18:20
    Unity는 근본적으로 3D 엔진이기 때문에
    오브젝트의 Z값도 필요합니다
  • 18:21 - 18:26
    아무튼, 움직이게 하려면
    현재 위치에다가 다른걸 더해야 하기 떄문에
  • 18:26 - 18:31
    transform.position = transform.position +
  • 18:31 - 18:37
    그 후 괄호 안에 Vector3.left * moveSpeed;
  • 18:39 - 18:44
    Unity로 돌아와서, 플레이를 누르면
    너무 빠르네요
  • 18:44 - 18:48
    그냥 moveSpeed에 엄청 작은 값,
  • 18:48 - 18:53
    예를 들어 0.001을 넣어도 되긴 하지만
    문제의 근본적인 원인은 그게 아닙니다
  • 18:53 - 18:59
    Update에 있는 코드는 가능한 한 많이 실행됩니다
    게임 뷰에서 통계를 보면;
  • 18:59 - 19:03
    게임이 초당 1000프레임으로 구동되고 있는게 보이네요
  • 19:03 - 19:08
    플레이스테이션 5에게 미안해지네요,
    120프레임? 플래피 버드에겐 잽도 안되는군요
  • 19:08 - 19:12
    아무튼 이게 중요한 이유는,
    컴퓨터 사양에 따라 게임이 다른 속도로 구동될 가능성이 있다는 겁니다
  • 19:12 - 19:16
    컴퓨터 사양에 따라 파이프 속도가 달라지면 안돼죠
  • 19:16 - 19:23
    시장에 있는 게임에도 이런 실수가 종종 보입니다 -
    다크 소울 2에선, 무기 내구도가 프레임과
  • 19:23 - 19:31
    연관되어 있어서 60프레임에선 30프레임보다
    내구도가 2배 빨리 닳았습니다
  • 19:31 - 19:36
    해결법은 간단합니다
    그냥 Time.deltaTime을 곱하면 됩니다
  • 19:36 - 19:41
    이러면 프레임에 상관 없이 움직임이 일정한 간격으로 발생합니다
  • 19:41 - 19:45
    Rigidbody에 이게 없어도 됐던 이유는
    물리와 관련된 건 타이머가 내장되어 있기 때문이였고,
  • 19:45 - 19:49
    그 외 상황에는 필요합니다.
    이거(혹은 다른거 뭐든지)에 대해 알고 싶다면,
  • 19:49 - 19:54
    Unity 사용자 매뉴얼을 확인해보세요
    정보와 샘플 코드도 있습니다
  • 19:54 - 19:59
    아무튼, 이제 파이프가 부드럽게 움직이네요
    좋습니다
  • 19:59 - 20:05
    다음으로, 파이프가 무한히 생성되는 시스템을 만들겠습니다
  • 20:05 - 20:11
    우선 계층 구조에 있는 부모 GameObject를 프로젝트에 드래그하세요
  • 20:11 - 20:17
    이러면 프리팹이 생성됩니다
    프리팹은 이 GameObject 전체의 설계도와도 같죠
  • 20:17 - 20:22
    그리고 프리팹을 이용하면
    이 GameObject들의 바리에이션을 만들기 쉬워집니다
  • 20:22 - 20:26
    프리팹을 만들었으면, 계층 구조에 있는건 지워도 됩니다.
  • 20:26 - 20:29
    이제 새로운 빈 오브젝트를 만들고
    이름을 PipeSpawner로 지읍시다
  • 20:31 - 20:36
    카메라 영역 오른쪽에 놓고,
    이제 스크립트를 만듭시다
  • 20:36 - 20:42
    스크립트에는 매초마다 파이프 프리팹의 새로운 바리에이션을
    생성하는 코드를 작성할겁니다 - 파이프가 왼쪽으로 움직이는건
  • 20:42 - 20:47
    이미 전에 했기 덕분에, 파이프가 생성되면 자동으로 왼쪽으로 움직일겁니다
  • 20:47 - 20:51
    방금 전에 만든 프리팹을 소환하는 코드를 작성할겁니다
  • 20:51 - 20:54
    일단 프리팹의 레퍼런스부터 만들겠습니다
  • 20:54 - 20:59
    여기에 public GameObject pipe; 를 작성합니다
  • 20:59 - 21:04
    그 후 Unity에서 빈칸을 드래그로 채울겁니다.
    이 빈칸은
  • 21:04 - 21:08
    컴포넌트로 채우는게 아니라, 프리팹으로 채워야 합니다
  • 21:08 - 21:12
    Unity에는 새로운 GameObject를 생성하는 기능이 내장되어 있기에
  • 21:12 - 21:18
    그걸 써먹으려면, Instantiate, 그리고 괄호를 열면
  • 21:18 - 21:23
    뭔가 자세히 입력하라고 뜨네요
    화살표를 눌러 이 레시피? 같은걸 넘기다
  • 21:23 - 21:28
    보면 - 4번이 좋아보이는군요
    특정한 좌표와 기울기를 가진 GameObject를 생성한다고 하네요
  • 21:28 - 21:33
    생성할 GameObject는 pipe고; 좌표는
  • 21:33 - 21:38
    transform.position을 사용하면 이 스크립트가 달린 오브젝트의
  • 21:38 - 21:42
    좌표를 구할 수 있기에 그걸 쓰면 되고,
    기울기는
  • 21:42 - 21:47
    같은 원리로 transform.rotation을 쓰면 됩니다
  • 21:48 - 21:53
    플레이 해보면, 맙소사 너무 많이 소환되네요
    소환은 되는데
  • 21:53 - 21:56
    매 프레임마다 소환되고 있습니다
  • 21:56 - 22:00
    작당한 간격을 두고 소환되게 만듭시다
    - Visual Studio로 돌아와서
  • 22:00 - 22:05
    타이머를 만들겁니다
  • 22:05 - 22:10
    타이머가 끝나면, 코드 실행,
    타이머, 같은 식으로요
  • 22:10 - 22:15
    일단 변수 몇개를 만들어야 합니다
    spawnRate는 소환 간 간격을
  • 22:15 - 22:20
    나타내고, timer는 말 그대로 타이머입니다
  • 22:20 - 22:23
    timer는 private로 작성할 겁니다
    왜냐면 다른 스크립트에서도 timer를 쓰면 혼동이 오니까요
  • 22:23 - 22:29
    Update에는, if를 작성할겁니다
    만약 timer가 spawnRate보다 작다면:
  • 22:29 - 22:35
    timer를 1만큼 올릴겁니다
    그럴려면
  • 22:35 - 22:40
    현재 timer에 time.deltaTime을 더하면 됩니다
    이러면 매 프레임마다 timer가 올라가고
  • 22:40 - 22:43
    컴퓨터 사양에 상관없이 타이머가 일정하게 올라갑니다
  • 22:43 - 22:48
    이 과정은 += 로 줄일 수 있지만,
    다른 사람한데 꼽사리 안받으려고
  • 22:48 - 22:53
    코드 분량을 이 악물고 줄일 필요는 없습니다
  • 22:53 - 22:58
    만약 timer = timer + ~ 가 읽기 더 편하다면
    그렇게 쓰면 됩니다
  • 22:58 - 23:02
    나중에 생각이 바뀌더라도 그냥 바꾸면 되니까요
  • 23:02 - 23:05
    아무튼, 제가 전에 if는 관문과도 같단 말을 했었죠
  • 23:05 - 23:10
    else를 이용하면 관문 옆에 또다른 관문을 만들 수 있습니다
  • 23:10 - 23:15
    즉, if 조건을 만족하지 못하면 else에 있는 조건을 시도합니다
  • 23:15 - 23:23
    이제 else 안에 파이프 생성 코드를 쓰고,
    timer를 0으로 리셋하는 코드도 쓰겠습니다. 이제 매 프레임마다
  • 23:23 - 23:28
    timer가 spawnRate보다 작은지 확인하고,
    만약 맞다면, timer 증가, 아니라면, 즉
  • 23:28 - 23:33
    timer가 생성 주기와 같거나 높으면,
    파이프를 생성하고 timer를 0으로 리셋.
  • 23:33 - 23:39
    저장하고 플레이하면 - 잘 되네요
    근데 한가지 문제점은,
  • 23:39 - 23:44
    첫 파이프가 생성될때까지 한참 기다려야 된다는 점입니다
    파이프가 시작하자마자 나오면 좋을텐데요
  • 23:44 - 23:50
    파이프 생성 코드를 Start에 복붙하면,
    시작하자마자 파이프가 나올겁니다
  • 23:50 - 23:55
    그런데 이런 식으로 코드 전체를 복붙하는건 좋은 습관이 아닙니다
  • 23:55 - 24:01
    게임을 만들 때는, 똑같거나 비슷한 코드를 온갖곳에 두는건
    피해야 합니다. 이유를 말하자면,
  • 24:01 - 24:06
    예를 들어 파이프 스폰 방식을 바꾸고 싶다고 하면
    온갖곳에 있는 코드를 전부 일일히 바꿔야 할겁니다
  • 24:06 - 24:10
    대신, 그 코드를 새로운 함수(function)에 넣고,
    그 함수를 실행하면 됩니다
  • 24:10 - 24:15
    Update 밑에, 마지막 중꽐호 위에,
  • 24:15 - 24:21
    void spawnPipe()라는 함수를 만들고,
    파이프 생성 코드를 안에 넣으면 되죠
  • 24:21 - 24:28
    이제 원래 그게 있던 자리에 spawnPipe()만 넣으면 됩니다
  • 24:28 - 24:32
    이제 spawnPipe()라는 코드가 실행될 때마다
    아래에 있는 함수가 실행됩니다
  • 24:32 - 24:38
    잘 되는지 확인해보면,
    처음 시작할때 파이프 나오고, 타이머 지날때마다 생성되네요. 좋습니다
  • 24:39 - 24:45
    그런데, 파이프가 항상 중간에 나오니
    게임이 너무 단조롭네요
  • 24:45 - 24:49
    파이프의 높이가 랜덤하게 나왔으면 좋겠는데;
    파이프 생성 코드가 어떻게 되있었는지 기억나시나요?
  • 24:49 - 24:53
    오브젝트의 생성 좌표를 지정할 수 있었던거 기억나나요?
    그 값을 바꿉시다
  • 24:53 - 24:58
    현재는 파이프가 항상 같은 좌표에 생성되고 있죠
  • 24:58 - 25:04
    X좌표는 같아도 되니 냅두고, Y는...
    PipeSpawner 위 혹은 아래에 랜덤하게 생성되면 좋겠네요
  • 25:04 - 25:09
    우선 heightOffset이라는 public 변수를 만듭시다
    값은 10정도로 하죠
  • 25:09 - 25:14
    그리고 이 안에 lowestPoint라는 float를 만들겁니다
    함수 안에서 변수를 만들고 있기에,
  • 25:14 - 25:20
    이 변수는 이 함수 안에서만 사용 가능합니다
  • 25:20 - 25:22
    또한, ???
  • 25:22 - 25:30
    일단 lowestPoint = transform.position.y - heightOffset
    그리고
  • 25:30 - 25:37
    highestPoint도 만들겁니다
    lowest와 같지만 - 대신 +를 넣으면 됩니다. 숫자 2개가 만들어졌으니
  • 25:38 - 25:41
  • 25:41 - 25:47
  • 25:47 - 25:54
  • 25:54 - 25:59
  • 25:59 - 26:05
  • 26:05 - 26:12
  • 26:14 - 26:20
  • 26:20 - 26:25
  • 26:25 - 26:30
  • 26:30 - 26:35
  • 26:35 - 26:40
  • 26:40 - 26:45
  • 26:45 - 26:51
  • 26:51 - 26:58
  • 26:58 - 27:06
  • 27:06 - 27:13
  • 27:16 - 27:19
  • 27:19 - 27:24
  • 27:24 - 27:33
  • 27:33 - 27:39
  • 27:39 - 27:45
  • 27:45 - 27:50
  • 27:52 - 27:53
  • 27:53 - 27:56
  • 27:56 - 27:59
  • 27:59 - 28:04
  • 28:04 - 28:09
  • 28:09 - 28:13
  • 28:13 - 28:17
  • 28:17 - 28:22
  • 28:22 - 28:27
  • 28:27 - 28:31
  • 28:32 - 28:36
  • 28:36 - 28:39
  • 28:39 - 28:43
  • 28:43 - 28:47
  • 28:47 - 28:53
  • 28:53 - 28:58
  • 28:58 - 29:01
  • 29:01 - 29:07
  • 29:07 - 29:12
  • 29:12 - 29:17
  • 29:17 - 29:22
  • 29:22 - 29:28
  • 29:28 - 29:34
  • 29:34 - 29:40
  • 29:40 - 29:45
  • 29:47 - 29:49
  • 29:49 - 29:53
  • 29:53 - 29:57
  • 29:57 - 30:00
  • 30:00 - 30:03
  • 30:04 - 30:09
  • 30:09 - 30:14
  • 30:14 - 30:18
  • 30:18 - 30:23
  • 30:23 - 30:28
  • 30:28 - 30:30
  • 30:30 - 30:35
  • 30:35 - 30:41
  • 30:41 - 30:46
  • 30:46 - 30:52
  • 30:52 - 30:59
  • 30:59 - 31:05
  • 31:05 - 31:10
  • 31:10 - 31:16
  • 31:16 - 31:20
  • 31:20 - 31:25
  • 31:26 - 31:31
  • 31:31 - 31:39
  • 31:39 - 31:46
  • 31:46 - 31:52
  • 31:53 - 31:57
  • 31:57 - 32:03
  • 32:05 - 32:10
  • 32:11 - 32:14
  • 32:15 - 32:19
  • 32:19 - 32:23
  • 32:23 - 32:28
  • 32:28 - 32:33
  • 32:33 - 32:38
  • 32:38 - 32:42
  • 32:42 - 32:45
  • 32:45 - 32:51
  • 32:51 - 32:56
  • 32:56 - 33:01
  • 33:01 - 33:06
  • 33:06 - 33:14
  • 33:14 - 33:19
  • 33:19 - 33:26
  • 33:26 - 33:30
  • 33:30 - 33:34
  • 33:34 - 33:41
  • 33:41 - 33:46
  • 33:46 - 33:51
  • 33:51 - 33:57
  • 33:57 - 34:01
  • 34:01 - 34:06
  • 34:06 - 34:08
  • 34:08 - 34:13
  • 34:13 - 34:17
  • 34:17 - 34:24
  • 34:24 - 34:30
  • 34:30 - 34:35
  • 34:35 - 34:37
  • 34:37 - 34:47
  • 34:47 - 34:51
  • 34:51 - 34:54
  • 34:54 - 34:58
  • 34:58 - 35:02
  • 35:03 - 35:09
  • 35:09 - 35:14
  • 35:14 - 35:19
  • 35:19 - 35:23
  • 35:23 - 35:28
  • 35:29 - 35:34
  • 35:35 - 35:41
  • 35:41 - 35:47
  • 35:47 - 35:53
  • 35:53 - 35:58
  • 35:58 - 36:04
  • 36:04 - 36:11
  • 36:11 - 36:15
  • 36:15 - 36:20
  • 36:23 - 36:27
  • 36:27 - 36:33
  • 36:33 - 36:39
  • 36:39 - 36:45
  • 36:45 - 36:50
  • 36:50 - 36:55
  • 36:55 - 36:59
  • 36:59 - 37:03
  • 37:03 - 37:07
  • 37:07 - 37:13
  • 37:13 - 37:14
  • 37:14 - 37:18
  • 37:18 - 37:23
  • 37:23 - 37:26
  • 37:26 - 37:30
  • 37:30 - 37:34
  • 37:34 - 37:37
  • 37:37 - 37:42
  • 37:42 - 37:47
  • 37:47 - 37:51
  • 37:51 - 37:57
  • 37:57 - 37:59
  • 38:01 - 38:07
  • 38:07 - 38:11
  • 38:11 - 38:16
  • 38:17 - 38:21
  • 38:21 - 38:28
  • 38:31 - 38:37
  • 38:37 - 38:42
  • 38:43 - 38:48
  • 38:48 - 38:54
  • 38:54 - 38:59
  • 39:00 - 39:02
  • 39:02 - 39:07
  • 39:07 - 39:12
  • 39:12 - 39:18
  • 39:18 - 39:23
  • 39:24 - 39:30
  • 39:30 - 39:35
  • 39:35 - 39:43
  • 39:45 - 39:48
  • 39:49 - 39:53
  • 39:57 - 40:03
  • 40:03 - 40:08
  • 40:08 - 40:12
  • 40:13 - 40:16
  • 40:16 - 40:23
  • 40:23 - 40:28
  • 40:28 - 40:30
  • 40:31 - 40:39
  • 40:39 - 40:42
  • 40:42 - 40:48
  • 40:48 - 40:53
  • 40:53 - 40:58
  • 40:58 - 41:03
  • 41:03 - 41:10
  • 41:10 - 41:16
  • 41:16 - 41:21
  • 41:21 - 41:28
  • 41:28 - 41:34
  • 41:34 - 41:38
  • 41:39 - 41:44
  • 41:44 - 41:49
  • 41:49 - 41:54
  • 41:54 - 42:01
  • 42:01 - 42:06
  • 42:06 - 42:11
  • 42:11 - 42:17
  • 42:17 - 42:24
  • 42:24 - 42:32
  • 42:32 - 42:35
  • 42:35 - 42:40
  • 42:40 - 42:44
  • 42:44 - 42:49
  • 42:49 - 42:54
  • 42:54 - 42:56
  • 42:56 - 43:00
  • 43:00 - 43:05
  • 43:05 - 43:10
  • 43:10 - 43:16
  • 43:16 - 43:21
  • 43:21 - 43:28
  • 43:28 - 43:32
  • 43:32 - 43:37
  • 43:37 - 43:41
  • 43:41 - 43:44
  • 43:44 - 43:48
  • 43:48 - 43:52
  • 43:52 - 43:55
  • 43:55 - 44:00
  • 44:00 - 44:06
  • 44:06 - 44:11
  • 44:11 - 44:16
  • 44:16 - 44:19
  • 44:19 - 44:23
  • 44:23 - 44:26
  • 44:26 - 44:31
  • 44:31 - 44:35
  • 44:35 - 44:41
  • 44:41 - 44:45
  • 44:45 - 44:49
  • 44:49 - 44:53
  • 44:53 - 44:58
  • 44:58 - 45:03
  • 45:03 - 45:08
  • 45:08 - 45:12
  • 45:12 - 45:15
  • 45:15 - 45:19
  • 45:19 - 45:21
  • 45:21 - 45:26
  • 45:26 - 45:31
  • 45:31 - 45:35
  • 45:35 - 45:39
  • 45:39 - 45:46
  • 45:46 - 45:52
  • 45:52 - 45:55
  • 45:55 - 45:59
  • 45:59 - 46:04
  • 46:04 - 46:10
  • 46:10 - 46:14
  • 46:14 - 46:17
  • 46:17 - 46:22
  • 46:22 - 46:25
  • 46:25 - 46:31
Title:
The Unity Tutorial For Complete Beginners
Description:

more » « less
Video Language:
English
Duration:
46:39

Korean subtitles

Incomplete

Revisions Compare revisions