1 00:00:23.663 --> 00:00:25.298 안녕하세요 이영훈입니다 2 00:00:25.942 --> 00:00:32.106 이번 시간에는 적 생성과 AI 제어를 위한 FSM을 제작해 볼텐데요 3 00:00:32.493 --> 00:00:35.678 이번 단원에서는 적 액터를 생성하고 4 00:00:35.906 --> 00:00:39.025 적의 AI 제어를 위한 유한상태기계 5 00:00:39.223 --> 00:00:42.969 즉 FSM 기반으로 각 상태를 구분하고 6 00:00:43.375 --> 00:00:47.731 상태별로 기능을 구현하는 방법에 대해 학습하겠습니다 7 00:00:47.989 --> 00:00:52.416 먼저 적 액터를 생성하고 외관을 적용해 보겠습니다 8 00:00:52.990 --> 00:00:56.772 적 액터 생성 및 FSM 기반의 상태 구분 9 00:00:57.495 --> 00:00:59.755 먼저 적 클래스를 만들어 보도록 할게요 10 00:01:01.240 --> 00:01:06.776 Tools에서 C 클래스를 만들고 캐릭터로 만들겠습니다 11 00:01:07.360 --> 00:01:10.749 Next라고 하시고 Enemy라고 할게요 12 00:01:28.383 --> 00:01:32.750 Enemy에는 먼저 외관이나 충돌체 이런 것들을 지정을 해 줘야 되는데 13 00:01:32.750 --> 00:01:35.242 원래 캐릭터니까 기본적으로 14 00:01:36.786 --> 00:01:38.023 다 갖추고 있겠죠 15 00:01:38.023 --> 00:01:42.671 그래서 Mesh 부분만 우리가 설정을 해 주도록 하겠습니다 16 00:01:43.146 --> 00:01:48.589 들어와서 여기 캐릭터, 플레이어를 만들었을 때 어떻게 했는지 기억을 해보시면 17 00:01:49.916 --> 00:01:50.858 플레이어 보면 18 00:01:54.199 --> 00:01:59.560 Capsule, Mesh 그리고 Movement Comp, Arrow 19 00:01:59.560 --> 00:02:02.804 이렇게 네가지 컴포넌트가 미리 배치가 되어 있었어요 20 00:02:03.318 --> 00:02:09.649 거기에서 Mesh 컴포넌트에 이렇게 SKM Quinn을 넣어 줬는데 21 00:02:09.866 --> 00:02:12.000 똑같이 Quinn을 사용해 보도록 하겠습니다 22 00:02:12.000 --> 00:02:13.241 이거 복사를 하고요 23 00:02:14.142 --> 00:02:16.958 여기서 복사를 하셔도 돼요 복사하시고 24 00:02:19.037 --> 00:02:21.456 다시 클래스로 옵니다 25 00:02:22.080 --> 00:02:30.686 여기다가 문자열을 이렇게 해서 이 주소로 로드를 할 건데요 26 00:02:31.686 --> 00:02:39.111 그러면 여기에서는 메시 에셋을 로드해서 27 00:02:40.517 --> 00:02:44.226 메시에 적용하고 싶다 28 00:02:47.987 --> 00:02:50.088 이렇게 해 보도록 할게요 29 00:02:50.247 --> 00:02:55.449 이걸 하기 위해서 ConstructHelpers라는 것을 사용했죠 이렇게 하고 30 00:02:56.360 --> 00:02:58.354 Fobject finder를 사용합니다 31 00:02:58.354 --> 00:03:00.624 그리고 여기다가 꺾쇠 이렇게 넣어 주시고요 32 00:03:01.298 --> 00:03:05.346 이름은 TempMesh라고 하겠습니다 33 00:03:07.287 --> 00:03:09.293 여기다가 Text라고 작성을 하고요 34 00:03:11.144 --> 00:03:14.985 사실 여기 적은 내용을 여기다가 넣어 주면 되겠죠 35 00:03:16.925 --> 00:03:20.659 이렇게 해서 이렇게 로드를 할 수 있겠죠 36 00:03:22.887 --> 00:03:26.260 그리고 여기에 들어가는 것은 실제로 우리가 로드할 정보인 37 00:03:26.517 --> 00:03:30.011 SkeletalMesh를 이렇게 작성해 주시면 되고요 38 00:03:30.328 --> 00:03:31.456 U를 붙여야 됩니다 39 00:03:34.047 --> 00:03:37.039 로드를 했는지 성공했는지 확인을 하겠습니다 40 00:03:37.168 --> 00:03:42.787 만약에 TempMesh가 Success 성공을 했다면 41 00:03:46.240 --> 00:03:48.726 이것을 우리 GetMesh에다가 42 00:03:50.839 --> 00:03:51.988 반영을 해 주면 되겠죠 43 00:03:55.857 --> 00:03:59.873 이렇게 해서 SetSkeletalMesh해서 44 00:04:00.853 --> 00:04:05.198 TempMesh에 Object 이렇게 넣어 주시면 됩니다 45 00:04:07.307 --> 00:04:12.026 그리고 이 녀석의 위치를 이제 보정을 해 줄 건데요 46 00:04:12.550 --> 00:04:17.263 기본적으로 오른쪽을 바라보고 중앙 하단이 이 녀석의 중점이기 때문에 47 00:04:17.580 --> 00:04:21.150 밑으로 내려주고 그 다음에 회전도 시켜줬습니다 48 00:04:21.536 --> 00:04:22.897 이거는 동일한 일을 할게요 49 00:04:26.098 --> 00:04:35.242 GetMesh를 가져오고 여기에서 SetRelativeLocationAndRotation 함수 죠 50 00:04:35.401 --> 00:04:38.519 이 값을 세우겠습니다 Fvector 51 00:04:39.886 --> 00:04:41.915 그 다음에 FRotator 52 00:04:46.103 --> 00:04:47.547 얘는 0, 0, 90이고요 53 00:04:49.319 --> 00:04:50.323 -90이고요 54 00:04:51.977 --> 00:04:55.117 그리고 Rotator는 보시면은 55 00:04:56.226 --> 00:04:57.820 Pitch 이 롤 순서죠 56 00:04:57.820 --> 00:05:01.883 이것은 Pitch가 y라고 했어요 그리고 U가 z니까 57 00:05:02.467 --> 00:05:04.331 y, z, x 순서입니다 58 00:05:04.331 --> 00:05:09.119 그러니까 0, -90, 0 이렇게 넣어 줘야겠죠 59 00:05:15.843 --> 00:05:17.940 이렇게 설정을 해 주도록 할게요 60 00:05:23.959 --> 00:05:27.998 자 그리고 언리얼로 와서 컴파일 한번 해 주고요 61 00:05:27.998 --> 00:05:32.453 그 다음에 이제 Enemy를 블루프린트로 만들어서 확인해 보겠습니다 62 00:05:34.483 --> 00:05:35.087 이렇게 하고 63 00:05:39.017 --> 00:05:42.978 Enemy를 마우스 오른쪽 눌러서 Create Blueprint 해 주겠습니다 64 00:05:44.235 --> 00:05:47.586 블루프린트 폴더에 가서 BP_Enemy라고 하고요 65 00:05:50.658 --> 00:05:53.197 그러면 이렇게 잘 설정이 된 걸 볼 수가 있죠 66 00:05:54.702 --> 00:05:55.896 일단 컴파일을 해 줍니다 67 00:05:57.678 --> 00:05:59.918 그리고 Enemy를 레벨에 배치를 해 볼게dy 68 00:06:00.601 --> 00:06:04.448 Enemy는 플레이어를 바라보도록 180도 회전해 주겠습니다 69 00:06:09.087 --> 00:06:10.907 `이렇게 배치를 해 보고요 70 00:06:13.679 --> 00:06:14.670 실행을 해 볼까요? 71 00:06:16.135 --> 00:06:18.936 이렇게 해서 가까이 가면 이런 식으로 되고요 72 00:06:18.936 --> 00:06:21.898 총을 쏴 볼게요 그러면은 총dp 맞지 않습니다 73 00:06:21.898 --> 00:06:23.273 뚫고 나가죠 74 00:06:23.659 --> 00:06:26.550 그리고 카메라도 좀 이상해요 이렇게 돌려 보면은 75 00:06:26.946 --> 00:06:29.363 이렇게 됩니다 갑자기 훅 이렇게 오죠 76 00:06:29.818 --> 00:06:30.728 이건 왜 그러냐면 77 00:06:32.867 --> 00:06:33.480 이런 개념이에요 78 00:06:33.480 --> 00:06:35.555 두 가지인데 일단 총이 안 맞는 것은 79 00:06:37.110 --> 00:06:42.313 우리가 총을 쏠 때 Visibility라는 형태로 라인 트레이스를 쐈어요 80 00:06:42.669 --> 00:06:45.268 그래서 그 Trace channel response죠 81 00:06:45.268 --> 00:06:47.518 Trace response 속성을 한번 봐야 될 것 같고요 82 00:06:47.933 --> 00:06:51.748 그 다음에 두 번째는 카메라가 이렇게 회전을 한 다음에 83 00:06:51.748 --> 00:06:53.881 탁 갑자기 가까이 오게 되는데 84 00:06:54.168 --> 00:06:58.249 그것은 플레이어가 이렇게 있고 플레이어 카메라가 이렇게 있죠 85 00:06:58.804 --> 00:07:00.618 그러면 Enemy가 이렇게 오게 된 거에요 86 00:07:00.618 --> 00:07:02.987 돌리다 보면 그러면은 이 카메라가 87 00:07:05.000 --> 00:07:08.563 이렇게 이동을 하게 돼요 이렇게 가까이 이렇게 88 00:07:09.445 --> 00:07:11.629 이것도 Trace channel과 상관이 있습니다 89 00:07:11.817 --> 00:07:14.037 그래서 두 가지를 설정을 해 주도록 할 거에요 90 00:07:15.512 --> 00:07:18.621 그러면 Enemy를 더블 클릭해서 연 다음에 91 00:07:20.027 --> 00:07:23.630 Enemy에 보면 Capsule Component를 보시면 여기 컬리션 설정 있죠 92 00:07:24.046 --> 00:07:27.283 여기 보면은 여기 Trace response 부분에 보면 93 00:07:27.481 --> 00:07:29.573 Visibility는 Ignore 되어있고 94 00:07:29.880 --> 00:07:32.764 카메라는 Block이 되어있어요 이것 때문에 그렇거든요 95 00:07:33.130 --> 00:07:35.413 이거를 다르게 처리를 하겠습니다 96 00:07:35.413 --> 00:07:37.835 그래서 Custom이라고 하시고요 97 00:07:38.320 --> 00:07:40.458 그 다음에 Visibility는 Block 98 00:07:40.458 --> 00:07:42.784 그 다음에 카메라는 Ignore 반대로 해 줄게요 99 00:07:43.655 --> 00:07:45.614 그리고 Mesh에도 충돌체가 있기 때문에 100 00:07:46.040 --> 00:07:49.338 여기에 있는 것도 같이 처리를 하면 좋을 것 같은데요 101 00:07:49.764 --> 00:07:53.210 이렇게 열어서 일단은 Custom으로 해서 102 00:07:54.200 --> 00:07:57.189 일단 둘 다 Ignore로 해놓겠습니다 103 00:08:00.971 --> 00:08:04.734 사실 Mesh 같은 경우에는 이거를 NoCollision 해도 상관없을 것 같아요 104 00:08:05.556 --> 00:08:10.371 이렇게 컴파일 하고요 다시 한번 실행해 보겠습니다 105 00:08:11.787 --> 00:08:15.101 그리고 총을 쏘면은 Enemy가 총에 맞죠 106 00:08:15.101 --> 00:08:18.825 그리고 카메라로 이렇게 회전해 봐도 걸리지 않아요 107 00:08:19.538 --> 00:08:20.648 이렇게 지정을 해 줄게요 108 00:08:26.400 --> 00:08:27.793 이렇게 Enemy를 배치를 하고요 109 00:08:27.803 --> 00:08:31.734 그 다음에 Enemy에게 상태라는 개념을 만들어서 110 00:08:31.734 --> 00:08:33.314 이렇게 처리를 할까 하는데요 111 00:08:34.225 --> 00:08:36.509 그러면 먼저 설명을 하겠습니다 112 00:08:38.143 --> 00:08:40.704 상태머신 보통 FSM이라고 하죠 113 00:08:40.704 --> 00:08:44.839 Finite State Machine이라고 해요 114 00:08:50.770 --> 00:08:52.273 이렇게 작성을 할 수가 있고요 115 00:08:53.937 --> 00:08:56.169 앞에 인 이렇게 붙으면 인피니티죠 116 00:08:56.278 --> 00:08:59.247 근데 인이 없으면은 유한이 됩니다 117 00:08:59.247 --> 00:09:05.111 그래서 이거를 뭐 그대로 번역한다면 유한 상태 기계 118 00:09:06.527 --> 00:09:09.740 혹은 머신 이런 식으로 번역을 해요 119 00:09:09.740 --> 00:09:12.271 줄여서 상태머신 이렇게 부르기도 합니다 120 00:09:12.568 --> 00:09:15.158 그래서 이걸 줄여서 FSM이라고 하는데요 121 00:09:17.684 --> 00:09:20.805 언리얼에서는 보통 애니메이션이나 이런 제어를 할때는 122 00:09:20.805 --> 00:09:22.682 FSM 기반으로 제어를 하고요 123 00:09:22.969 --> 00:09:25.456 그래서 우리도 일단 AI 를 만들어 볼 건데 124 00:09:25.456 --> 00:09:27.675 FSM 기반의 AI 를 만들겠습니다 125 00:09:28.487 --> 00:09:34.249 그러면 이렇게 이제 상태머신을 만들 때는 3가지 어떤 요소가 있어요 126 00:09:34.249 --> 00:09:37.638 3요소가 있는데 하나는 이제 상태입니다 127 00:09:39.648 --> 00:09:40.989 이건 영어로 State라고 하죠 128 00:09:43.506 --> 00:09:45.661 그리고 조건이 있어요 129 00:09:46.898 --> 00:09:48.640 그리고 전이라는 개념이 있습니다 130 00:09:48.640 --> 00:09:50.115 전이는 그냥 옮겨 가는 거에요 131 00:09:51.244 --> 00:09:56.844 그러면 조건은 뭐 Condition 이렇게 부르고요 132 00:09:56.844 --> 00:09:58.658 전이는 Transition이라고 합니다 133 00:10:01.640 --> 00:10:04.117 영어로도 이렇게 기억하고 계시면 좋을 것 같고요 134 00:10:04.344 --> 00:10:07.208 그럼 이거를 이제 만들어 보도록 할게요 135 00:10:08.247 --> 00:10:11.108 상태머신을 이용해서 다이어그램 형태로 만들 건데 136 00:10:11.375 --> 00:10:17.050 기본적으로 Enemy의 AI는요 기본적으로 대기가 있고요 137 00:10:18.159 --> 00:10:21.506 이동 그 다음에 공격을 할 수 있어요 138 00:10:23.080 --> 00:10:26.727 그리고 피격을 받을 수 있고요 뭐 데미지죠 139 00:10:26.905 --> 00:10:28.611 그리고 이제 죽을 수가 있습니다 140 00:10:29.591 --> 00:10:31.363 이렇게 다섯가지 상태를 만들 거고요 141 00:10:31.600 --> 00:10:33.907 영어로는 이건 Idle이라고 할 거고요 142 00:10:36.248 --> 00:10:39.429 이동은 Move 공격은 Attack 143 00:10:41.400 --> 00:10:42.758 피격은 Damage라고 할게요 144 00:10:44.960 --> 00:10:48.372 죽음은 Die 이런 용어를 좀 써보도록 하겠습니다 145 00:10:49.145 --> 00:10:52.474 그러면 상태를 그릴 때는 네모 박스를 이용하는데요 146 00:10:52.474 --> 00:10:53.942 이렇게 이게 상태입니다 147 00:10:54.239 --> 00:10:55.824 처음엔 대기 상태겠죠? 148 00:10:56.903 --> 00:10:59.905 그리고 대기에서 이제 전이할 수 있는 것은 이동이에요 149 00:11:00.826 --> 00:11:05.647 그래서 이동 상태가 있고 이렇게 이동을 합니다 이렇게 전이를 합니다 150 00:11:06.389 --> 00:11:08.293 그러면 어떤 조건이 있어요 151 00:11:08.719 --> 00:11:12.215 어떤 조건이냐면 대기에서는 주인공을 찾을 겁니다 152 00:11:12.462 --> 00:11:16.175 주인공을 찾는 조건 그래서 만약 주인공이 있다면 153 00:11:17.106 --> 00:11:20.705 그 다음에 이동 상태로 전이하겠다 뭐 이런 식으로 이제 구현할 거고요 154 00:11:21.002 --> 00:11:24.939 이동한 다음에 공격을 할 수 있는 거리가 있겠죠 155 00:11:24.939 --> 00:11:27.020 가까워지면 공격을 할 수 있으니까요 156 00:11:27.020 --> 00:11:29.225 그러면은 이제 공격 상태로 전이를 하는 거죠 157 00:11:30.829 --> 00:11:34.758 그리고 공격하다가 만약에 이제 공격을 하려고 했더니 158 00:11:34.758 --> 00:11:36.143 공격거리에 있지 않아요 159 00:11:36.638 --> 00:11:37.819 플레이어가 도망을 갔어요 160 00:11:38.087 --> 00:11:39.458 그러면 다시 쫓아가야겠죠 161 00:11:39.458 --> 00:11:42.715 그래서 여기서는 다시 이동으로도 전이를 할 수가 있습니다 162 00:11:43.388 --> 00:11:46.654 이러한 형태로 이제 기본적인 움직임을 가질 거고요 163 00:11:46.654 --> 00:11:50.309 그 다음에 이제 피격이나 죽음 같은 경우에는 164 00:11:50.626 --> 00:11:53.618 외부적인 요인이죠 이것은 외부 165 00:11:55.907 --> 00:11:59.283 여기에서 우리가 만든 예제에서는 주인공이 총을 쏴요 166 00:11:59.283 --> 00:12:03.514 그럼 총을 쏴서 플레이어가 Enemy에게 데미지를 입히는 거죠 167 00:12:03.880 --> 00:12:05.865 그러면은 이제 데미지 상태가 되고 168 00:12:06.865 --> 00:12:08.935 그러면 체력이라는 개념이 있으면 좋겠죠 169 00:12:08.935 --> 00:12:13.440 체력을 이제 체력이 다 달지 않았으면 피격 상태로 가는 거고 170 00:12:13.440 --> 00:12:14.879 만약에 체력이 0이 되었어요 171 00:12:14.879 --> 00:12:17.281 그럼 죽음 상태로 가서 처리를 한다던지 172 00:12:17.499 --> 00:12:18.991 그런 식의 흐름을 가져갑니다 173 00:12:18.991 --> 00:12:22.277 그러니까 그러면은 뭐 Any State가 있다면 174 00:12:25.479 --> 00:12:30.296 어떤 상태에서든 왜냐면은 피격과 죽음은 대기를 할 때도 갈 수도 있고 175 00:12:30.296 --> 00:12:31.643 이동, 공격 마찬가지죠 176 00:12:31.643 --> 00:12:34.916 언제 어느 상태에서도 들어갈 수 있는 거죠 그렇죠? 177 00:12:35.649 --> 00:12:38.087 그래서 여기서 이제 피격을 하고요 178 00:12:43.316 --> 00:12:46.430 그리고 피격 이후에는 죽음 상태가 될 수도 있는 거죠 179 00:12:48.915 --> 00:12:50.411 바로 이렇게 죽을 수도 있고요 180 00:12:50.411 --> 00:12:53.711 이러한 형태로 우리가 구현을 좀 해 보도록 할 겁니다 181 00:12:53.711 --> 00:12:55.802 그래서 이거부터 구현할 건데 182 00:12:55.802 --> 00:13:01.431 저는 이번에는 Enemy에다가 Enemy 클래스를 만들었는데 183 00:13:01.679 --> 00:13:04.337 여기다가 컴포넌트를 하나 붙이겠습니다 184 00:13:06.880 --> 00:13:11.820 Enemy FSM이라는 컴포넌트를 하나 붙일 거에요 만들어야겠죠 이렇게 185 00:13:12.641 --> 00:13:16.362 그래서 컴포넌트 쪽에서 이걸 구현해서 어떻게 그러면은 186 00:13:16.897 --> 00:13:22.042 본체인 캐릭터 클래스와 그 다음에 거기 붙어있는 FSM 간에 어떤 187 00:13:22.824 --> 00:13:26.229 서로 어떻게 정보를 주고 받을 수 있는지 그런 것들도 같이 188 00:13:26.229 --> 00:13:27.845 학습을 해 보도록 하면 좋을 것 같아요 189 00:13:28.707 --> 00:13:32.372 그래서 컴포넌트를 하나 만들게요 190 00:13:33.057 --> 00:13:38.712 Tools에서 여기 내려 보시면은 컴포넌트가 두 개가 있습니다 그렇죠? 191 00:13:39.009 --> 00:13:41.792 액터와 Scene Component 두 가지가 있는데 192 00:13:42.782 --> 00:13:45.892 액터 컴포넌트는 그냥 존재하는 개념이고요 193 00:13:46.289 --> 00:13:48.763 Scene Component는 트랜스폼까지 같이 있는 거에요 194 00:13:49.456 --> 00:13:51.436 그래서 우리는 트랜스폼은 필요 없죠 195 00:13:51.436 --> 00:13:54.934 그래서 액터 컴포넌트를 상속받은 녀석으로 만들겠습니다 196 00:13:55.756 --> 00:14:02.629 Next 하고요 이거는 EnemyFSM 이렇게 작성을 할까요? 197 00:14:15.589 --> 00:14:18.846 EnemyFSM을 만들었는데요 그러면 상태를 만들어야겠죠 198 00:14:19.459 --> 00:14:25.969 상태를 만들 때 가장 편안한 형태는 열거형을 사용하는 거에요 199 00:14:26.305 --> 00:14:28.192 그래서 열거형을 좀 써볼 건데 200 00:14:28.450 --> 00:14:31.864 언리얼에서는 이 열거형을 제공해주고 있습니다 201 00:14:31.864 --> 00:14:35.634 U-Innerm이라고 하고요 이렇게 매크로가 있는데요 이렇게 202 00:14:36.297 --> 00:14:40.082 이걸 이용해서 enum class로 할 겁니다 203 00:14:41.656 --> 00:14:44.243 enum은 뭐 스코프가 있고 없고라는 개념이 있잖아요 204 00:14:45.045 --> 00:14:49.440 그래서 스코프도 enum으로 클래스 형태로 제작을 하겠습니다 205 00:14:50.420 --> 00:14:54.453 그래서 이 Enemy State란 이름으로 작성을 할게요 206 00:14:55.057 --> 00:14:58.674 그리고 이건 블루프린트에서도 뭐 보고 싶다 그럴 때는 207 00:14:59.377 --> 00:15:04.062 블루 프린트 타임이라고 작성해 주시면 되고요 208 00:15:05.022 --> 00:15:11.147 그 다음에 이렇게 작성할 때는 무조건 unit 8, Unsigned이죠 209 00:15:11.147 --> 00:15:13.948 이렇게 이제 구현이 되어야 합니다 이거는 규칙이에요 210 00:15:14.374 --> 00:15:18.969 이렇게 작성을 하시고 보통 이거 만드실 때는 여기만 이름을 바꾸시면 되겠죠 211 00:15:18.969 --> 00:15:23.325 그리고 열거형은 접두어를 E로 시작하게 하시면 됩니다 212 00:15:23.681 --> 00:15:24.830 이렇게 작성을 할게요 213 00:15:24.979 --> 00:15:33.842 그럼 여기에다가 Idle, Move, Attack, Damage, Die 이렇게 214 00:15:34.129 --> 00:15:35.237 다섯가지를 넣을 거고요 215 00:15:35.950 --> 00:15:39.664 뭐 이렇게는 콤마를 해도 되고 안 해도 됩니다 그냥 해줄게요 216 00:15:40.307 --> 00:15:42.878 그리고 여기에 이름을 만약에 블루프린트 상에서 217 00:15:42.878 --> 00:15:47.509 다르게 표현하고 싶다 그럴 때는 UMETA라는 키워드 218 00:15:47.509 --> 00:15:51.298 매크로죠? 매크로를 이용해서 디스플레이 네임을 변경을 할 수 있어요 219 00:16:03.506 --> 00:16:05.487 이건 선택인데 안 해도 상관없습니다 220 00:16:05.487 --> 00:16:08.647 대소문자 바꾸는건 Ctrl Shift U 하면은 대문자로 바뀌어요 221 00:16:09.479 --> 00:16:13.296 단축키들이 있으니까 이렇게 작성하셔도 괜찮습니다 222 00:16:13.474 --> 00:16:15.529 이렇게 해서 일단 작성을 해주고요 223 00:16:16.608 --> 00:16:19.601 그러면 이것이 이제 자료형이 돼요 열거형이니까 224 00:16:20.176 --> 00:16:22.446 이걸로 변수를 만들게요 좀 내려가서 225 00:16:23.159 --> 00:16:26.019 여기다가 public을 치겠습니다 226 00:16:27.118 --> 00:16:29.267 이렇게 하시고 State라고 할게요 227 00:16:32.137 --> 00:16:35.763 해당 State를 가지고 이제 분기를 할 거거든요 228 00:16:36.684 --> 00:16:39.758 그래서 어떻게 할 거냐면 여기 소스로 와 보시면 229 00:16:41.392 --> 00:16:44.034 Tick이 있습니다 여기도 컴포넌트에도 Tick이 있어요 230 00:16:44.945 --> 00:16:49.119 그럼 여기에서 작성을 해주는데 스위치 케이스문을 이용해 보겠습니다 231 00:16:49.119 --> 00:16:51.416 스위치라고 하고 탭 누르신 다음에 232 00:16:51.812 --> 00:16:55.223 그럼 이렇게 자동으로 이제 인텔센스 기능이 있어요 233 00:16:55.223 --> 00:16:56.633 자동 완성 기능이 여기다가 234 00:16:57.039 --> 00:17:00.192 State라고 적으시고 탭을 한번 더 누르고 235 00:17:00.192 --> 00:17:02.911 그다음에 엔터 이렇게 하시면 자동으로 쭉 나옵니다 236 00:17:04.387 --> 00:17:06.129 일단 이거는 디폴트는 필요 없고요 237 00:17:06.703 --> 00:17:10.318 여기다가 작성을 해줄건데 여기다가 Idle이라고 할 건데 238 00:17:10.575 --> 00:17:12.760 저는 여기가 이제 Tick이잖아요 239 00:17:12.760 --> 00:17:17.905 그래서 Tick Idle이라는 이름으로 함수를 이렇게 구현을 해줄게요 240 00:17:18.895 --> 00:17:22.038 이거는 어떻게 된 거냐면 이제 Tick은 매번 들어오는 곳이죠 241 00:17:22.038 --> 00:17:25.180 그러면 현재 상태가 어떤 거냐에 따라서 242 00:17:25.180 --> 00:17:28.244 그 일만 하겠다 뭐 이런 식으로 이제 기계적인 제어를 하는 거죠 243 00:17:28.877 --> 00:17:33.358 이거를 그림으로 표현한다면 뭐 여기다가 적으면 이렇게 되는 거죠 244 00:17:34.299 --> 00:17:35.959 이렇게 신호가 이렇게 들어오는데요 245 00:17:35.959 --> 00:17:39.691 이 State가 무엇이냐에 따라서 이렇게 해서 246 00:17:39.691 --> 00:17:41.146 분기가 이렇게 되는 거예요 신호가 247 00:17:41.760 --> 00:17:45.560 다섯 가지니까 이렇게 이건 Idle 뭐 이런 식으로 이렇게 248 00:17:45.817 --> 00:17:49.071 신호가 처음에 이제 State가 Idle이라면 249 00:17:49.319 --> 00:17:51.298 그럼 Idle 쪽으로 신호가 이렇게 가는 거고요 250 00:17:51.486 --> 00:17:54.794 만약에 State 값을 다른 걸로 바꿨어요 Move로 바꿨어요 251 00:17:55.160 --> 00:17:59.120 이거를 Move로 변경을 했다면 그러면 신호가 Move 쪽으로 흘러가는 거죠 252 00:17:59.863 --> 00:18:02.585 이런 신호를 만들 수가 있는데 이게 이제 253 00:18:03.199 --> 00:18:04.881 유한 상태 기계라는 거에요 254 00:18:06.842 --> 00:18:09.971 그래서 각 상태마다 이렇게 함수를 만들어서 255 00:18:09.971 --> 00:18:11.040 제어를 해주면 좋을 것 같습니다 256 00:18:11.040 --> 00:18:14.153 여기다 그대로 작성을 해도 되지만 그러면 여기가 너무 길어지니까요 257 00:18:14.906 --> 00:18:16.138 함수를 이렇게 만들어서 258 00:18:21.407 --> 00:18:22.995 제어를 해보도록 하겠습니다 259 00:18:38.565 --> 00:18:42.318 FSM 기반의 상태별 기능 구현 260 00:18:42.520 --> 00:18:46.524 이렇게 만들었으니까요 이거 전부 다 구현해주도록 하겠습니다 261 00:18:49.396 --> 00:18:53.156 헤더로 가서 여기다가 구현부를 만들게요 선언부를 만들게요 262 00:18:58.091 --> 00:18:59.057 이렇게 작성하시고 263 00:19:08.838 --> 00:19:10.034 이렇게 다 만들었습니다 264 00:19:11.232 --> 00:19:12.557 구현도 해줘야 겠죠 265 00:19:18.814 --> 00:19:20.046 이렇게 작성을 하고요 266 00:19:20.749 --> 00:19:23.660 그러면 이제 이걸 이용해서 처리를 하면 됩니다 267 00:19:23.759 --> 00:19:27.177 먼저 이렇게 하면은 밑에 이제 함수가 다 만들어져 있을 겁니다 268 00:19:27.642 --> 00:19:29.892 그러면은 여기다가 하나씩 이제 구현해주면 돼요 269 00:19:30.239 --> 00:19:36.763 유한 상태 머신의 장점은 이렇게 기능별로 뜯어 가지고 270 00:19:37.219 --> 00:19:39.833 따로따로 이제 각각 구현을 할 수가 있고요 271 00:19:40.338 --> 00:19:43.273 그것을 이제 흐름을 제어 흐름을 통해서 272 00:19:43.550 --> 00:19:45.548 그 일을 했다가 저 일을 했다가 이렇게 273 00:19:45.548 --> 00:19:48.477 신호로 바꿔주면서 처리를 할 수 있다는 거죠 274 00:19:49.299 --> 00:19:52.987 근데 단점은 이게 복잡해질 수 있고 275 00:19:53.333 --> 00:19:55.051 그리고 가속성이 좀 좋지 않죠 276 00:19:55.051 --> 00:19:58.418 어떻게 흐름을 이어가고 있는지 한눈에 보이지 않는게 277 00:19:58.418 --> 00:20:02.042 문제가 있는 부분인데 하지만 이게 가장 기본이 되고요 278 00:20:02.943 --> 00:20:04.172 하나씩 제어를 해 볼게요 279 00:20:04.509 --> 00:20:05.726 Idle부터 갑니다 280 00:20:08.627 --> 00:20:10.370 Idle에서는 이렇게 할 거에요 281 00:20:11.300 --> 00:20:12.708 일단 시간이 흐르다가요 282 00:20:16.280 --> 00:20:18.262 만약에 1초가 지났어요 283 00:20:20.272 --> 00:20:22.520 그러면 주인공을 찾을 겁니다 284 00:20:24.817 --> 00:20:27.418 주인공을 찾고 싶다 285 00:20:28.854 --> 00:20:30.517 그래서 만약에 찾았다면 286 00:20:32.439 --> 00:20:35.778 Move 상태로 전이 하고 싶다 287 00:20:37.174 --> 00:20:38.255 이런 일을 할 거고요 288 00:20:38.949 --> 00:20:40.410 일단 한번 다 적어 볼까요? 289 00:20:40.657 --> 00:20:44.246 Move에서는요 이동을 해야겠죠 290 00:20:47.958 --> 00:20:48.847 목적지를 291 00:20:53.749 --> 00:20:56.107 향해서 이동하고 싶다 292 00:20:59.235 --> 00:21:02.346 그리고 목적지와의 거리를 구할 거에요 293 00:21:02.346 --> 00:21:05.134 계속 이동을 하다가 끝나면 안되겠죠 294 00:21:05.134 --> 00:21:06.604 가까이 가면 멈춰야 되니까요 295 00:21:07.069 --> 00:21:11.218 목적지와의 거리를 구하고 296 00:21:14.560 --> 00:21:19.827 만약에 그 거리가 공격 가능 거리라면 297 00:21:21.263 --> 00:21:23.671 근데 이렇게 쓰면 조금 구현하기가 좀 그렇겠죠 298 00:21:24.018 --> 00:21:28.238 공격 가능 거리보다 이하라면 299 00:21:31.477 --> 00:21:34.384 그러면 공격 상태로 전이 하고 싶다 300 00:21:35.215 --> 00:21:36.779 이런 식으로 구현하면 될 것 같고요 301 00:21:38.852 --> 00:21:41.427 그러면 크게 보면 이렇게 두 가지로 나누는 거죠 기능이 302 00:21:41.585 --> 00:21:45.808 이동하는 기능과 그 다음에 조건을 체크해서 전이를 하는 303 00:21:45.808 --> 00:21:47.450 그러한 형태로 이렇게 나눠집니다 304 00:21:48.093 --> 00:21:48.921 여기도 마찬가지죠 305 00:21:48.921 --> 00:21:54.014 시간이 흐르는 게 1초가 지낸 것까지가 기본적인 구현이고 306 00:21:54.014 --> 00:21:57.378 그 다음에 주인공을 찾아서 전이를 하는 거죠 307 00:22:00.137 --> 00:22:01.418 Tick Attack도 해볼까요? 308 00:22:01.418 --> 00:22:05.434 여기는 나중에는 좀 많이 바꾸겠지만 기본적으로 309 00:22:06.880 --> 00:22:10.290 시간이 흘러서 공격을 한다 이렇게 처리해 볼게요 310 00:22:10.924 --> 00:22:11.897 시간이 흐르다가 311 00:22:14.560 --> 00:22:20.144 만약 공격 대기 시간이 되면 312 00:22:20.450 --> 00:22:24.590 그렇다는 것은 현재 시간이 공격 대기 시간보다 커지면 313 00:22:27.760 --> 00:22:29.808 이렇게 할게요 현재 시간이 314 00:22:32.954 --> 00:22:34.684 그러면 공격을 할 겁니다 315 00:22:36.427 --> 00:22:38.734 공격은 간단하게 로그를 출력해 줄게요 316 00:22:38.734 --> 00:22:39.895 Attack 이런 식으로 317 00:22:40.736 --> 00:22:43.758 그리고 현재 시간을 초기화 해야겠죠 318 00:22:47.827 --> 00:22:49.130 이게 이제 하나의 일이고요 319 00:22:49.407 --> 00:22:52.226 두 번째는 공격에서는 공격을 하고 나서 320 00:22:52.959 --> 00:22:55.093 목적지와의 거리를 또 구할 거에요 321 00:22:55.865 --> 00:23:00.248 그래서 목적지와의 거리를 구하고 322 00:23:02.280 --> 00:23:11.587 만약에 그 거리가 공격 범위를 벗어나면 323 00:23:12.280 --> 00:23:14.047 반대죠 공격 가능 거리 324 00:23:14.532 --> 00:23:17.427 이걸로 그대로 쓴다면 거리가 325 00:23:20.719 --> 00:23:27.479 공격 거리 보다 뭐 크다 이렇게 하면 되겠죠 326 00:23:32.537 --> 00:23:34.214 그러면은 이동할 겁니다 327 00:23:34.392 --> 00:23:38.745 상태로 전이하고 싶다 이러한 일을 할 거고요 328 00:23:39.458 --> 00:23:40.782 일단 시간이 흘러야 되겠죠 329 00:23:40.872 --> 00:23:45.347 그리고 보면은 공격 대기 시간, 공격 가능 거리 이런 것들이 있습니다 330 00:23:45.347 --> 00:23:50.454 그래서 이거를 먼저 구현을 해 보도록 할 건데요 331 00:23:51.454 --> 00:23:53.485 그리고 여기 보면은 주인공을 찾아야 되겠죠 332 00:23:53.485 --> 00:23:55.305 찾았다가 기억하고 있어야 되겠죠 333 00:23:55.998 --> 00:23:57.318 그래야지 목적지를 334 00:24:00.160 --> 00:24:01.906 그 사용을 할 수 있는 거니까요 335 00:24:02.272 --> 00:24:05.969 사실 여기다가 주인공이라고 썼지만 이것은 이제 목적지입니다 목적지 336 00:24:06.939 --> 00:24:07.997 이렇게 쓸게요 337 00:24:10.897 --> 00:24:14.921 그래서 헤더에다가 저 관련된 변수들을 좀 만들어 주도록 하겠습니다 338 00:24:16.307 --> 00:24:17.738 먼저 new property로 339 00:24:22.361 --> 00:24:25.759 class ATPSPlayer 340 00:24:26.719 --> 00:24:28.046 이게 타겟이에요 341 00:24:30.646 --> 00:24:34.946 그리고 이동을 할 건데 사실 이동하기 위해서는 본체가 필요해요 342 00:24:34.946 --> 00:24:39.280 이것은 컴포넌트니까 컴포넌트는 바로 이동을 할 수 없거든요 343 00:24:39.280 --> 00:24:41.768 이동하는 것은 컴포넌트에 있는 것이 아니라 344 00:24:43.382 --> 00:24:47.791 자기를 소유하고 있는 소유자의 Movement 컴포넌트 쪽에 있잖아요 345 00:24:47.791 --> 00:24:51.045 이동하는 기능이 그래서 자기 소유자를 기억해야 됩니다 346 00:24:51.758 --> 00:24:54.883 그래서 그거를 하기 위해서 new property라고 하고요 347 00:24:56.738 --> 00:24:58.723 이 컴포넌트의 소유자는 Enemy죠 348 00:24:59.050 --> 00:25:03.186 그래서 class AEnemy라고 하고 이건 어차피 349 00:25:03.809 --> 00:25:05.828 나 자신이니까 Me라고 하겠습니다 350 00:25:06.095 --> 00:25:08.182 대문자로 사용할게요 351 00:25:10.488 --> 00:25:14.187 이렇게 해주고 아까 시간도 있었죠 float column time 352 00:25:17.858 --> 00:25:21.639 float Attack Range라고 할게요 353 00:25:23.699 --> 00:25:28.249 공격 가능 거리 이거는 한 150cm, 1.5m 정도 주고요 354 00:25:29.268 --> 00:25:34.136 그 다음에 처음에 1초를 기다려야 되죠 355 00:25:35.512 --> 00:25:37.593 이건 Find time이라고 하겠습니다 356 00:25:40.766 --> 00:25:43.955 이건 1초 그리고 이런 것들은 나중에 357 00:25:43.955 --> 00:25:47.267 기획자가 수정할 수 있는 내용이죠 Find time 이런 것들은 358 00:25:51.687 --> 00:25:54.268 이렇게 해서 기획자가 이걸로 변경할 수 있도록 359 00:25:56.308 --> 00:25:58.070 Find time 말고도 또 있죠 360 00:25:59.000 --> 00:26:04.435 Attack Range 이것도 사실 기획자가 바꿀 수 있는 내용인 것 같아요 361 00:26:05.327 --> 00:26:06.865 그리고 Find time 말고 362 00:26:09.297 --> 00:26:12.177 공격 대기 시간은 우리가 만들었나요 363 00:26:13.970 --> 00:26:15.258 공격 대기 시간 있죠 364 00:26:15.258 --> 00:26:17.566 Delay Time 이런 거 만들어야 될 것 같습니다 365 00:26:17.823 --> 00:26:21.277 여기서 Attack Delay Time 366 00:26:22.337 --> 00:26:25.277 이거는 일단 1초로 해주겠습니다 이런 식으로 367 00:26:27.580 --> 00:26:31.801 뭔가 밸런스에 관련된 정보들은 이렇게 이 property 붙여가지고 368 00:26:31.969 --> 00:26:35.199 기획자가 건드릴 수 있도록 이렇게 해주면 좋을 것 같습니다 369 00:26:36.467 --> 00:26:39.373 여기는 0 이라고 안 썼지만 기본적으로 0으로 초기화가 되고요 370 00:26:39.779 --> 00:26:41.679 그럼 이것들을 이제 다 채워 볼게요 371 00:26:41.679 --> 00:26:43.163 이것만 BeginPlay에서 채우고 372 00:26:43.599 --> 00:26:47.978 이것은 이제 Idle 대기 상태에서 채우면 될 것 같습니다 373 00:26:49.137 --> 00:26:50.447 그러면 이쪽으로 가서 374 00:26:52.932 --> 00:26:56.944 BeginPlay에서 일단은 Me를 채워보겠습니다 375 00:26:57.251 --> 00:27:00.438 Me는 소유자 Owner라고 하죠 376 00:27:01.349 --> 00:27:04.942 Owner가 있어요 자기를 소유하고 있는 소유자 377 00:27:06.160 --> 00:27:11.496 이 컴포넌트를 소유하고 있는 것은 Enemy라는 캐릭터죠 378 00:27:11.912 --> 00:27:18.229 그러니까 이거를 캐스팅을 해서 가지고 있으면 됩니다 379 00:27:22.756 --> 00:27:23.386 자 이렇게 380 00:27:26.238 --> 00:27:29.364 이런거 사용할 때는 항상 헤더를 추가를 해주셔야 됩니다 381 00:27:29.364 --> 00:27:31.075 저는 자동으로 일단 추가를 할게요 382 00:27:32.026 --> 00:27:33.643 이런 식으로 추가를 해주십시오 383 00:27:34.930 --> 00:27:37.780 이거는 기본이니까요 항상 이런거 하실 때는 384 00:27:37.780 --> 00:27:40.165 클래스를 이렇게 새롭게 사용하실 때는 385 00:27:40.888 --> 00:27:44.511 구현을 하시는 부분에서 전부 다 헤더로 추가해 주셔야 됩니다 386 00:27:45.353 --> 00:27:46.415 이렇게 해서 캐스팅을 하고요 387 00:27:47.395 --> 00:27:49.734 Me를 채웠고 그러면은 다시 Idle로 가서 388 00:27:49.734 --> 00:27:51.562 이 기능을 구현해 보도록 할게요 389 00:27:51.562 --> 00:27:55.752 일단 시간은 흘러야 되겠죠 시간은 CurrentTime 390 00:27:56.198 --> 00:28:01.027 여기다가 = GetWorld에서 델타 세컨드 391 00:28:03.010 --> 00:28:04.412 이렇게 가져와도 되고요 392 00:28:05.214 --> 00:28:08.219 아니면 그냥 델타 세컨드 변수를 사용하셔도 돼요 393 00:28:11.239 --> 00:28:13.936 이렇게 보면 여기 있죠 이렇게 하셔도 됩니다 394 00:28:16.307 --> 00:28:18.998 가져오고요 그 다음에 1초가 지났다면 395 00:28:19.533 --> 00:28:21.057 1초가 아니라 Find time이죠 396 00:28:21.433 --> 00:28:29.760 Find time이 보다 커졌다면 이렇게 하면 되겠죠 397 00:28:29.760 --> 00:28:33.939 If CurrentTime이 Find time보다 크다면 398 00:28:34.781 --> 00:28:36.832 그러면 이제 목적지를 찾아볼거에요 399 00:28:38.188 --> 00:28:41.409 그리고 이거는 주기니까 0으로 일단 초기화를 해주고요 400 00:28:42.320 --> 00:28:43.632 그러면 찾아보도록 할게요 401 00:28:43.632 --> 00:28:47.780 여기 보면은 UGameplaystatics를 이용하면 편하겠죠 402 00:28:47.780 --> 00:28:50.277 UGameplaystatics에 보면 403 00:29:04.487 --> 00:29:08.218 여기 보면 GetActorOfClass가 있습니다 404 00:29:08.426 --> 00:29:10.446 이걸 이용하면 되겠죠 GetWorld 405 00:29:12.317 --> 00:29:14.462 주인공이니까 Player Pawn을 찾아도 되고요 406 00:29:14.462 --> 00:29:17.035 Player Character 찾아도 되고 이렇게 찾아도 돼요 407 00:29:17.718 --> 00:29:22.764 이렇게 해서 주인공은 ATPSPlayer 이렇게 되죠 408 00:29:22.764 --> 00:29:24.763 여기에서 UClass를 넣으면 되니까요 409 00:29:25.040 --> 00:29:29.753 StaticClass를 이렇게 넣어주시면 되겠습니다 410 00:29:30.594 --> 00:29:34.426 이것도 사용하려면 이렇게 헤더를 추가를 해줘야 되고요 411 00:29:36.958 --> 00:29:39.073 이 녀석도 헤더를 추가하겠습니다 412 00:29:41.168 --> 00:29:43.597 헤더 추가는 제가 계속적으로 말씀드렸던 부분이니까 413 00:29:43.973 --> 00:29:46.432 이렇게 지금 이렇게 추가했습니다 414 00:29:49.448 --> 00:29:50.817 이렇게 해주시면 되겠습니다 415 00:29:53.880 --> 00:29:57.637 그러면 찾았잖아요 그럼 이거를 이제 담아야겠죠 416 00:29:57.637 --> 00:29:59.672 우린 타겟이라는 변수를 만들었으니까요 417 00:30:01.128 --> 00:30:04.175 Target 이렇게 받으면 되는데 418 00:30:05.868 --> 00:30:09.946 보시면 GetActorOfClass는요 반환하는 것이 액터의 포인터에요 419 00:30:10.688 --> 00:30:14.575 그러니까 여기서 이렇게 하면 안 되고 캐스팅을 해야겠죠 캐스트 420 00:30:15.853 --> 00:30:17.996 이렇게 담아주면 되겠습니다 421 00:30:25.398 --> 00:30:26.560 이렇게 해서 담았고요 422 00:30:26.560 --> 00:30:28.427 그래서 이 타겟이 null이 아니라면 423 00:30:30.199 --> 00:30:33.817 이렇게 해서 타겟이 null이 아니라면 그러면 State를 424 00:30:36.698 --> 00:30:40.087 Move State로 이렇게 전이를 해주면 됩니다 425 00:30:40.770 --> 00:30:42.425 전이라는 게 다른 게 아니고요 426 00:30:42.425 --> 00:30:45.279 이 값을 바꿔주는 것을 얘기한다고 보시면 돼요 427 00:30:48.285 --> 00:30:52.505 그리고 전이를 할 때는 같이 시간을 사용하고 그러거든요 428 00:30:53.268 --> 00:30:58.142 이동하고 거리 구하고 그리고 공략할 때 시간도 또 쓰고 그렇죠? 429 00:30:58.142 --> 00:31:00.553 여기 있는 CurrentTime을 좀 재활용을 할 겁니다 430 00:31:01.959 --> 00:31:05.815 그래서 일단 시간을 0으로 이렇게 해서 넘겨주도록 할 거에요 431 00:31:05.815 --> 00:31:08.880 근데 이제 매번 이렇게 하면은 시간이 좀 많이 걸리겠죠 432 00:31:08.880 --> 00:31:11.198 작성할 때 이렇게 다 작성을 해야 되니까 433 00:31:11.545 --> 00:31:14.635 그래서 이거를 하는 기능을 하나 만들어 줄게요 434 00:31:15.348 --> 00:31:15.978 이쪽으로 와서 435 00:31:18.348 --> 00:31:23.073 여기다가 void, SetState라는 함수를 하나 만들겠습니다 436 00:31:23.736 --> 00:31:28.448 이거는요 EEnemyState를 newState 이렇게 받을 거고요 437 00:31:30.649 --> 00:31:32.307 이걸 구현을 해줄게요 이렇게 438 00:31:39.000 --> 00:31:42.537 여기 있네요 여기다가 현재 State에다가 439 00:31:42.537 --> 00:31:45.319 이렇게 new State를 넣어주도록 할 거고요 440 00:31:45.319 --> 00:31:48.424 그 다음에 CurrentTime을 0 초기화하는 일까지 441 00:31:48.424 --> 00:31:49.875 같이 한 번에 하도록 하겠습니다 442 00:31:50.479 --> 00:31:53.822 그럼 이 setState를 호출해 주면은 이제 이거는 자동으로 하겠죠 443 00:31:55.297 --> 00:31:59.778 그래서 기존에 했던 내용을 이렇게 변경을 할게요 444 00:32:02.439 --> 00:32:05.584 이렇게 하면 시간 초기화까지 같이 하게 됩니다 445 00:32:06.218 --> 00:32:08.485 그러면 이제 목적지를 향해 이동을 해 볼게요 446 00:32:10.257 --> 00:32:11.567 이 Move로 넘어왔을 겁니다 447 00:32:13.171 --> 00:32:14.447 이동을 해 보겠습니다 448 00:32:14.447 --> 00:32:18.682 그러면 이동하는 거는 이제 방향을 정해서 그 방향으로 가는 거죠 449 00:32:18.880 --> 00:32:21.016 목적지를 알고 있죠 타겟이에요 450 00:32:21.471 --> 00:32:22.397 타겟에 보면 451 00:32:26.100 --> 00:32:29.423 GetActorLocation 이렇게 해서 가져올 수 있고요 452 00:32:29.423 --> 00:32:35.706 여기 빼기 나의 GetActorLocation 이렇게 해서 가져오면 되겠죠 453 00:32:36.359 --> 00:32:38.115 이러면 이제 Direction을 구할 수 있고요 454 00:32:38.858 --> 00:32:41.703 Fvector로 해서 Direction이라고 하겠습니다 455 00:32:49.010 --> 00:32:52.799 그리고 움직일 건데 이건 캐릭터로 구현이 되어있기 때문에 456 00:32:52.799 --> 00:32:56.716 Enemy가 그래서 위에 add Movement input을 이용하면 457 00:32:56.716 --> 00:32:58.018 간단하게 움직일 수 있겠죠 458 00:32:58.018 --> 00:32:59.595 여기다가 Direction을 넣겠습니다 459 00:33:04.427 --> 00:33:06.738 그러면은 실제로 이제 Direction을 넣었는데 460 00:33:06.738 --> 00:33:08.790 여기서는 자동으로 알아서 얘가 이제 461 00:33:08.790 --> 00:33:10.882 크기를 normalizing 해서 사용하거든요 462 00:33:11.199 --> 00:33:15.362 그러니까 여기서는 실제로 여기 안에는 길이가 있겠죠 463 00:33:15.520 --> 00:33:18.124 근데 혹시 모르니까 이거를 normalizing 해주고 싶으면 464 00:33:18.520 --> 00:33:25.102 get safe normal을 이용하면 원본은 그대로 유지하고 465 00:33:25.419 --> 00:33:28.353 이렇게 normalizing한 사본을 반환하는 형태로 됩니다 466 00:33:28.353 --> 00:33:29.378 그래서 이렇게 쓰고요 467 00:33:29.640 --> 00:33:33.661 그러면 이 Direction은 실제로 떨어진 거리를 얘가 가지고 있겠죠 468 00:33:34.057 --> 00:33:36.057 그래서 목적지와의 거리는요 469 00:33:37.920 --> 00:33:42.274 dist 라고 한다면 이건 Direction의 사이즈 입니다 470 00:33:42.739 --> 00:33:44.872 사이즈 함수에 가보시면 이런 식으로 되어있어요 471 00:33:45.674 --> 00:33:50.688 사실 거리를 구하는 공식은 이렇게 각 항목 별로 다 곱하고요 472 00:33:52.959 --> 00:33:55.978 이렇게 다 곱하고 그 다음에 그거를 루트를 씌우면 473 00:33:56.226 --> 00:33:58.126 실제 그 거리를 구할 수가 있거든요 474 00:33:59.058 --> 00:34:03.733 그 다음에 이제 이거를 Attack Range보다 이하라면 475 00:34:04.060 --> 00:34:11.199 이렇게 하죠 dist가 Attack Range보다 이하니까 이렇게 써야겠죠 476 00:34:11.377 --> 00:34:17.127 이렇게 하고 그러면은 공격 상태로 전이하면 되겠죠 setState 477 00:34:18.850 --> 00:34:21.802 이렇게 해서 공격이니까 Attack 이렇게 하면 되겠죠 478 00:34:28.050 --> 00:34:29.191 그리고 이것도 해볼게요 479 00:34:29.350 --> 00:34:32.629 공격을 할 겁니다 시간이 흘러야 겠죠 동일합니다 480 00:34:32.837 --> 00:34:33.749 CurrentTime 481 00:34:35.749 --> 00:34:44.447 GetWorld에서 DeltaTimeSecond 이렇게 할게요 482 00:34:45.477 --> 00:34:49.914 그래서 현재 시간이 CurrentTime이 483 00:34:52.726 --> 00:34:55.977 공격 대기시간 Attack Delay Time 이거보다 커졌어요 484 00:34:55.977 --> 00:34:57.837 그러면은 이제 공격을 할 거고 485 00:34:59.669 --> 00:35:01.338 공격은 그냥 로그를 출력할게요 486 00:35:01.764 --> 00:35:03.368 UE_Log 487 00:35:11.114 --> 00:35:13.947 렉이 걸려가지고 잠깐만 기다려 볼까요? 488 00:35:17.917 --> 00:35:20.439 이렇게 작성을 하시고 그 다음에 여기다가 텍스트로 489 00:35:23.238 --> 00:35:27.085 Attack 이렇게 표현을 해보도록 하겠습니다 490 00:35:29.479 --> 00:35:33.159 그리고 UE_LOG 같은 경우는 뒤에 세미콜론을 굳이 안 붙여도 되긴 합니다 491 00:35:33.159 --> 00:35:35.345 왜냐하면 이 매크로인데 이 매크로그가 492 00:35:36.018 --> 00:35:38.503 끝에 세미콜론이 아마 자동으로 붙을 거예요 493 00:35:39.038 --> 00:35:40.243 그래서 안 붙여도 됩니다 494 00:35:41.233 --> 00:35:43.063 근데 그래도 붙여도 상관없고요 495 00:35:44.469 --> 00:35:46.385 그 다음에 현재 시간은 초기화 하겠습니다 496 00:35:46.385 --> 00:35:49.251 CurrentTime은 0 이렇게 그래야지 주기가 되죠 497 00:35:49.855 --> 00:35:52.726 이렇게 계속해서 반복해서 공격을 할 거 아니에요 498 00:35:53.617 --> 00:35:55.178 이거는 이제 공격하는 일이고요 499 00:35:55.178 --> 00:35:58.939 그 다음에 이거랑 별개로 주인공이 도망갔어요 500 00:35:58.939 --> 00:36:00.306 그러면은 따라가야겠죠 501 00:36:01.335 --> 00:36:06.726 그래서 여기다가 거리를 구할게요 502 00:36:06.726 --> 00:36:09.855 거리 구하는 거는 이렇게 하면 되겠죠 503 00:36:10.360 --> 00:36:13.324 float dist는 504 00:36:14.008 --> 00:36:16.055 여기도 이제 랭스 이렇게 구하고 싶은데 505 00:36:16.332 --> 00:36:18.575 보면 이렇게 이미 여기서 뺐었잖아요 506 00:36:18.575 --> 00:36:20.706 근데 이제 여기는 없죠 해줘야죠 507 00:36:21.518 --> 00:36:23.447 그래서 여기 보면은 좀 다른 걸로 해볼까요 이번에는? 508 00:36:23.447 --> 00:36:28.247 액터에 보면 dist라는 함수가 있습니다 509 00:36:28.247 --> 00:36:31.744 이걸 이용해도 되고 여기 보면은 이제 두 개의 위치를 넣으면 되는데요 510 00:36:31.971 --> 00:36:37.518 이렇게 할 수도 있고요 혹은 내가 혹은 뭐 타겟이 511 00:36:38.320 --> 00:36:43.266 그 녀석과 얼마나 거리가 멀리 있느냐 이걸로 구하는 함수도 있어요 512 00:36:43.503 --> 00:36:44.944 그래서 뭐 Me에서 보면 513 00:36:45.360 --> 00:36:49.736 Me에서 dist2 514 00:36:50.360 --> 00:36:54.465 get dist2 이렇게 distance2 이런 함수가 있습니다 515 00:36:54.465 --> 00:36:56.996 여기다가 이제 타겟을 넣어주시면 돼요 516 00:36:57.659 --> 00:36:58.895 반대로 해도 됩니다 517 00:36:58.895 --> 00:37:01.233 타겟이 Me를 해도 돼요 518 00:37:01.362 --> 00:37:03.063 이렇게 반대로 해도 상관없고요 519 00:37:04.577 --> 00:37:05.498 저는 이렇게 할게요 520 00:37:06.053 --> 00:37:09.956 Me가 내가 타겟과 얼마나 멀리 있느냐고 물어보는 거죠 521 00:37:10.758 --> 00:37:12.116 그러면 값을 반환 해주고요 522 00:37:13.037 --> 00:37:16.000 그래서 이거를 공격 가능 거리랑 비교를 해보겠습니다 523 00:37:16.000 --> 00:37:19.061 dist가 Attack Range 보다 커졌다면 524 00:37:20.111 --> 00:37:21.557 그러면 이제 도망간 거 잖아요 525 00:37:22.656 --> 00:37:24.498 그러면은 따라가야죠 그래서 526 00:37:27.565 --> 00:37:33.119 setState 이렇게 해서 Move 쫓아가겠습니다 527 00:37:36.768 --> 00:37:40.034 그러면 이걸 좀 로그로 출력을 해보고 싶어요 528 00:37:40.351 --> 00:37:43.816 근데 UE_LOG 말고 화면에 이렇게 노출하는 로그로 하고 싶은데요 529 00:37:44.687 --> 00:37:46.774 여기 보면은 이렇게 한번 해볼게요 530 00:37:46.981 --> 00:37:51.367 tick 컴포넌트 쪽에다가 아래쪽에다가 작성을 해볼게요 531 00:37:52.199 --> 00:38:01.575 여기서는 이제 현재 상태를 화면에 로그로 출력하고 싶다 532 00:38:03.367 --> 00:38:06.486 일단 현재 상태를 문자로 바꿔야겠죠 Fstring 533 00:38:08.557 --> 00:38:10.740 strState라고 하고요 534 00:38:11.493 --> 00:38:12.701 이건 Enum인데요 535 00:38:12.701 --> 00:38:15.963 이렇게 열광으로 된 녀석을 State 이거를 536 00:38:15.963 --> 00:38:17.610 문자열을 바꾼 기능이 있습니다 537 00:38:17.610 --> 00:38:22.473 여기 보면은 UEnum이라고 작성하시고요 538 00:38:22.730 --> 00:38:25.682 대소문자 잘 보세요 뒤에는 소문자에요 539 00:38:26.177 --> 00:38:30.352 이렇게 한 다음에 as string 540 00:38:31.546 --> 00:38:32.371 여러분 여기 있죠 541 00:38:32.371 --> 00:38:34.455 get value as string 이런 함수가 있습니다 542 00:38:35.158 --> 00:38:37.466 여기다가 State를 넣으시면 되고요 543 00:38:39.446 --> 00:38:42.032 템플릿으로 되어 있어서 여기다가 꺽쇠해서 544 00:38:42.032 --> 00:38:43.795 템플릿을 이렇게 넣어 주셔도 되고 545 00:38:43.795 --> 00:38:45.493 이걸 생략해도 상관 없습니다 546 00:38:45.998 --> 00:38:49.583 이렇게 해서 State를 이렇게 문자열을 바꾸고요 547 00:38:50.227 --> 00:38:53.536 그러면은 이렇게 돼요 이 문장이 이제 출력이 됩니다 548 00:38:54.298 --> 00:38:55.677 이거를 출력을 해볼게요 549 00:38:57.449 --> 00:39:02.231 Draw Debug String이라는 함수가 있는데 550 00:39:02.231 --> 00:39:06.415 이거는 이제 실제로 문자열을 화면에 탁 찍는 551 00:39:06.504 --> 00:39:09.399 그 특정 위치에다가 탁 찍는 그런 기능입니다 552 00:39:09.399 --> 00:39:12.417 그래서 이거를 사용해 볼 거고요 GetWorld 하시고 553 00:39:15.120 --> 00:39:23.578 그 다음에 두 번째 여기에 이제 위치가 되죠 554 00:39:23.994 --> 00:39:30.974 벡터가 들어가니까요 위에 GetActorLocation 이렇게 받으신 다음에 555 00:39:31.360 --> 00:39:33.968 여기다가 조금 저는 약간 위쪽에다 출력하고 싶어요 556 00:39:33.968 --> 00:39:37.140 머리 정도에다가 그래서 Me의 아니죠 557 00:39:38.120 --> 00:39:40.437 Fvector로 추가를 해줄게요 558 00:39:41.546 --> 00:39:45.387 위쪽 이라는 것은 z 값이죠 0, 0, 0 559 00:39:46.120 --> 00:39:46.929 조금 위에다가 560 00:39:50.159 --> 00:39:52.807 이렇게 50cm 정도 위로 올릴까요? 이렇게 561 00:39:55.188 --> 00:39:58.114 그리고 여기다가 str State를 출력을 합니다 562 00:39:59.897 --> 00:40:01.526 뒤에는 그냥 이렇게 하셔도 돼요 563 00:40:02.308 --> 00:40:06.485 근데 여기 보면은 지속시간이 있거든요 Duration이 564 00:40:06.485 --> 00:40:09.566 그래서 이게 이제 -1이 아니라 0으로 넣어줘야 돼서 565 00:40:10.120 --> 00:40:12.974 여기를 좀 넣겠습니다 그래서 이렇게 넣고 566 00:40:14.291 --> 00:40:16.849 0 넣어도 되죠 이렇게 하고 그 다음에 567 00:40:19.107 --> 00:40:22.448 색깔을 지정해 줘야 되는데 기존이 화이트네요 568 00:40:22.765 --> 00:40:25.919 F-color라고 하고 보면은 여기 색깔이 있습니다 569 00:40:25.919 --> 00:40:27.357 원하시는 색을 주시면 되고요 570 00:40:27.357 --> 00:40:29.303 저는 cyan으로 해볼게요 571 00:40:30.392 --> 00:40:35.459 약간 푸릇푸릇한 색으로 이렇게 하고 그 다음에 여기를 572 00:40:36.518 --> 00:40:38.643 Duration을 0 이렇게 해주시면 되고요 573 00:40:38.643 --> 00:40:40.988 쉐도우 주시려면 true 이렇게 넣어주시면 되겠습니다 574 00:40:41.760 --> 00:40:47.254 뒤에는 이제 폰트 크기를 더 키울거냐 그런건데 1이면은 1배이고요 575 00:40:47.719 --> 00:40:49.490 그 다음에 1. 몇 하면 몇 배 이렇게 되겠죠 576 00:40:50.797 --> 00:40:53.548 저는 그대로 해보겠습니다 이렇게 하고요 577 00:40:57.523 --> 00:40:59.588 컴파일 해서 어떻게 되나 한번 볼까요? 578 00:41:03.736 --> 00:41:06.058 성공했고요 실행을 하면 579 00:41:10.778 --> 00:41:14.209 오지 않네요 다시 볼게요 아 컴포넌트를 붙이지 않았네요 580 00:41:15.239 --> 00:41:19.311 Enemy 컴포넌트 이거 FSM 컴포넌트를요 Enemy에다가 붙여줘야겠죠 581 00:41:20.173 --> 00:41:22.235 여기다가 Enemy의 헤더로 와서요 여기다가 582 00:41:23.859 --> 00:41:28.932 Uproperty EditAnywhere라고 하겠습니다 583 00:41:28.932 --> 00:41:29.872 그 다음에 여기다가 584 00:41:31.050 --> 00:41:35.151 class UEnemyFSM이죠 585 00:41:35.359 --> 00:41:39.219 이렇게 해서 FSM이라고 하겠습니다 586 00:41:41.817 --> 00:41:43.689 이거를 이제 구현을 해줄게요 587 00:41:44.135 --> 00:41:48.377 생성을 해야겠죠 여기서 생성자 제일 아래쪽에다가 588 00:41:50.198 --> 00:41:53.631 FSM 이거 똑같아요 589 00:41:53.631 --> 00:41:57.877 CreateDefaultSubobject 590 00:42:05.877 --> 00:42:09.859 이렇게 하시고 이게 이제 UEnemyFSM이라고 하시고요 591 00:42:10.720 --> 00:42:12.429 이름은 FSM이라고 하겠습니다 592 00:42:16.508 --> 00:42:21.073 사실 영어만 쓸 때는 텍스트를 뭐 그냥 생략해도 상관없는데 593 00:42:21.073 --> 00:42:22.075 그냥 다 적어 줄게요 594 00:42:22.808 --> 00:42:25.610 이렇게 하고 다시 한번 컴파일 할게요 595 00:42:28.617 --> 00:42:31.981 이건 액터 컴포넌트이기 때문에 어테치를 하지 않아도 돼요 596 00:42:32.753 --> 00:42:33.562 할 수도 없고요 597 00:42:34.176 --> 00:42:36.374 이렇게 하고 어 오류가 났네요 598 00:42:37.938 --> 00:42:39.455 아 헤더 추가를 안했네요 599 00:42:40.119 --> 00:42:41.946 이거를 헤더를 이렇게 추가하겠습니다 600 00:42:53.627 --> 00:42:55.615 실행해 보면 적이 이제 오죠 601 00:42:55.773 --> 00:42:59.130 Move 그리고 Attack 상태가 바뀌는게 보이시죠 이렇게 602 00:43:02.116 --> 00:43:06.109 어우 잘 따라옵니다 이렇게 처리를 한 다음에요 603 00:43:07.258 --> 00:43:09.084 이제 타격을 해야겠죠 604 00:43:09.510 --> 00:43:11.218 기본적으로 움직이는 건 다 됐는데 605 00:43:12.396 --> 00:43:16.599 주인공이 이제 적을 타격했을 때 어떤 일이 바로 발생을 해야 될 것 같아요 606 00:43:17.044 --> 00:43:19.409 그래서 일단 EnemyFSM 쪽에다가 607 00:43:21.716 --> 00:43:23.870 데미지를 입을 수 있는 함수를 하나 만들어줄게요 608 00:43:25.830 --> 00:43:29.120 void OnDamageProcess 609 00:43:31.706 --> 00:43:32.553 이렇게 할까요? 610 00:43:32.553 --> 00:43:35.587 Attack Damage라고 써도 되는데 이렇게 한번 적어보겠습니다 611 00:43:36.627 --> 00:43:40.843 이렇게 한 다음에 실제로 이제 데미지 값을 int로 받을게요 612 00:43:40.843 --> 00:43:46.637 Damage 이렇게 구현부를 만들고요 613 00:43:51.318 --> 00:43:55.196 데미지가 되면은 이제 이 상태를 이제 바꿔주면 되겠죠 614 00:43:55.879 --> 00:43:58.656 그러면 데미지 들어왔을 때 바꾸려면 뭔가 있어야 되겠죠 615 00:43:58.656 --> 00:43:59.976 그냥 바로 할 수가 없잖아요 616 00:44:00.758 --> 00:44:03.725 체력이라는 개념이 있어야 체력을 소진한 후에 617 00:44:03.884 --> 00:44:05.826 체력이 0이 되었으면 Die로 가고 618 00:44:06.073 --> 00:44:07.724 0이 안되었으면 데미지로 가는거죠 619 00:44:08.546 --> 00:44:11.152 그래서 체력도 하나 만들어주겠습니다 620 00:44:11.152 --> 00:44:14.465 int HP라고 하고 일단 2라고 할게요 621 00:44:14.970 --> 00:44:16.778 두 번 맞으면 죽는거죠 622 00:44:18.698 --> 00:44:25.098 들어와서 HP에다가 데미지를 빼주고요 623 00:44:27.157 --> 00:44:36.075 만약에 HP가 0보다 커요 그러면은 setState 해서 데미지로 보내고요 624 00:44:36.550 --> 00:44:38.669 그리고 크지 않아요 else에요 625 00:44:38.669 --> 00:44:42.639 그러면 0보다 이하라는 거죠 0 이하라는 거니까 죽어야겠죠 626 00:44:42.639 --> 00:44:44.671 그럼 setState 해서 627 00:44:46.077 --> 00:44:51.885 nm.. 아니 이거는 다시 적을게요 628 00:44:53.399 --> 00:44:55.466 Die 이렇게 보내면 되겠습니다 629 00:44:57.607 --> 00:45:00.456 그럼 이제 보냈으니까 여기를 구현을 해줘야겠죠 630 00:45:02.218 --> 00:45:03.637 데미지는 이렇게 할 거에요 631 00:45:03.637 --> 00:45:04.847 일단 시간이 흐르다가 632 00:45:08.627 --> 00:45:17.594 현재 시간이 만약에 데미지 딜레이 시간이 되면 633 00:45:17.594 --> 00:45:24.080 크면 다시 이동 상태로 전이하고 싶다 이렇게 되야겠죠 634 00:45:25.208 --> 00:45:28.029 죽었을 때는 일단은 저는 죽었을 때 635 00:45:28.237 --> 00:45:30.399 바닥으로 쭉 내려주고 싶어요 636 00:45:30.399 --> 00:45:35.600 바닥으로 아래 방향으로 이동하고 싶다 637 00:45:36.907 --> 00:45:38.234 이걸 구현할 거고요 하나는 638 00:45:38.848 --> 00:45:40.959 두 번째는 시간을 잴 겁니다 639 00:45:40.959 --> 00:45:42.456 그래서 시간이 흐르다가 640 00:45:44.560 --> 00:45:52.320 만약 현재 시간이 죽음 딜레이 시간이 되면 641 00:45:52.320 --> 00:45:55.697 칸트 방식으로 파괴하고 싶다 642 00:45:56.919 --> 00:46:01.520 누구를? 나를 Me를 이렇게 구현을 해보도록 할 거에요 643 00:46:03.708 --> 00:46:05.535 그럼 데미지부터 한번 해볼게요 644 00:46:06.357 --> 00:46:07.626 먼저 구현부터 해볼까요? 645 00:46:07.943 --> 00:46:12.627 여기도 CurrentTime GetWorld의 646 00:46:15.480 --> 00:46:16.896 DeltaTimeSeconds 647 00:46:18.748 --> 00:46:20.609 이렇게 누적을 해주면 시간이 흐르겠죠? 648 00:46:20.609 --> 00:46:24.006 저번에 얘기했지만 이렇게 해서 누적해서 1이 되는 순간이 1초가 지난 거에요 649 00:46:24.927 --> 00:46:28.792 만약에 현재 시간이 그러면 여기 변수가 있어야 겠네요 650 00:46:28.792 --> 00:46:31.710 데미지 딜레이, 죽음 딜레이라는 변수가 있어야 겠네요 651 00:46:31.948 --> 00:46:35.315 헤더로 가서 두 개를 추가를 해주겠습니다 652 00:46:35.315 --> 00:46:37.364 이렇게 해서 2번 복사를 하시고 653 00:46:38.117 --> 00:46:40.382 이거는 데미지 딜레이라고 하고요 654 00:46:41.917 --> 00:46:45.701 이거는 죽음 딜레이, 다이 딜레이 이렇게 작성을 해주도록 하겠습니다 655 00:46:50.535 --> 00:46:53.057 데미지 딜레이는 넉넉하게 2초 정도 주고요 656 00:46:56.248 --> 00:46:59.542 다이 딜레이도 2초 정도 주도록 하겠습니다 657 00:47:00.948 --> 00:47:04.251 어택도 넉넉하게 2초라고 할까요? 좀 빠른 거 같은데 658 00:47:05.013 --> 00:47:06.087 다이 2초라고 하겠습니다 659 00:47:10.800 --> 00:47:13.571 그러면 마저 구현부를 만들어 볼까요? 660 00:47:13.928 --> 00:47:16.459 이렇게 하면 이제 딜레이 시간을 만들어 줬으니까 661 00:47:16.459 --> 00:47:19.223 CurrentTime이 커졌어요 662 00:47:19.223 --> 00:47:21.877 뭐 보다? 데미지 딜레이 타임보다 663 00:47:23.838 --> 00:47:27.280 그러면 이동 상태로 전이를 하겠습니다 664 00:47:28.469 --> 00:47:33.818 이렇게 해서 setState, Move 이렇게 하면 되겠죠 665 00:47:37.520 --> 00:47:39.472 어떻게 보면 이렇게 되면 총에 맞으면 666 00:47:39.472 --> 00:47:41.375 2초 정도 가만히 서 있을 거에요 지금은 667 00:47:42.108 --> 00:47:44.247 나중에 애니메이션을 붙이면은 668 00:47:44.247 --> 00:47:47.820 리액션하는 행위를 하고 이제 다시 돌아오는 그런 개념인데 669 00:47:48.098 --> 00:47:49.783 지금은 그런 애니메이션이 없으니까 670 00:47:50.070 --> 00:47:51.953 이런 식으로 일단 구현을 해보도록 할게요 671 00:47:52.765 --> 00:47:55.853 그 다음에 죽음 상태도 마저 구현을 해볼까요? 672 00:47:55.853 --> 00:47:57.729 아래 방향으로 일단 이동하고 싶습니다 673 00:47:58.749 --> 00:48:06.641 그러면은 우리는 이거는 P=P0 vt 이렇게 이동시키면 되겠죠 674 00:48:07.829 --> 00:48:10.580 먼저 P0를 만들게요 Fvector 675 00:48:11.639 --> 00:48:15.457 P0 이거는 GetActorLocation 676 00:48:17.550 --> 00:48:23.652 어? Me에서 해야 되죠? GetActorLocation 이렇게 가져옵니다 677 00:48:25.078 --> 00:48:26.202 그 다음에 vt를 만들게요 678 00:48:26.202 --> 00:48:30.894 Fvector에 vt는요 일단 아래 방향이에요 679 00:48:30.894 --> 00:48:34.040 Fvector에 보면 다운 벡터가 있습니다 680 00:48:34.040 --> 00:48:36.971 이게 다운 벡터는 이렇게 되있네요 681 00:48:36.971 --> 00:48:38.938 0, 0, -1 이렇게 되어있습니다 682 00:48:39.898 --> 00:48:42.030 그 다음에 여기다가 움직여야겠죠 683 00:48:42.228 --> 00:48:43.981 그래서 한 200정도 줄게요 크기를 684 00:48:44.357 --> 00:48:47.714 이것도 변수를 빼도 되는데 이거는 그냥 이렇게 적어 주겠습니다 685 00:48:48.159 --> 00:48:49.738 너무 변수가 많은 것 같아 가지고 686 00:48:50.401 --> 00:48:52.348 그 다음에 델타 세컨드 곱해야겠죠? 687 00:48:52.615 --> 00:48:58.729 GetWorld에 DeltaTimeSeconds 688 00:48:59.154 --> 00:49:02.143 이렇게 해서 vt를 만들었습니다 그렇죠? 689 00:49:02.143 --> 00:49:06.612 이게 v죠 방향 곱하기 스피드 이게 v고 벨로시티 690 00:49:06.890 --> 00:49:09.288 그 다음에 t는 델타 세컨드를 사용하면 됩니다 691 00:49:11.399 --> 00:49:12.438 이동을 해 볼게요 692 00:49:12.952 --> 00:49:17.189 Me의 SetActorLocation 693 00:49:19.439 --> 00:49:24.169 이렇게 해서 P0 vt 하면은 아래쪽으로 쭉 이동을 하게 될 겁니다 694 00:49:27.979 --> 00:49:30.399 시간을 측정해서 파괴를 할 건데요 695 00:49:30.706 --> 00:49:32.909 먼저 또 시간이 흘러야 됩니다 CurrentTime 696 00:49:36.265 --> 00:49:39.310 GetWorld의 델타 이거 그대로 쓰면 되겠죠? 697 00:49:41.805 --> 00:49:42.508 이렇게 하고요 698 00:49:45.486 --> 00:49:46.448 시간을 측정합니다 699 00:49:46.448 --> 00:49:49.879 CurrentTime이 die Delay Time보다 커졌어요 700 00:49:52.369 --> 00:49:56.594 이렇게 해서 원래 Ctrl K D 하면 701 00:49:56.594 --> 00:49:58.224 자동으로 이제 정렬해 주거든요 702 00:49:58.224 --> 00:49:59.760 이런 기능으로 써줘도 됩니다 703 00:49:59.760 --> 00:50:04.657 이렇게 해서 이렇게 되면은 나를 파괴하면 되겠죠? 704 00:50:04.657 --> 00:50:06.257 Me를 Destroy 하겠다 705 00:50:10.687 --> 00:50:12.913 이렇게 구현을 해 주시면 되겠습니다 706 00:50:14.230 --> 00:50:16.617 그러면 한번 실행해서 결과를 보도록 할게요 707 00:50:19.298 --> 00:50:20.287 컴파일 하고 708 00:50:24.918 --> 00:50:27.980 아 그러고 보니까 총에 맞는 일을 안 했습니다 709 00:50:28.792 --> 00:50:30.725 플레이어로 가서 여기죠 710 00:50:31.032 --> 00:50:34.647 여기 OnIAFire에서 히트를 한 다음에 711 00:50:34.647 --> 00:50:39.607 여기에서 이제 부딪힌 상대방이 적이에요 Enemy에요 712 00:50:39.607 --> 00:50:41.555 AEnemy다 라면 713 00:50:44.216 --> 00:50:48.008 AEnemy에 FSM에 714 00:50:50.820 --> 00:50:52.869 OnDamageProcess 715 00:50:54.810 --> 00:50:56.517 함수를 이렇게 콜을 해 주겠다는 거예요 716 00:50:56.517 --> 00:51:00.462 1점 데미지, 데미지를 1점 717 00:51:01.719 --> 00:51:05.775 적에게 데미지를 1점 데미지죠 718 00:51:05.775 --> 00:51:08.268 데미지를 1점 주고 싶다 719 00:51:09.426 --> 00:51:15.186 이런 일을 할 건데 그거는 결국은 이 일을 하는 겁니다 자 먼저 그러면은 720 00:51:15.186 --> 00:51:20.000 부딪힌 상대방이 Enemy인지 알아야겠죠? 자 이것은 이렇게 할 수 있어요 721 00:51:20.000 --> 00:51:26.719 hit info에 보면 get actor가 있습니다 이게 이제 부딪힌 상대방이에요 상대방의 actor입니다 722 00:51:26.719 --> 00:51:32.520 이거를 캐스팅을 해보면 검증할 수 있겠죠? cast 라고 하고요 723 00:51:33.000 --> 00:51:37.439 AEnemy 이렇게 캐스팅을 해보면 되겠죠 724 00:51:39.756 --> 00:51:42.159 헤더를 이렇게 추가를 해주십시오 725 00:51:42.407 --> 00:51:47.087 헤더는 제가 이렇게 올려서 어떻게 추가하고 있는지 보여드릴께요 726 00:51:47.998 --> 00:51:49.107 이거를 추가했습니다 727 00:51:57.808 --> 00:52:00.925 그럼 auto 해가지고 이거 Enemy라고 이렇게 받을게요 728 00:52:01.787 --> 00:52:04.887 이게 포인터니까 이렇게 적어주면 더 좋겠죠? 729 00:52:04.887 --> 00:52:06.506 auto라고 그냥 써도 되는데 730 00:52:07.010 --> 00:52:11.592 네 auto 그리고 레퍼런스 같은 경우에는 이렇게 작성을 해줘야 되죠 731 00:52:12.404 --> 00:52:13.673 이렇게 쓰겠습니다 732 00:52:17.867 --> 00:52:20.599 그리고 만약에 Enemy가 null이 아니에요 733 00:52:20.599 --> 00:52:22.335 그러면은 실제로 Enemy인거죠 734 00:52:23.869 --> 00:52:25.189 이렇게 캐스팅을 시도해보고 735 00:52:28.812 --> 00:52:32.072 그럼 Enemy에 보면 FSM이 있죠 736 00:52:33.498 --> 00:52:38.371 이런식으로 여기서 바로 접근해서 사용해도 되는데요 737 00:52:38.816 --> 00:52:41.533 사실 이렇게 하는 거는 그렇게 좋은 방법은 아니에요 738 00:52:41.810 --> 00:52:45.516 개체제한 프로그래밍에서는 상대방의 속성에 접근하고 739 00:52:45.516 --> 00:52:48.648 또 거기에서 또 다른 속성에 접근하고 이런식으로 타고 들어가서 740 00:52:48.648 --> 00:52:51.577 뭔가 값을 처리하는 거는 좋은 방법은 아닙니다 741 00:52:52.617 --> 00:52:57.239 그래서 좀 더 나은 방법은 Enemy 헤더에다가 v를 구현하고 742 00:52:57.239 --> 00:52:59.833 그 다음에 여기서는 콜을 해주는 형식으로 하면 좋겠죠 743 00:53:00.358 --> 00:53:07.077 그래서 여기다가 void TakeDamage라는 함수를 이렇게 만들까요? 744 00:53:13.536 --> 00:53:16.137 이렇게 구현을 한번 해주도록 할게요 745 00:53:18.360 --> 00:53:20.964 그래서 트릭 데미지에서는 746 00:53:23.449 --> 00:53:31.414 FSM의 OnDamageProcess에다가 데미지를 전달해 주겠습니다 747 00:53:31.592 --> 00:53:33.818 이렇게 하는 게 이제 좀 더 개체 제한스럽죠 748 00:53:35.990 --> 00:53:39.523 그리고 외부에서는 Enemy에 TakeDamage를 호출해주면 되겠죠 749 00:53:41.038 --> 00:53:42.629 이렇게 구현해 보도록 하겠습니다 750 00:53:43.570 --> 00:53:45.878 근데 이게 TakeDamage를 또 딴 데 쓸 수도 있으니까 751 00:53:45.878 --> 00:53:48.661 이름은 OnMy 이런 식으로 써줄까요 752 00:53:50.136 --> 00:53:52.135 이름을 이런식으로 바꿔서 쓰겠습니다 753 00:53:55.798 --> 00:53:58.279 그러면 플레이어 쪽에서는 Enemy에 754 00:54:01.259 --> 00:54:04.237 OnmytakeDamage를 호출해주면 되겠죠 755 00:54:04.237 --> 00:54:05.097 1점 주겠습니다 756 00:54:09.770 --> 00:54:11.185 전부 다 저장을 해주시고요 757 00:54:11.760 --> 00:54:14.046 컴파일을 해본 다음에 결과를 볼게요 758 00:54:24.225 --> 00:54:27.228 잘 오고요 총에 탁 맞으면 멈춰 있죠 759 00:54:27.367 --> 00:54:28.890 그리고 2초 후에 다시 옵니다 760 00:54:29.306 --> 00:54:32.394 그 다음에 탁 쏘면 죽어야 되는데 바닥으로 내렸는데 761 00:54:32.899 --> 00:54:34.482 파괴는 되는데 못 내려가죠 762 00:54:34.482 --> 00:54:40.116 그건 왜 그러냐면 CapsuleComponent가 바닥에 부딪히고 있어서 그래요 사실 763 00:54:41.008 --> 00:54:42.612 그래서 그것까지 마무리를 해줄게요 764 00:54:43.375 --> 00:54:46.634 이거는 이렇게 하고 Enemy FSM으로 와서 765 00:54:47.436 --> 00:54:49.948 여기 die로 넘어가는 부분은 여기 있죠 766 00:54:50.681 --> 00:54:53.916 OnDamageProcess 여기서 die로 넘어갈 때 767 00:54:54.718 --> 00:55:00.313 Me에 보면은 캡슐이 있습니다 CapsuleComponent 768 00:55:01.917 --> 00:55:05.743 이 녀석의 SetCollisionEnabled를 769 00:55:06.644 --> 00:55:09.386 이렇게 해서 NoCollision이라고 바꿔줄게요 770 00:55:09.525 --> 00:55:11.925 어차피 이제 죽었으니까 이거 쓰지 않을 거니까요 771 00:55:12.667 --> 00:55:17.187 이거 쓰려면은 이 CapsuleComponent를 가지고 와야 돼요 그렇죠? 772 00:55:17.187 --> 00:55:19.352 그럼 이거를 이제 헤더를 추가를 해줘야 됩니다 773 00:55:19.609 --> 00:55:21.520 그래서 여기서는 추가를 해줄게요 774 00:55:21.807 --> 00:55:26.540 이 CapsuleComponent 이렇게 해서 헤더를 이렇게 추가를 해주면 775 00:55:27.708 --> 00:55:30.257 오류가 없어지는데 여러분들은 보셔야겠죠 776 00:55:31.405 --> 00:55:34.835 Components에 CapsuleComponent 이렇게 되어있습니다 777 00:55:40.689 --> 00:55:41.810 이렇게 작성하시면 돼요 778 00:55:47.768 --> 00:55:48.897 그럼 오류가 없어지고요 779 00:55:50.214 --> 00:55:52.206 컴파일 해서 결과를 볼게요 780 00:55:59.528 --> 00:56:01.826 탕 탕 쏘면 쭉 내려가죠 781 00:56:01.945 --> 00:56:04.286 그리고 파괴 이렇게 됩니다 782 00:56:06.008 --> 00:56:08.621 그리고 이거 총알은 삭제를 해놓겠습니다 783 00:56:08.621 --> 00:56:10.511 지금 분리 넥터가 필요없죠 784 00:56:11.581 --> 00:56:12.481 여기까지 입니다 785 00:56:13.679 --> 00:56:17.254 이번 단원에서 학습한 내용을 정리하도록 하겠습니다 786 00:56:17.893 --> 00:56:21.393 적 액터 생성 및 FSM 기반의 상태 구분 적 액터 생성 적 액터의 외관을 적용하는 방법: Quinn을 사용해서 적을 만듦 787 00:56:21.393 --> 00:56:24.903 FSM 기반의 상태 구분 유한 상태 기계의 구성 요소: 상태, 조건, 전이 적 액터의 상태를 처리하기 위한 Tick에서 현재 상태를 분기 처리하는 방법 788 00:56:24.903 --> 00:56:28.853 FSM 기반의 상태별 기능 구현 유한 상태 머신 장점: 기능별로 구분하여 각각 구현할 수 있음 단점: 복잡하고 가속성이 떨어짐 789 00:56:28.853 --> 00:56:32.775 대기, 이동, 공격, 피격, 죽음 상태 구현 각 상태별로 구현부를 나누고 독립적으로 구현함 어떤 조건이 성립했을 때 그에 맞는 전이가 이루어지게 함