﻿1
00:00:04,480 --> 00:00:05,260
‫こんにちは､ ようこそ｡

2
00:00:05,260 --> 00:00:09,820
‫この講義では､ ビヘイビアツリーの中の新しいもの､ サービスを紹介します｡

3
00:00:09,820 --> 00:00:16,390
‫サービスとは何か､ サービスが永続的な動作にどのように役立つか､ そしてC++で独自のサービスを書くにはどうしたらよいかを調べます｡

4
00:00:16,390 --> 00:00:17,380
‫早速､ 飛び込んでみましょう｡

5
00:00:18,060 --> 00:00:23,940
‫これで､ AIコントローラには､ ビヘイビアツリーにないロジックがいくつか残るだけとなりました｡

6
00:00:24,000 --> 00:00:27,000
‫そのひとつが､ 開始位置の設定です｡

7
00:00:27,000 --> 00:00:30,120
‫これはやはり､ Iコントローラからここに設定したいですね｡

8
00:00:30,510 --> 00:00:36,210
‫しかし､ 今のtickのようなことは､ ビヘイビアツリーの中から行いたいものです｡

9
00:00:36,390 --> 00:00:38,100
‫私はここで何をしたいのか？

10
00:00:38,190 --> 00:00:40,020
‫どうすればできるようになるのか？

11
00:00:40,410 --> 00:00:45,750
‫プレイヤーの位置を設定し､ 最後に確認されたプレイヤーの位置を更新します｡

12
00:00:46,200 --> 00:00:51,540
‫いずれも､ ブループリント・サービスというものがあれば可能です｡

13
00:00:51,540 --> 00:00:56,030
‫では､ 設計図を見てみましょう｡

14
00:00:56,040 --> 00:01:03,870
‫そこで､ 私のAIでビヘイビアツリーを開き､ メインウィンドウにドッキングさせたら､ サービスとは何かということを示す必要があります｡

15
00:01:03,870 --> 00:01:10,770
‫今まで使ったことがなかったのですが､ 基本的には特定のパスがアクティブになるたびに､ tick毎､

16
00:01:10,770 --> 00:01:14,790
‫あるいはそう頻繁に何かを実行する方法です｡

17
00:01:14,790 --> 00:01:22,380
‫ですから､ もし「チェイス」ビヘイビアにサービスがあれば､ 「チェイス」ビヘイビアがアクティブな間は､

18
00:01:22,650 --> 00:01:28,800
‫移動､ 射撃､ ウェイト付けなど､ 常に何らかのコードが実行されることになります｡

19
00:01:28,800 --> 00:01:31,200
‫しかし､ もし私たちが調査中ならそれはないでしょう｡

20
00:01:31,410 --> 00:01:35,740
‫まさにこういう時にサービスを使いたいわけです｡

21
00:01:35,760 --> 00:01:38,070
‫では､ サービスの例を挙げてみましょう｡

22
00:01:38,070 --> 00:01:44,670
‫遊んでいて気づいたのは､ AIが射程距離に入ってきて､ こちらが移動すると､ AIはこちらを見ようと回転しないのですが､

23
00:01:44,670 --> 00:01:51,480
‫ここはすでに組み込まれているサービスで解決できますね｡

24
00:01:51,480 --> 00:02:00,210
‫このノードを右クリックして「サービスの追加」を選択し､ デフォルトのフォーカスサービスを探すと､ 色が変わって緑色になっているのがわかります｡

25
00:02:00,390 --> 00:02:05,370
‫また､ デフォルトのサービスを選択すると､ デコレータが行うようにシーケンスノードの上にではなく､

26
00:02:05,370 --> 00:02:06,870
‫その下に配置されます｡

27
00:02:07,350 --> 00:02:11,940
‫そこで､ デフォルトのフォーカスを選択した状態で､ 次にフォーカスするものを選択します｡

28
00:02:11,940 --> 00:02:17,460
‫そしてこの場合､ プレーヤーの位置に焦点を当てたいので､ 先に進み､ 保存を押して､ 再生を押してください｡

29
00:02:17,460 --> 00:02:23,370
‫そして今､ 私たちが見に行き､ 動き回ると､ 彼が回転しながら私たちを追っているのがわかります｡

30
00:02:23,790 --> 00:02:24,840
‫かっこいいもの

31
00:02:24,930 --> 00:02:38,940
‫今度は､ C++で同様のサービスを実装して､ プレイヤーの位置をずっと更新し､ 追跡中に最終的に判明したプレイヤーの位置を更新できるようにしたいと思います｡

32
00:02:38,940 --> 00:02:45,000
‫ビヘイビアツリーの適切な場所にいるときだけ､ 最後に確認したプレーヤーの位置を実行できるので､

33
00:02:45,000 --> 00:02:54,870
‫tickで実行するよりも少し効率的です｡

34
00:02:54,870 --> 00:03:02,880
‫サンドボックスに移動して､ コンテンツブラウザで新しいC++クラスを追加し､ すべてのクラスを表示するようにして､ ここでどんなオプションがあるのか見てみましょう｡

35
00:03:03,000 --> 00:03:11,370
‫BTサービスを探しているのですが､ BTタスクの時と同じように､ いくつかのオプションがあり､

36
00:03:11,490 --> 00:03:18,180
‫Blackboard Baseもあります｡

37
00:03:18,180 --> 00:03:20,640
‫例えば､ プレイヤーの位置であるべきでしょうか？

38
00:03:20,640 --> 00:03:23,190
‫最後に判明したプレイヤーの位置であるべきでしょうか？

39
00:03:23,310 --> 00:03:28,830
‫Blackboard Baseを選択した状態でnextを押して､ このBT serviceを呼び出し､

40
00:03:28,830 --> 00:03:36,540
‫プレイヤーロケーションにアンダースコアをつけて､ 先に進み､ クラスを作成します｡

41
00:03:36,660 --> 00:03:42,870
‫コンパイルが完了したら､ Visual Studio のコードに移動して､ Service Blackboard

42
00:03:42,870 --> 00:03:48,390
‫Base Call を継承した BT サービスプレーヤーの場所を確認できます｡

43
00:03:48,390 --> 00:03:49,110
‫それが私たちの望みでした｡

44
00:03:49,110 --> 00:03:51,870
‫さて､ これからどのような機能でこの中に入っていくのでしょうか｡

45
00:03:52,050 --> 00:04:01,650
‫さて､ できるだけシンプルな機能で動かそうと思います｡ 基本的には最後に判明したプレイヤーの位置の値を設定するだけです｡

46
00:04:01,650 --> 00:04:08,340
‫このキーはビヘイビアツリーで設定されますが､ ここではテキストではなく､ プレイヤー

47
00:04:08,340 --> 00:04:12,390
‫-- ロケーションを取得して黒板キーに設定します｡

48
00:04:12,390 --> 00:04:17,640
‫また､ 視線チェックは行いません｡ ビヘイビアツリーの中で､ 追いかけるときだけ実行するのであれば､

49
00:04:17,640 --> 00:04:21,930
‫視線チェックは必要ないからです｡

50
00:04:21,930 --> 00:04:25,470
‫私たちは､ 自動的にそれがわかっているプレーヤーを見ることができます｡

51
00:04:25,470 --> 00:04:29,010
‫そこで､ もうひとつ､ サービスの中で行うことを簡略化しました｡

52
00:04:29,520 --> 00:04:36,840
‫BTサービスのメソッドコールを取得する方法を知っていれば､ これはかなり簡単なはずです｡

53
00:04:37,230 --> 00:04:41,940
‫そこで､ BTのサービスにはどんなものがあるのか､ 見てきましょう｡

54
00:04:41,940 --> 00:04:44,100
‫ドキュメントはどうなっているんだ､ 何ができるんだ？

55
00:04:44,130 --> 00:04:51,120
‫主なメソッドは､ "Become relevant" "C relevant" "the tick node" "search start "です｡

56
00:04:51,150 --> 00:04:52,020
‫検索開始時｡

57
00:04:52,020 --> 00:04:54,240
‫特に興味はないが､ ティックノード｡

58
00:04:54,240 --> 00:05:00,870
‫そう､ そこで､ このサービスがアクティブな経路にあることを常にアップデートしてもらうのです｡

59
00:05:01,110 --> 00:05:02,970
‫だから､ そういうときにこそ､ 実装したいんです｡

60
00:05:02,980 --> 00:05:06,180
‫私たちは､ このファイルを検索して､ ここにある完全な署名を見つけに行くのです｡

61
00:05:06,390 --> 00:05:08,010
‫ここにあるのがわかります｡

62
00:05:08,010 --> 00:05:09,270
‫えーと､ どのセクションにあるんだっけ？

63
00:05:09,270 --> 00:05:10,770
‫保護されたセクションの下にあります｡

64
00:05:10,770 --> 00:05:16,890
‫そこで､ 作成したBTサービスに行き､ 保護されたセクションを作成します｡

65
00:05:17,530 --> 00:05:24,220
‫そして貼り付けます｡ BT Serviceは親クラスから自分自身で継承していたので､ ここでは自動的にオーバーライドされていますが､

66
00:05:24,220 --> 00:05:27,660
‫自分自身で再度オーバーライドしても問題はありません｡

67
00:05:27,670 --> 00:05:32,920
‫コントロールシフトPで実装を作成し､ superに呼び出したいのです｡

68
00:05:32,920 --> 00:05:39,550
‫そこで､ スーパーティックノードが欲しいのですが､ 自分のコンプとノードのメモリを渡したいのです｡

69
00:05:39,550 --> 00:05:41,500
‫あと､ えーと､ 他にもいろいろあるんですけど｡

70
00:05:41,500 --> 00:05:49,960
‫Delta秒と､ 同様に渡す必要があるものがあり､ 最後にセミコロンでtickノードの実装を終了させる必要があります｡

71
00:05:49,960 --> 00:05:59,590
‫ここでは､ 基本的にIコントローラCPから､ 黒板コンポーネントを取得し､ vectorとして値を設定する動作を行いたいと考えています｡

72
00:05:59,590 --> 00:06:04,120
‫さて､ オーナーコンポーネントリファレンスから黒板の部品を入手する方法がわかりました｡

73
00:06:04,120 --> 00:06:05,410
‫ということは､ かなりわかりやすいですね｡

74
00:06:05,410 --> 00:06:17,980
‫owner comp dotを実行し､ get blackboard componentを実行します｡ ここで､ ビヘイビアツリーのフォワードスラッシュ黒板コンポーネントをハッシュでインクルードする必要があることを思い出してください｡

75
00:06:17,980 --> 00:06:20,410
‫そして､ 矢印演算子を使うことができます｡

76
00:06:20,500 --> 00:06:27,370
‫そして､ ここでできることは､ 値をvectorとして設定すること､ そしてキーが必要であることです｡

77
00:06:27,370 --> 00:06:30,490
‫まあ､ 対処の仕方はわかっているのですが､ ちょっと記憶をたどってみましょう｡

78
00:06:30,490 --> 00:06:38,380
‫BTサービスのアンダースコア黒板ベースにアクセスすると､ タスクと同じように､ 黒板を選択状態にするキーがあるのがわかります｡

79
00:06:38,380 --> 00:06:39,310
‫それを利用するのです｡

80
00:06:39,340 --> 00:06:45,940
‫Get selected Blackboard Keyはビヘイビアツリーで選択されたキーを取得し､ 次にベクター値を取得します｡

81
00:06:45,940 --> 00:06:46,840
‫それをどこで手に入れるのか？

82
00:06:46,840 --> 00:06:48,580
‫AIコントローラーと全く同じにします｡

83
00:06:48,580 --> 00:06:52,960
‫これからプレーヤーを......何よりもまず､ このトップで｡

84
00:06:52,960 --> 00:06:57,880
‫そして､ これがNULLかどうかをチェックし､ ゲームプレイの静止画も含める必要があります｡

85
00:06:57,880 --> 00:07:06,130
‫そこで､ ゲームプレイのスタティックがコントローラCPからプレイヤーサービスのプレイヤーロケーションにインクルードされていることを確認しましょう｡

86
00:07:06,790 --> 00:07:13,750
‫そして､ もしプレイヤーのポーンがヌルポインタと等しい場合は､

87
00:07:13,750 --> 00:07:20,080
‫再び早期にリターンすることになります｡

88
00:07:20,140 --> 00:07:30,070
‫そして､ プレイヤーポーンを使用して､ アクターの位置を取得します｡ また､ ここでインクルードを行う必要があるかもしれません｡

89
00:07:30,070 --> 00:07:30,970
‫どうするかは､ これからです｡

90
00:07:30,970 --> 00:07:34,420
‫まあ､ 安全には越したことはないですからね､ こういうのは明示的に｡

91
00:07:34,420 --> 00:07:38,890
‫そこで､ ゲームフレームワークのincludeを行い､ フォワードスラッシュを行います｡

92
00:07:38,890 --> 00:07:46,090
‫Hにポーンと置かれるので､ ここで全てを確認した上で､ vectorとして値を設定しているだけです｡

93
00:07:46,090 --> 00:07:47,350
‫それだけで十分なはずです｡

94
00:07:47,350 --> 00:07:49,210
‫では､ コンパイルして､ これがうまくいくかどうか見てみましょう｡

95
00:07:49,210 --> 00:07:50,350
‫実は､ もうひとつ｡

96
00:07:50,350 --> 00:07:54,700
‫おそらく素敵なきれいな名前が欲しいので､ ここにコンストラクタを用意する必要があります｡

97
00:07:54,700 --> 00:08:00,550
‫そこで､ クラス名となるコンストラクタを含むpublicセクションを作成し､

98
00:08:00,550 --> 00:08:03,760
‫その実装を作成していきます｡

99
00:08:03,760 --> 00:08:08,590
‫自分の実装をtickノードの実装の上に持ってきて､ ノード名をit

100
00:08:08,590 --> 00:08:17,680
‫should be update player locationに等しく設定して､ ビルドして動作するか確認してみましょう｡

101
00:08:17,710 --> 00:08:19,300
‫セミコロンが抜けていたようです｡

102
00:08:19,300 --> 00:08:20,170
‫もう一度やってみよう｡

103
00:08:20,170 --> 00:08:23,350
‫それがうまくコンパイルされると､ 敵に乗り移ることができるんです｡

104
00:08:23,350 --> 00:08:34,600
‫私や､ 設定の焦点と同様に､ 我々はここに表示されているプレイヤーの場所として持っている新しいサービスを追加したいと思います｡

105
00:08:34,600 --> 00:08:40,720
‫これは､ 0回ごとにカチカチと音を鳴らすことを望んでいることがわかります｡  4から0へ｡  6秒

106
00:08:40,720 --> 00:08:43,990
‫これはtickを使うよりも良い方法です｡ なぜなら､ tickはここで毎フレーム実行されることが分かっているからです｡

107
00:08:43,990 --> 00:08:46,660
‫これは実行頻度が少ないので､ 良いことだと思います｡

108
00:08:46,660 --> 00:08:52,450
‫そして､ 細部に入り､ 黒板キーを作成し､ ドロップダウンして､ 更新したいのはプレーヤーの位置だけでなく､

109
00:08:52,450 --> 00:09:02,800
‫最後に確認したプレーヤーの位置であることを選択することができます｡

110
00:09:02,800 --> 00:09:11,230
‫もう一つのサービスノードは､ AIコントローラの動作として､ ティックに潜り込み､ 何が残っているかを確認するために作成します｡

111
00:09:11,230 --> 00:09:17,530
‫ここでやるべきことは､ 視線が合っているかどうかを条件としてプレイヤーの位置を更新することです｡

112
00:09:17,530 --> 00:09:19,390
‫そこで､ プレイヤーの位置を更新させるようにしたいのです｡

113
00:09:19,390 --> 00:09:22,450
‫見通しが良ければ､ その場所をクリアにする｡

114
00:09:22,450 --> 00:09:25,750
‫つまり､ 少し変わった動作になるので､ 新しいサービスノードになるわけです｡

115
00:09:25,780 --> 00:09:28,270
‫新しい新しいC++のクラスを追加する予定です｡

116
00:09:28,270 --> 00:09:33,220
‫すべてのクラスを表示し､ BTサービス､ アンダースコアの黒板ベース､

117
00:09:33,220 --> 00:09:39,910
‫基本クラス､ そしてビートサービス・アンダーコアと名付けます｡

118
00:09:40,590 --> 00:09:44,010
‫見かけたらプレイヤーの位置を教えてください｡

119
00:09:44,130 --> 00:09:46,980
‫そして､ そのクラスを作成してください｡

120
00:09:46,980 --> 00:09:51,930
‫しかも､ ほとんど見たことのないものばかりですから､ このサービスを導入するのはあなたのチャレンジになりますね｡

121
00:09:51,930 --> 00:09:57,570
‫つまり､ AIコントローラーにあるコードを使ってチックノードを実装するわけです｡

122
00:09:57,570 --> 00:10:04,350
‫目安としては､ BTサービス内からAIコントローラーのポインターを手に入れることです｡

123
00:10:04,350 --> 00:10:11,340
‫これはBTタスクでやったことと全く同じなので､ AIコントローラーのポインターを手に入れるためのガイダンスとして使ってください｡

124
00:10:11,520 --> 00:10:15,270
‫視線を確認するためには､ AIコントローラーのポインタが必要です｡

125
00:10:15,270 --> 00:10:21,630
‫視線はAIコントローラーのメソッドであることを忘れないでください｡ そして､ 視線のチェックに応じてキーを更新またはクリアしてから､

126
00:10:21,660 --> 00:10:27,270
‫このノードをビヘイビアツリーに配置する必要があります｡

127
00:10:27,270 --> 00:10:32,130
‫このサービスを実行するために､ ビヘイビアツリーのどのレベルが適切だと思われますか？

128
00:10:32,130 --> 00:10:33,660
‫それをどう考えるか｡

129
00:10:33,660 --> 00:10:37,110
‫ちょっとアゴを掻いて､ ビデオを一時停止して､ やってみる｡

130
00:10:38,070 --> 00:10:38,310
‫なるほど｡

131
00:10:38,310 --> 00:10:38,870
‫お帰りなさい｡

132
00:10:38,880 --> 00:10:44,670
‫そのため､ Visual Studioのコードの上に新しいビューティサービスを開くことができました｡

133
00:10:44,670 --> 00:10:51,750
‫このヘッダーはほとんど同じになるので､ 先に進んで新しく生成したヘッダーにコピーします｡

134
00:10:51,750 --> 00:11:00,300
‫例外は､ コンストラクターの名前を一致するように変更する必要があることです｡

135
00:11:00,300 --> 00:11:07,650
‫次に､ コンストラクタの実装を作成し､ ノード名を付けて､ プレーヤーの位置が確認されたら更新し､

136
00:11:08,010 --> 00:11:12,690
‫最後にセミコロンを追加します｡

137
00:11:12,720 --> 00:11:14,400
‫今回はそれを忘れないようにしよう｡

138
00:11:14,400 --> 00:11:25,080
‫次にC++に戻ってtickノードを実装し､ プレイヤーの位置がわかればコピーして渡します｡

139
00:11:25,080 --> 00:11:32,610
‫CP そして､ スーパーへの呼び出し､ プレイヤーポーンの取得､ NULLリターンのチェックをコピーしていくだけです｡

140
00:11:32,610 --> 00:11:36,090
‫実際､ 本体ごとコピーして､ そこから修正することになります｡

141
00:11:36,600 --> 00:11:43,380
‫黒板コンポーネント､ ゲームプレイ静止画､ ポーンへのアクセスが必要なので､

142
00:11:43,740 --> 00:11:50,160
‫黒板コンポーネントへのアクセスをインクルードしてコピーしています｡

143
00:11:50,160 --> 00:11:53,130
‫実際､ 機能の多くはここで共有されています｡

144
00:11:53,130 --> 00:12:00,360
‫このコードをどうにかして共有してもらうという考え方もありますが､ 気にするほど重複していないと思います｡

145
00:12:00,840 --> 00:12:05,430
‫ここでやらなければならないのは､ アイ・コントローラーの有無も確認することです｡

146
00:12:05,430 --> 00:12:19,470
‫オーナーコンポーネントまたはオーナーコンプドットゲットIオーナーがヌルポインターと等しい場合は､ この段階で先に進んでリターンすることになりますね｡

147
00:12:19,950 --> 00:12:24,360
‫そして､ 次に行いたいのは､ 視認性の確認です｡

148
00:12:24,360 --> 00:12:34,440
‫そこで､ if owner comp dot get I ownerを行い､ ここに矢印を書き､ ここにコントローラを入れる必要があります｡

149
00:12:34,440 --> 00:12:36,900
‫だから､ ハッシュインクルードになるんです｡

150
00:12:38,120 --> 00:12:41,810
‫そして､ IコントローラHになるのです｡

151
00:12:42,380 --> 00:12:48,470
‫では､ lineを行いたいのですが､ ここでは正しい使い方を確認しましょう｡

152
00:12:48,470 --> 00:12:54,650
‫IコントローラーのCPに移動すると､ ライン・オブ・サイト2になっているのが､ 私たちが欲しいものです｡

153
00:12:54,650 --> 00:13:00,380
‫視線2......それから､ プレイヤーポーンへの視線も必要ですね｡

154
00:13:00,380 --> 00:13:02,870
‫この場合､ プレイヤーポーンへの視線は確保されているのでしょうか？

155
00:13:03,320 --> 00:13:04,820
‫CPでやっていることなのか？

156
00:13:04,820 --> 00:13:05,810
‫再確認しておこう｡

157
00:13:05,810 --> 00:13:06,680
‫はい､ そうです｡

158
00:13:07,220 --> 00:13:11,450
‫次に､ 別の値を設定してきたいと思います｡

159
00:13:11,510 --> 00:13:15,800
‫つまり､ プレイヤーポーンのアクター取得位置にベクター値を設定するわけです｡

160
00:13:15,800 --> 00:13:18,620
‫そうですね､ 他に視界が開けていればの話ですが｡

161
00:13:18,620 --> 00:13:22,430
‫ラインオブサイトがない場合は､ その値をクリアする必要があることが分かります｡

162
00:13:22,430 --> 00:13:26,030
‫つまり､ オーナーコンポーネントと黒板コンポーネントを取得することに変わりはありません｡

163
00:13:26,060 --> 00:13:37,790
‫それから､ 値をクリアして､ 選択された黒板のキーの値をまだクリアしています｡

164
00:13:37,790 --> 00:13:41,480
‫見られたら､ コンパイルして､ うまく動くかどうか見てきましょう｡

165
00:13:41,480 --> 00:13:42,710
‫コンパイルは成功した｡

166
00:13:42,710 --> 00:13:44,570
‫ビヘイビアツリーに入りましょう｡

167
00:13:44,570 --> 00:13:50,420
‫なぜなら､ プレイヤーの位置が設定されていることを前提に､

168
00:13:50,420 --> 00:13:59,600
‫他の動作を中止できるようにする必要があるからです｡

169
00:13:59,600 --> 00:14:02,810
‫だから､ いつでも設定・解除できるようにする必要がある｡

170
00:14:02,900 --> 00:14:08,870
‫そこで､ トップレベルのセレクタを右クリックして､ サービスを追加し､ プレイロケーションを追加します｡

171
00:14:09,200 --> 00:14:15,260
‫そして､ そのサービスノードを選択して､ 黒板キーを選択する必要があります｡ これは､ プレーヤーの位置となります｡

172
00:14:15,710 --> 00:14:22,220
‫だから､ プレイヤーロケーションに設定されたその1つは､ アップデートプレイヤーロケーション､ より多くのダム1が最後に知られているプレイヤーロケーションを更新しています｡

173
00:14:22,550 --> 00:14:33,740
‫そして､ AIコントローラーに移動して､ TTICにあるこのコードをすべて削除することができるはずです｡

174
00:14:33,740 --> 00:14:36,350
‫そして､ 先に進んでコンパイルし､ それがうまくいくかどうかを確認することができます｡

175
00:14:36,350 --> 00:14:41,060
‫エディターでプレイして､ まだ敵が近づいてくるかどうか見てみよう｡

176
00:14:41,060 --> 00:14:46,580
‫走ってきて見失ったかと思うと､ また戻って来て撃ち始める｡

177
00:14:46,580 --> 00:14:46,850
‫うん｡

178
00:14:46,850 --> 00:14:55,730
‫基本的にはすべて以前と同じように動作していますが､ 今はすべて私たち自身がC++で書いたサービスを通じて行っています｡

179
00:14:55,760 --> 00:15:03,290
‫次回の講義では､ AIが撃ち続け､ 最終的に自滅してしまうという厄介なバグを修正する予定です｡

180
00:15:03,290 --> 00:15:04,160
‫現地でお会いしましょう｡

