﻿1
00:00:04,290 --> 00:00:05,340
‫こんにちは､ ようこそ｡

2
00:00:05,340 --> 00:00:11,610
‫今回の講義では､ C++でシュートノードを実装することで､ 敵をより脅威的な存在にすることを目指します｡

3
00:00:11,610 --> 00:00:13,800
‫さっそく､ 潜入してみましょう｡

4
00:00:14,580 --> 00:00:19,980
‫そこで､ ビヘイビアツリーに明らかに欠けている機能のひとつが､ 「撮影」機能です｡

5
00:00:19,980 --> 00:00:24,930
‫理想は､ プレイヤーのいる場所に移動して撮影することですね｡

6
00:00:24,930 --> 00:00:28,560
‫でも､ まずは動きのやり方を少し変えたいんです｡

7
00:00:28,560 --> 00:00:34,290
‫いくつか微調整したいことがあるので､ ノードへの移動を選択すると､ ひとつは半径を変更したい｡

8
00:00:34,290 --> 00:00:42,930
‫敵がすぐ近くまで来るのは嫌だから､ 許容範囲を変えたら5メートル先で動かなくなる｡

9
00:00:42,930 --> 00:00:43,740
‫だから､ やめることになるんです｡

10
00:00:43,740 --> 00:00:45,690
‫5mの距離でお願いします｡

11
00:00:45,690 --> 00:00:46,650
‫彼は私に近づいてくる､ そこに行く｡

12
00:00:46,650 --> 00:00:48,180
‫そして､ 立ち止まって見つめている｡

13
00:00:48,180 --> 00:00:54,780
‫もうひとつは､ 黒板のセクションで､ 黒板の観測値があるのがわかると思います｡

14
00:00:54,780 --> 00:00:58,470
‫もし､ そのチェックがなかったら､ 私が動くことでどうなるか見てみましょう｡

15
00:00:58,500 --> 00:01:03,660
‫彼は基本的に､ 許容半径が小さくなると､ このことが少しばかり顕著になるのです｡

16
00:01:03,660 --> 00:01:06,780
‫では､ それを今､ 5 4に貼り付けましょう｡

17
00:01:06,990 --> 00:01:09,840
‫そして､ 再生ボタンを押せば､ 私の動きと同じように見ることができます｡

18
00:01:09,840 --> 00:01:14,940
‫私の最後の位置まで行って､ そこに到達してからアップデートが来るんです｡

19
00:01:14,940 --> 00:01:16,320
‫それは､ 私たちが望んでいることではありません｡

20
00:01:16,320 --> 00:01:19,530
‫私たちが望むのは､ それが常に私たちの方に向かってくることです｡

21
00:01:19,530 --> 00:01:25,320
‫そして､ observe blackboardの値をチェックすると､ 本質的には､ プレイヤーの位置が変わるたびに､

22
00:01:25,320 --> 00:01:30,180
‫移動先の場所を更新する､ ということです｡

23
00:01:30,180 --> 00:01:37,770
‫だから､ 再生ボタンを押して移動すると､ 彼が継続的に私を追いかけ､ 軌道を更新しているのがわかる｡

24
00:01:37,770 --> 00:01:39,180
‫それこそ､ 私たちの望むところです｡

25
00:01:39,180 --> 00:01:43,830
‫そこで､ 今度は受け入れ半径を500に変更すれば､ 目立たなくなります｡

26
00:01:43,830 --> 00:01:47,250
‫でも､ そこで観察した黒板の価値があるのは､ やはり良いことだと思います｡

27
00:01:47,250 --> 00:01:54,330
‫そして､ 私たちが望む行動は､ 彼が私たちの半径の中に入ってきたら､ そうやって立ち止まって私たちを撃つということです｡

28
00:01:54,330 --> 00:01:56,730
‫そのためには､ 新しいタイプのタスクが必要です｡

29
00:01:56,730 --> 00:01:58,950
‫そこで､ ここに新しいC++タスクを作成することにします｡

30
00:01:58,950 --> 00:02:02,100
‫そこで､ 新しいC++クラスを追加することにします｡

31
00:02:02,100 --> 00:02:06,990
‫そして､ 全クラスを表示して､ ビートタスクを探しに行くのです｡

32
00:02:07,020 --> 00:02:12,030
‫さて､ ビートタスクノードとビートタスク黒板ベース､ どちらがいいのでしょうか？

33
00:02:12,030 --> 00:02:16,500
‫まあ､ 実際には撮影してみるだけなので､ キーを使う必要はないんですけどね｡

34
00:02:16,500 --> 00:02:17,520
‫それだけでいいんです｡

35
00:02:17,520 --> 00:02:23,520
‫銃の引き金を引くか､ 照準はビヘイビアツリーの他の場所で行うことになります｡

36
00:02:23,610 --> 00:02:31,650
‫では､ この基本クラスであるタスク・ノードを開いて､ これをビート・タスクと呼ぶことにしましょう｡

37
00:02:32,420 --> 00:02:33,320
‫アンダースコア

38
00:02:33,350 --> 00:02:34,190
‫撃つ｡

39
00:02:34,760 --> 00:02:36,700
‫では､ そのクラスを作成してみましょう｡

40
00:02:36,710 --> 00:02:39,470
‫そうすると､ ちょうどこんな感じになります｡

41
00:02:39,470 --> 00:02:41,960
‫そこで､ 同じようにセットアップを行いたいと思います｡

42
00:02:41,960 --> 00:02:48,920
‫そこで､ 黒板と同じように､ クリアな黒板の値を設定することに､ ちょっとだけ挑戦してみましょう｡

43
00:02:48,920 --> 00:02:52,220
‫名前が欲しい､ 実行タスクが欲しい｡

44
00:02:52,220 --> 00:02:54,020
‫では､ ビデオと仮定して､ それを使ってみてください｡

45
00:02:54,050 --> 00:02:54,920
‫では､ お帰りなさい｡

46
00:02:54,920 --> 00:02:56,480
‫それがミニタスクだったんですね｡

47
00:02:56,480 --> 00:03:04,610
‫透明な黒板の値から署名を上書きして撮影するんです､ 公開部分と保護部分を含めてね｡

48
00:03:04,610 --> 00:03:07,640
‫コンストラクタの名前を変えてみる｡

49
00:03:07,640 --> 00:03:10,130
‫これからコンストラクタを実装していきます｡

50
00:03:10,130 --> 00:03:12,050
‫そして､ 私たちに必要なことは何だったのか｡

51
00:03:12,080 --> 00:03:16,490
‫ノード名と撮影を等しく設定する必要があったのです｡

52
00:03:16,490 --> 00:03:17,690
‫ということになりますね｡

53
00:03:17,690 --> 00:03:25,820
‫次にシュートタスクのヘッダに戻り､ 実行タスクを実装してみますが､ superを呼び出すだけでよいのです｡

54
00:03:25,820 --> 00:03:32,600
‫そこで､ 黒板のクリア値CPファイルからそれをコピーして､ 実装を開始する準備が整ったというわけです｡

55
00:03:32,600 --> 00:03:37,220
‫さて､ ここでまず必要なのは､ もう少し広いスペースで､

56
00:03:37,220 --> 00:03:39,860
‫ポーンを手に入れることです｡

57
00:03:39,860 --> 00:03:41,540
‫なぜ､ ポーンを手に入れる必要があるのでしょうか？

58
00:03:41,540 --> 00:03:45,020
‫では､ ポーンであるシューターキャラクターを見てもらいましょう｡

59
00:03:45,020 --> 00:03:46,580
‫シューターキャラクターを覚えていますか？

60
00:03:46,580 --> 00:03:48,890
‫ドットHにはシュート方式があります｡

61
00:03:48,890 --> 00:03:54,770
‫それこそ､ 私たちプレイヤーがやっているのと本質的に同じことを呼んでほしいのです｡

62
00:03:54,770 --> 00:03:58,460
‫トリガーボタンを押しながら､ この撮影方法を呼び出しているのです｡

63
00:03:58,460 --> 00:04:01,100
‫AIにも同じことができるようにしたい｡

64
00:04:01,100 --> 00:04:06,830
‫撮影タスクがあると､ トリガーボタンを押し続けたり､ そのトリガーボタンを繰り返し押したりするので､

65
00:04:06,830 --> 00:04:10,070
‫実行タスクが適切な場所になるのでしょう｡

66
00:04:10,100 --> 00:04:15,260
‫ここで何を返すかというと､ このアクションは一発勝負であることを忘れてはならないからです｡

67
00:04:15,260 --> 00:04:16,760
‫連写ではないんです｡

68
00:04:16,760 --> 00:04:17,570
‫どうするんだ？

69
00:04:17,600 --> 00:04:22,430
‫成功した場合は､ ETノードの結果であるsuccessを返します｡

70
00:04:22,430 --> 00:04:28,430
‫もし私たちが成功したのなら､ 継続的に冷却する必要がないためです｡

71
00:04:28,430 --> 00:04:32,630
‫このタスクは､ 1フレームより長く実行する必要はありません｡

72
00:04:32,630 --> 00:04:36,950
‫そしてもうひとつは､ 先ほども言ったように､ ポーンとしたクラスを手に入れることです｡

73
00:04:36,950 --> 00:04:41,330
‫さて､ これから紹介するのは､ AIコントローラーを手に入れる方法です｡

74
00:04:41,330 --> 00:04:47,540
‫そして､ AIコントローラーから､ get pawnを呼び出すと､ 操作されたポーンを取得できることが分かっています｡

75
00:04:47,540 --> 00:04:53,570
‫そして､ その制御されたポーンをシューターキャラクターの実装に投じることができることも分かっています｡

76
00:04:53,570 --> 00:04:58,850
‫では､ ここからどうやってAIコントローラーを手に入れるか｡

77
00:04:58,850 --> 00:05:03,560
‫さて､ ビヘイビアツリーコンポーネントは､ AIコントローラーにあることがわかりました｡

78
00:05:03,560 --> 00:05:09,440
‫そこで､ Yuビヘイビアツリーコンポーネントに移動して､ この中に使えそうなメソッドがないか見てみると､

79
00:05:09,440 --> 00:05:12,350
‫何かあるかもしれませんね｡

80
00:05:12,350 --> 00:05:18,140
‫YU behavior treeコンポーネントの親クラスはYu brainコンポーネントなので､

81
00:05:18,140 --> 00:05:24,560
‫この中にたくさんありますが､ コントローラーを探すと､ 何も見当たりません｡

82
00:05:24,560 --> 00:05:27,350
‫その1つをフォローアップし､ ここでコントローラーを探します｡

83
00:05:27,350 --> 00:05:29,420
‫そのためのプロパティがあることがわかります｡

84
00:05:29,450 --> 00:05:31,100
‫ゲッターはあるのか？

85
00:05:31,100 --> 00:05:38,840
‫はい､ get AI ownerというのがあり､ それにカーソルを合わせるとAIコントローラのポインタが返ってくるはずです｡

86
00:05:38,840 --> 00:05:46,370
‫だから､ それを使ってポーンを手に入れ､ シューターキャラクターにキャストして､ シューターメソッドを呼び出すことができるはずです｡

87
00:05:46,370 --> 00:05:51,740
‫shootメソッドを呼び出して公開し､ ポーンを取得し､ ポーンをキャストし､ 呼び出し､ shootして､

88
00:05:51,740 --> 00:05:56,480
‫ビヘイビアツリーでテストすることがあなたの課題になりますね｡

89
00:05:56,480 --> 00:05:57,890
‫ビデオを一時停止して､ 試してみてください｡

90
00:05:57,980 --> 00:05:58,280
‫なるほど｡

91
00:05:58,280 --> 00:05:58,880
‫お帰りなさい｡

92
00:05:58,880 --> 00:06:07,280
‫まず最初に､ このクラスの外から呼び出される必要があるため､ このシュートメソッドをパブリックにする必要があります｡

93
00:06:07,280 --> 00:06:09,200
‫だから､ ダメージだけ請け負うということにしています｡

94
00:06:09,200 --> 00:06:12,200
‫撮影を行い､ 少し余裕を持たせる､ 息抜きをする｡

95
00:06:12,200 --> 00:06:13,670
‫余白があると見やすくていいですね｡

96
00:06:13,700 --> 00:06:14,540
‫考えるのを手伝ってください｡

97
00:06:14,540 --> 00:06:17,240
‫そして､ BTのタスクシュートに臨みます｡

98
00:06:17,240 --> 00:06:21,500
‫まず､ コントローラがNULLでないことを確認します｡

99
00:06:21,500 --> 00:06:24,380
‫そうでなければ､ 矢印演算子を使うことができません｡

100
00:06:24,380 --> 00:06:27,140
‫ただ､ 一般的には､ これらのNULLチェックを行うことが良い方法です｡

101
00:06:27,140 --> 00:06:35,420
‫ですから､ このAIオーナーが等しくない場合､ 申し訳ありませんがヌルポインターと等しい場合は､ 失敗で早めに返したいところです｡

102
00:06:35,420 --> 00:06:38,570
‫ですから､ AIコントローラーがないとこのタスクは失敗します｡

103
00:06:38,570 --> 00:06:39,920
‫それはとても分かりやすいですね｡

104
00:06:39,920 --> 00:06:43,730
‫そこで､ ETノードの結果コロンを返すということをやってみます｡

105
00:06:43,730 --> 00:06:45,590
‫コロンがそうやって失敗した｡

106
00:06:45,590 --> 00:06:52,580
‫そして､ オーナー・コンポーネントを作成し､ AIオーナーを取得し､ その上で -- を取得する予定です｡

107
00:06:52,580 --> 00:06:54,680
‫実際､ ここにヘッダーファイルを入れる必要があるかもしれません｡

108
00:06:54,680 --> 00:07:02,240
‫そこで､ ハッシュインクルードを行い､ ゲームフレームワークとコントローラにすることにします｡

109
00:07:02,240 --> 00:07:08,240
‫実際､ どんなコントローラでもいいと思うのですが､ AIコントローラが必要だと思います｡

110
00:07:08,240 --> 00:07:16,850
‫なぜなら､ それがポインタのタイプで､ 私たちは戻ることになります｡

111
00:07:16,850 --> 00:07:18,620
‫もしかしたら､ 何か間違っていたのかもしれませんね｡

112
00:07:18,620 --> 00:07:21,440
‫だから､ フォワードスラッシュIは間違っていたようだ｡

113
00:07:21,440 --> 00:07:23,000
‫実はゲームのフレームワークにはないんです｡

114
00:07:23,000 --> 00:07:26,300
‫それを含めてコントローラーを持つだけです｡

115
00:07:26,300 --> 00:07:28,640
‫そのあたりを淡々と教えてください｡

116
00:07:28,640 --> 00:07:29,180
‫そうそう､ そうなんです｡

117
00:07:29,180 --> 00:07:31,040
‫からポーンを得ることができるようになった｡

118
00:07:32,100 --> 00:07:34,890
‫そして､ 先ほども言いましたが､ キャストも必要です｡

119
00:07:34,890 --> 00:07:41,610
‫そこで､ シューターキャラクターのAに対して､ どのような型にキャストする必要があるのか､ キャストを行うことにします｡

120
00:07:41,610 --> 00:07:45,780
‫それが完全な形でシューターキャラクターになっているわけです｡

121
00:07:45,780 --> 00:07:48,990
‫そして､ その結果も確認する必要がありそうです｡

122
00:07:48,990 --> 00:07:51,360
‫でも､ シューターキャラクターは入れないといけないんです｡

123
00:07:51,360 --> 00:07:55,650
‫だから､ ハッシュは一番上にシューターキャラクターを入れるんです｡

124
00:07:56,040 --> 00:07:57,000
‫トッド・H

125
00:07:57,570 --> 00:08:02,100
‫このように､ ポインター型のシューターキャラクターに格納するのです｡

126
00:08:02,100 --> 00:08:04,440
‫スターは私たちのキャラクターになります｡

127
00:08:04,650 --> 00:08:05,430
‫そう呼ぶことにします｡

128
00:08:05,430 --> 00:08:06,510
‫そこに保管する｡

129
00:08:06,870 --> 00:08:14,070
‫そして基本的には､ get -- getは､ 目が現在ポーンをコントロールしていない場合､ nullを返すかもしれないので､

130
00:08:14,070 --> 00:08:17,520
‫どちらも返さないことを確認する必要があります｡

131
00:08:18,310 --> 00:08:25,810
‫あるいは､ このキャストは､ キャラクターが別の型を制御している場合､ 型が問題でなければ､ nullを返すかもしれません｡

132
00:08:25,840 --> 00:08:30,640
‫幸いなことに､ この2つは非常に相性が良いので､ NULLポインタをキャストしようとしても､

133
00:08:30,640 --> 00:08:33,040
‫結果はただのNULLポインタになります｡

134
00:08:33,130 --> 00:08:34,870
‫これらのチェックを1行にまとめたものです｡

135
00:08:35,380 --> 00:08:37,690
‫そうすると､ if文字ができるんです｡

136
00:08:39,150 --> 00:08:41,250
‫NULLポインタに等しい｡

137
00:08:42,390 --> 00:08:44,670
‫そして､ また失敗したい｡

138
00:08:44,670 --> 00:08:45,960
‫だから返す｡

139
00:08:46,990 --> 00:08:49,090
‫ETノードの結果です｡

140
00:08:49,480 --> 00:08:49,900
‫コロン

141
00:08:49,900 --> 00:08:51,910
‫コロンがそうやって失敗した｡

142
00:08:51,910 --> 00:08:56,260
‫そして最後に､ これらのチェックをすべて終えて､ 自分たちがシューターキャラクターになったことを確認したら､

143
00:08:56,260 --> 00:09:04,810
‫「shoot so character arrow」と「shoot like so」を呼び出して､ ようやくシューターができるようになるはずです｡

144
00:09:04,810 --> 00:09:07,570
‫ビヘイビアツリーに移動してみましょう｡

145
00:09:07,840 --> 00:09:16,330
‫ここで､ プルダウンして新しいノードを配置し､ ここにある新しい撮影タスクを探したいと思います｡

146
00:09:16,330 --> 00:09:20,680
‫そして､ コンパイルできたかどうか分からないので､ もう一度全部コンパイルできるかどうか確認します｡

147
00:09:20,680 --> 00:09:25,870
‫それが終わったら､ 再生ボタンを押して､ この人が出てきてシュートするかどうかを確認すればいいんです｡

148
00:09:26,560 --> 00:09:27,400
‫はい､ そうです｡

149
00:09:27,400 --> 00:09:32,860
‫残念なことに､ 彼は繰り返し撮影し､ 自分の足を撃っている｡

150
00:09:32,860 --> 00:09:35,950
‫だから､ 何かがうまく書けないんです｡

151
00:09:35,950 --> 00:09:37,900
‫つまり､ 2つのことがうまくいっていないのです｡

152
00:09:37,900 --> 00:09:43,330
‫まず､ 彼は2発で自殺することに成功しました｡ また､ 1フレームごとに撮影しているようです｡

153
00:09:43,330 --> 00:09:48,160
‫プレイヤーの姿が見えてきて､ そこに移動して､ 撮影が最後のアクションとなり､ それを繰り返し実行することになるので､

154
00:09:48,160 --> 00:09:52,210
‫納得がいくでしょう｡

155
00:09:52,210 --> 00:09:56,350
‫そこで､ 実際にこれをシーケンスにしてみたいと思います｡

156
00:09:56,350 --> 00:10:00,280
‫そこで､ シーケンスノードの作成という名のノードをここにドラッグオフします｡

157
00:10:00,280 --> 00:10:04,810
‫そして､ これからやることは､ 撃って､ 待って､ 撃って､ 待って､ それを無限に繰り返すということです｡

158
00:10:04,810 --> 00:10:07,690
‫だから先に撮影して､ 少し待つ｡

159
00:10:07,690 --> 00:10:14,950
‫そこで､ 撮影と撮影の間に1/2程度の時間をおいて､ これを繰り返すことにします｡ これは､ デコレーターを使えば可能です｡

160
00:10:14,950 --> 00:10:21,490
‫そこで､ 右クリックでデコレーターを追加して､ ループ・デコレーターを探せば､ 何回ループさせたいかがわかる｡

161
00:10:21,520 --> 00:10:22,540
‫3回と書いてある｡

162
00:10:22,540 --> 00:10:23,470
‫3回もいらねえよ｡

163
00:10:23,470 --> 00:10:30,340
‫移動する必要があるか､ プレイヤーを見失って調査する必要があるまで､ 基本的に無限にループするようにしたいのです｡

164
00:10:30,430 --> 00:10:32,970
‫では､ これから再生ボタンを押して､ うまくいくかどうか見てみましょう｡

165
00:10:32,990 --> 00:10:33,610
‫私のところに寄ってくる｡

166
00:10:33,610 --> 00:10:35,890
‫シュート､ シュート､ シュート｡

167
00:10:35,890 --> 00:10:37,510
‫でも､ 実際に殴っているわけではありません｡

168
00:10:37,510 --> 00:10:41,860
‫彼のショットは､ 実際に自分自身に着弾しているのがわかりますね｡

169
00:10:42,520 --> 00:10:46,660
‫そして､ そのバグについては､ 次回の講義で扱う予定です｡

170
00:10:46,660 --> 00:10:47,380
‫現地でお会いしましょう｡

