お茶漬けびより

"あなたに教わったことを、噛んでいるのですよ" 五等分の花嫁 7巻 「最後の試験が五月の場合」より

UE4 で http 通信を行う

少し前に UE4 で http 通信をしようと思い、ネットで方法を探していたのですが、 バージョンの違いか、手順が悪いのか、上手くいかず悩んだ末、UE4 の公式ドキュメントの方法で出来たので、その方法をまとめます。

以下、自己責任で行って下さい。

UE4.10 How To Make HTTP GET Request in C++ - Epic Wiki

上記のURLの方法をそのまま行えば出来ます。

ただ、php 周りの説明が分かっている前提なので、その辺補足出来たらいいなと思い、この記事を書くことにしました。

環境

  • Windows 10
  • UE4.14.3
  • VisualStudio 2015
  • XAMPP 3.2.2

プロジェクトの作成

まず、新規プロジェクトでC++のタブを選択します。 そして、基本コード(BASIC CODE)を選択します。

f:id:pickles-ochazuke:20170213214210p:plain

すると、VisualStudio が立ち上がると思います。気長に全ファイルを読み込むのを待ちます。
読み込めました? では、ビルドしましょう。
とくに問題が起こらないとは思うので、次に進みます。

アクタの作成

UE4 のエディタで http を取得するアクタを作ります。
まず、コンテンツブラウザの新規追加を選び、新規 C++ファイル… を選択します。親クラスは、Actorを選択します。
ファイル名は何でもいいです。今回は、GetHttpActorとしました。あと、パブリック、プライベートは特に選択しませんでした。
クラスを作成をクリックして、リコンパイルが終わるのを待ちます。

ソースコードの編集

では、プロジェクトの中身をいじっていきます。

Build.cs

”プロジェクトファイル名”.Build.cs という名前のファイルが VisualStudio のソリューションエクスプローラーにあると思います。
今回、自分のプロジェクト名は、MyProject(つまりデフォルトの名前)にしたので、MyProject.Build.cs というファイルがあるはずです……ありました。

f:id:pickles-ochazuke:20170213220228p:plain

見つかりましたか? よく探してくださいね。ソリューションエクスプローラーの検索を利用するといいかもしれません。例えば、.Build.cs で検索してみましょう。Games のフォルダ内を探して下さい。もう見つかった? お疲れ様です。では、次に行きましょう。

先ほど見つけたファイル(画像だと MyProject.Build.cs)を開いてください。

MyProject.Build.cs

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore"});

"Http", "Json", "JsonUtilities" という一文があると思います。バージョンによっては違うかも……。 PublicDependencyModuleNames.AddRange を探すといいかもしれません。見つけたら、{}内に以下を追加します。
すると以下のようになると思います。

MyProject.Build.cs

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Http", "Json", "JsonUtilities" });

このファイルはこれで以上です。

Engine.ini

次は、Engine.ini ファイルを探します。VisualStudio は使いません。そこには表示されないからです。 プロジェクトフォルダが保存されている場所に移動してください。そして、今回のプロジェクト名のフォルダの中に移動します。Saved/Config/Windows と移動して下さい。もしかしたら Windows がないかもしれません。Config 以下まで移動したら、Engine.ini を探して下さい。自分は、MyProject/Saved/Config/Windows の下に Engine.ini がありました。そして、てきとうなテキストエディタで開きます。

そして、一番下に以下を追加します。

Engine.ini

[HTTP]
HttpTimeout=300
HttpConnectionTimeout=-1
HttpReceiveTimeout=-1
HttpSendTimeout=-1
HttpMaxConnectionsPerServer=16
bEnableHttp=true
bUseNullHttp=false
HttpDelayTime=0

追加したら、保存して閉じて下さい。またVisualStudio に戻ります。

GetHttpActor.h

http を取得するアクタを作ったと思います。そのヘッダファイルを開きます。
今回だと、GetHttpActor.h です。 まず、以下のようにインクルードファイルを追加します。

GetHttpActor.h

#include "Runtime/Online/HTTP/Public/Http.h"

public: 以下に次の内容を追加します。

FHttpModule* Http;

/* The actual HTTP call */
UFUNCTION()
void MyHttpCall();
 
/*Assign this function to call when the GET request processes sucessfully*/
void OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);

ヘッダファイルは以上です。

GetHttpActor.cpp

次は、ソースファイル GetHttpActor.cpp をいじります。まず、コンストラクタ AGetHttpActor() に以下を追加します。

Http = &FHttpModule::Get();

そして BeginPlay() に以下を追加します。

MyHttpCall();

以下のメンバメソッドを追加します。

GetHttpActor.cpp

/*Http call*/
void AGetHttpActor::MyHttpCall()
{
TSharedRef<IHttpRequest> Request = Http->CreateRequest();
Request->OnProcessRequestComplete().BindUObject(this, &AGetHttpActor::OnResponseReceived);
//This is the url on which to process the request
Request->SetURL("http://localhost:8081/WebApi/getint.php");
Request->SetVerb("GET");
Request->SetHeader(TEXT("User-Agent"), "X-UnrealEngine-Agent");
Request->SetHeader("Content-Type", TEXT("application/json"));
Request->ProcessRequest();
}

/*Assigned function on successfull http call*/
void AGetHttpActor::OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{

 //Create a pointer to hold the json serialized data
 TSharedPtr<FJsonObject> JsonObject;

 //Create a reader pointer to read the json data
 TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());

 //Deserialize the json data given Reader and the actual object to deserialize
 if (FJsonSerializer::Deserialize(Reader, JsonObject))
 {
 //Get the value of the json object by field name
 int32 recievedInt = JsonObject->GetIntegerField("customInt");

 //Output it to the engine
 GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, FString::FromInt(recievedInt));
 }
}

ひとまずは、コピペで構いません。
お疲れ様です。C++ に追加することは以上で終了です。
ビルドが通るか確認しましょう。

これで、GetHttpActor をレベル上に置けば http を取得してくれるのですが、今の状態で行っても http は取得できません。http を発行してくれるサーバがないからですね。では、サーバの準備をしましょう。

XAMPP

サーバを立てる方法はいろいろありますが、今回は XAMPP を使います。 インストールの方法は、ネット上にたくさんあるので、そちらにお任せします。 例えばこれを見るといいでしょう。

XAMPP を立てるときにセキュリティが気になる人は、セキュリティの設定を行うか、ネット回線を切ってしまいましょう。

たぶん XAMPP を使って Apache を立てるとエラーが発生すると思います。 その場合、以下の記事を見ると解決するかもしれません。

余裕があれば、別記事にまとめたいと思います……。

PHP ファイルの作成

XAMPP を上手く入れることが出来ましたでしょうか? お疲れ様です。あと少しで完了です。では、XAMPP を無事インストールしたので、PHP のファイルを作ります。

以下の内容をコピペして下さい。

getint.php

<?php
    //Create a variable to be used in 
    $theVar = array('customInt' => 5);
 
    //Set the headers
    header('Content-Type: application/json');
 
    //Encode the variable, and save the encoded string
    $encoded = json_encode($theVar);
 
    //Output it
    echo $encoded;
?>

そして、getint.php というファイル名にして保存します。 このファイルを以下に置いて下さい。

C:\xampp\htdocs\WebApi

WebApi フォルダは作る必要があると思います。XAMPP をインストールするときに、保存場所を変更した場合は、 C:\ の下にないかもしれません。getint.php ファイルを置くことが出来たら、少しだけ C++ ファイルをいじります(Apache のポート番号を変えていなかったら必要ないかも)。

C++ 側の URL を編集

GetHttpActor.cpp を開いて下さい。 そして、void AGetHttpActor::MyHttpCall() の中を見ます。

Request->SetURL("http://localhost:8081/WebApi/getint.php");

という一文があると思いますが、この SetURL の中身を変えます。 見ると分かるかもしれませんが、中身は URL を表しています。 注意してほしいのは、 localhost:8081 の 8081 です。Apache のポート番号とここのポート番号が合っていないと、正しく処理することが出来ません(URLの場所が見つからないからです)。

サーバを立てる

SetURL の中身を書き換えたら、XAMPP の Apache の Start のボタンをクリックして下さい。すると Apache の文字の周りが黄緑色みたいになると思います。黄色や赤色だと何か問題が発生していると思います。エラーの内容をコピペして検索してみましょう。

問題がない場合、サーバを立てることに成功しています。実際に確認してみましょう。ブラウザを開いて、以下のように入力します。

例えば、http://localhost:94/ とします(ポート番号は人によって異なります)。すると以下のような画面が表示されます。

f:id:pickles-ochazuke:20170214230230p:plain

SetURL と同じURLを指定してみましょう

http://localhost:94/WebApi/getint.php

すると以下のような文章が出ると思います。

{"customInt":5}

これが出ていれば成功です。
では、VisualStudio の方でビルドをします。成功したら、UE4 エディタに戻り、GetHttpActor を選択します。右クリックをして、「GetHttpActor に基づくブループリントクラスを作成します。」 を選択します。そして、てきとうなファイル名(自分は、MyGetHttpActor にしました)を設定し、てきとうな場所に作って下さい。そして、 MyGetHttpActor を開きます。開いたら、コンポーネントを追加で視覚的に置いてあることが分かるようなものを追加しましょう。自分はキューブを追加しました。そしてコンパイルをして、レベル上に配置します。

確認

最後に確認です。

  • XAMPP は正常に動作していますか?
  • Apache は正常に動作していますか?
  • ブラウザを開いて、http://localhost:94/WebApi/getint.php にアクセスすると、php のコードが正しく動いていますか? PHP のコードをコピペしていたら {“customInt”:5} のように表示されるはずです。
  • VisualStudio は正しくビルド出来ていますか?
  • SetURL の中身は http://localhost:94/WebApi/getint.php になっていますか?
  • UE4 のレベル上に GetHttpActor を継承したブループリントクラスのインスタンスが置かれていますか?

では、UE4 エディタのプレイをクリックしましょう。
以下の画像のように文字が表示されるはずです。

f:id:pickles-ochazuke:20170214231918p:plain

無事、http 通信をすることが出来ました。とても小さなことですが、これだけでもいろいろ幅が広がります。長くなりましたが、以上です。 お疲れさまでした。

おわりに

http 周りのソースコード調べないとなぁ……。
あと、分かりづらいところがあればコメントを下さい。

Amazon Prime Music の曲紹介

はじめに

Amazon Prime Music で聴ける曲で、気に入った曲を紹介していく記事。
別々の記事にすると面倒そうなので、計画としてはこの記事に追記していく形。 いつまでも聴けるとは限らないので、その点ご注意。 あと主にOSTです。自分、歌(日本語)は疲れるのであまり聴きません。

OST:オリジナルサウンドトラック

#1.GRAVITY DAZE/重力的眩暈:上層への帰還において、彼女の内宇宙に生じた摂動 OST

タイトル長い。これは、ずっと前から聴ける曲なので、今後も聴ける気がする。
SCE(現SIE)のゲーム。ゲームは癖があるけど、このOSTは本当に最高。Prime Music にはまったきっかけ。万有引力の発見GRAVITY DAZE/重力的眩暈は必聴。
あ、自分はこのゲーム好きです。2 はまだ終わってないけど(2017/03/04 現在)。 Prime で聴けるけどサントラ欲しい。

#2.仮面の勇者~心の迷宮RPGOST

また良曲を見つけてしまった。これだから Prime Music は止められない。
ゲーム自体はやったことないのだけど、Android アプリのゲームらしい。
聴いたらピンと来るかもしれないけど、作曲者は、景山将太(かげやま しょうた)さん。主にポケモンを作曲している人らしい。というのも自分は、スマブラの印象が強かった。
一部しか聴けないし、短いからループが鬱陶しいかもしれないけど、一度は聴いてみて。

仮面の勇者?心の迷宮RPG? オリジナルサウンドトラック

仮面の勇者?心の迷宮RPG? オリジナルサウンドトラック

C++ のエラー処理

本に書いてあったエラー処理の話がためになりそうだったので、ここにまとめておこうかと思います。

参考にした本は、以下の2冊です。

C++のためのAPIデザイン

C++のためのAPIデザイン

 

4.7.4 「エラーの処理方法」を参考にしました。

ゲームエンジン・アーキテクチャ 第2版

ゲームエンジン・アーキテクチャ 第2版

 

 ゲームエンジンアーキテクチャは、3.3 「エラーの補足と処理」を参考にしました。

また、自分が持っている本は第1版です。 

 

では、まとめていきます。

 

まず、C++のためのAPIデザインの内容です。

エラーが発生した場合に対処する方法は、主に3つです。

  • エラーコードを返す
  • 例外を投げる
  • プログラムを停止する

では、一つずつ見ていきます。

エラーコードを返す

これは、エラー内容を値に置き換えることで対処する方法です。単純でありながら非常に便利です。今回はC++なのでエラーの対処法の一つになりますが、純粋なCの場合だと唯一の方法になります。

また、関数自体が何か値を返したいときにどちらか片方しか返せません。この場合は、エラーコードを返し、引数に値を入れることで対処します。

boost::tuple を使うと複数の結果を返すことが出来るようです。

例外を投げる

これはC++の例外処理を使います。関数が投げてきたオブジェクトを受け取り、対処します。例外を使うとエラー処理と通常の処理を別に切り分けることが出来るので、コードが読みやすくなります。また、シンプルなエラーコードよりも多くの情報を持たせることができます。さらに、大抵のデバッガは例外が発生するとそこで処理が止まってくれる(ブレーク)ので、デバッグが行いやすくなります。しかし、想定外の例外が発生するとプログラムが停止する恐れがあります。また通常は一部でも例外を使用する場合、そのアプリ全体で例外処理を正しく行うようにする必要があります。

エラーが発生した場合は、すぐに関数の処理を停止し、直前に割り当てられていたリソースを解放することが最善です。ただし、NULLなどの例外の値は返さないようにしましょう。関数を呼び出した側がさらにその例外の値をチェックする必要があるからです。この場合は、空のリストを返すようにするといいかもしれません。

エラー時に情報はなるべく多く、エラーの原因を早く突き止められるような情報を載せましょう。

 

次にゲームエンジンアーキテクチャの内容です。

エラーには、大きく分けて二つあります。ユーザエラーとプログラマエラーです。

ユーザエラーは、ソフトウェアを使うユーザが引き起こすエラーで、プログラマエラーはコード自体のバグです。ただし、ユーザにはさらに2種類に分けることができます。

一つは、ゲームをプレイしているユーザで、もう一つは、ゲームを制作しているユーザが引き起こすエラーです。

まとめると

ユーザエラー
  • プレイヤーエラー(ソフトウェア使用者)
  • 開発者エラー

プログラマエラー

大きく分けて2つ。細かく分けて3つのエラーの種類があります。

このユーザエラーとプログラマエラー、2つのタイプによってエラーの対処法は変わります。

ユーザエラーの場合、ゲームをプレイしていたりゲーム制作の作業をしているのでゲームや作業を止めるようなことはあってはいけません。処理を継続しながらも、ユーザの役に立つ情報を提供することが大事です。

逆にプログラマエラーの場合は、処理を止める必要があります。そして、デバッグを行うために必要な情報を提供します。

では、さらに細かく見ていきます。

プレイヤーエラー

ゲームをプレイしているときのエラーです。当然ゲームが止まるようなことはあってはいけません。そのような重度なエラーでなくとも、例えば、アイテムが0のときにアイテムを使用すると、そのアイテムは使用されずにプレイヤーに今は使うことが出来ないということを知らせる。これもプレイヤーエラーになるでしょう。

開発者エラー

これは、アーティストやアニメーターなどに起こるエラーです。例えばアセット(や画像)のようなデータを読みこませるときに、そのアセット自身が原因で起こるエラーです。このような問題のあるデータをエラーに気づかずまたは無視されていると、そのデータが入ったまま製品として出されることになります。かといって、問題があるから停止をさせると開発者の手が止まり、作業が進まなくなってしまいます。

なのでこの場合は、エラーであることを開発者に分かりやすく伝えながらも処理を継続させます。

プログラマーエラー

プログラマーエラーの場合は、本来あってはならないのですぐに処理を止めます。こうすることで、プログラマーは嫌でもバグを取り除くことになります。

 

では、エラーの検出、実装方法は何があるのでしょうか。

これはC++のためのAPIデザインにもあったエラーコードと例外。そして、アサートです。アサートは、式をチェックする命令行のことで、これを正しく使用することでプログラマはこれに引っかかると、引っかかった原因を取り除く必要があります。なので、上記の3つのエラーの中では、プログラマーエラーに使われるでしょう。またアサートは通常マクロで定義されるので、製品として出すときは取り除くことが出来ます。

以上、雑なまとめになりますが終わります。

今回のことで分かったのは、エラーの種類には複数あり、その種類によって対処の仕方は全然変わってくるということです。プログラマーのエラーには主にアサートを使い、開発者エラーの場合は、例外処理で処理を継続しつつエラーの情報を提供し、プレイヤーエラーのときは、エラーコードを使用して対処するという感じでしょうか。

そうすると統一性がなくぐちゃぐちゃになりそうですが……。アサートの使い道は分かりやすいですが、エラーコードと例外をどう使い分ければいいかがまだ分かりませんので、エラー処理の対処は、とにかく試行錯誤していくしかなさそうです……。

 

 

UE4 の Blueprint インタフェースについて

Blueprint(以下BP)のインタフェース(インターフェース)について調べました。

概要

BP のインタフェースは、見た目はBPクラスですが中身は少し違います。インタフェースには出来ることと、出来ないことがあります。
出来ること
  • 関数の作成
  • 関数の入出力の追加
  • 純粋(const)化*1
出来ないこと

詳細

インタフェースでは、関数の外枠だけを作り、中身は作りません。その中身は、インタフェースを実装したBPクラスに任せてしまいます。外枠を決めることで、このインタフェースを実装したBPクラスたちは、共通の関数を持つことが出来ます。つまり、同じインタフェースを実装したクラスたちの共通の関数を呼び出すだけで、それぞれ異なる動作を行わせることが出来ます。
インタフェースでは関数の外枠を作るわけですが、その外枠とは、具体的には関数の名前や入力、出力する値、純粋化するかどうかを決めます。逆にこれらは、インタフェースを実装したBPクラス側では編集できません。外枠を変えることが出来ると共通の関数を持つことにならないからです。
説明としては以上です。インタフェース自体は効率化を進めるための機能だと思うので、知らなくてもゲームは作れます。なので、あまりUE4に慣れていない間はあまり気にする必要はないでしょう。
 
作成した関数は、BPクラス側のインターフェースに表示される関数と表示されない関数があります。この違いは何でしょうか?
いろいろ試して分かったことは、BPクラスのインターフェースに表示される関数は、
  • 出力される値(アウトプット)がある
  • 純粋関数である(Const にチェックをしている)
この二つの内一つでも当てはまるものは、BPクラス側のインターフェースとして表示されます。
表示されない関数たちはどこにいったかというと、イベントグラフ上でノード検索を行い(右クリック)、関数の名前を入力すると「イベント○○(関数名)」と表示されます。これをクリックすることでインタフェースの関数をイベントとして追加できます。あとはBPクラス側で実装をすることで関数の中身を作ることができます。

作成、実装

実際の作成や実装の手順は、公式が書いてくれているのでそちらに任せます。
 
 
 

アクターを移動させる Blueprint

移動系のBleuprint(BP)を調べたのでまとめます。
といっても基本的な内容なので、大したものではないのですが。
 
アクターを移動させるためのBPはいろいろあると思います。
今回は、以下を調べました。
  • SetActorLocation
  • SetActorRelativeLocation
  • AddActorWorldOffset
  • AddActorLocalOffset
ここでは、SetActorLocation と SetActorRelativeLocation のことをまとめて、Location 系と呼び、AddActorWorldOffset と AddActorLocalOffset のことをまとめて、Offset 系と呼ぶことにします。 

Location 系

・SetActorLocation 

Input
Target(Actor Reference)
移動させたいアクター(以下ターゲット)を指定
New Location(Vector
世界座標の位置を指定。
Sweep(Boolean)
True のとき有効。ターゲットが物体にぶつかるとターゲットは停止する。
Teleport(Boolean)

指定した位置に瞬間移動するようになる

 
Output
Sweep Hit Result(Hit Result Structure)
Sweep を有効にしているときに何かにぶつかると Hit Result Structureとして返す
Return Value
移動に成功したとき True を返す。Sweep が無効のときは必ず True になる(はず)

詳細
New Location で指定した世界座標(ワールド座標、絶対座標)の位置に物体を動かします。Sweep を有効にすると現在位置から New Location の直線状に物体があるとその物体の手前で止まります。
Sweep についてはいくつか注意する点があります。
  • Sweep の機能は、ターゲットとぶつかる対象の両方が、Collison のオブジェクト応答でブロックしているとき機能する。
  • ターゲットは、ルートコンポーネントコリジョンの設定(オブジェクト応答)をしないと機能しない。
  • 注意ではないが、「オーバーラップイベントを発行させる」は有効にしなくてよい。
2つ目のルートコンポーネントコリジョンの設定をする話は、Sweep の仕様というよりもコリジョンの問題っぽい?*1
Teleport は、ルートコンポーネントについている別のコンポーネント側に移動速度を反映させないようにするようです*2

・SetActorRelativeLocation

Input
Target(Actor Reference)
移動させたいアクター(以下ターゲット)を指定
New Relative Location(Vector
アウトライナ上で親子関係のある、親を中心(0, 0, 0)とした座標位置を指定。
Sweep(Boolean)
True のとき有効。ターゲットが物体にぶつかるとターゲットは停止する。
 
Output
Sweep Hit Result(Hit Result Structure)
Sweep を有効にしているときに何かにぶつかると Hit Result Structure として返す
詳細
機能としてはほとんど同じですが、移動するときの基準となる座標が違います。
SetActorLocation のときは世界座標でしたが、SetActorRelativeLocation の場合は、親の位置を中心(0, 0, 0)とした相対座標(ローカル座標)になります。ここでいう親というのは、アウトライナ上の親子関係のことです。親子関係は、アクタを別のアクタにドラッグすること(アタッチ)で作れます。この場合、ドラッグ側のアクタがドラッグ先のアクタの子になります*3

Offset 系 

・AddActorWorldOffset

Input
Target(Actor Reference)
移動させたいアクター(以下ターゲット)を指定
Delta Location(Vector
ターゲットの現在位置から Delta Location だけ世界座標を軸に移動する。
Sweep(Boolean)
True のとき有効。ターゲットが物体にぶつかるとターゲットは停止する。
Teleport(Boolean)
指定した位置に瞬間移動するようになる。

Output
Sweep Hit Result(Hit Result Structure)
Sweep を有効にしているときに何かにぶつかると Hit Result Structure として返す


・AddActorLocalOffset

Input
Target(Actor Reference)
移動させたいアクター(以下ターゲット)を指定
Delta Location(Vector
ターゲットの現在位置から Delta Location だけ相対座標を軸に移動する。
Sweep(Boolean)
True のとき有効。ターゲットが物体にぶつかるとターゲットは停止する。
Teleport(Boolean)
指定した位置に瞬間移動するようになる。

Output
Sweep Hit Result(Hit Result Structure)
Sweep を有効にしているときに何かにぶつかるとHit Result Structure として返す
詳細
二つをまとめて紹介したほうが、分かりやすいと思ったので同時に説明します。
まずこの二つの名前には Offset というのが付いていますが、Offset とは何でしょうか?
上記の内容が分かりやすかったので、載せておきます。これによると Offset は基準の位置からのズレということです。つまり Offset 系は、ターゲットの位置を基準とした位置から Delta Location の分だけズラすということでしょう。ということは、これを使えばわざわざ Location 系を使うときに、(現在位置+移動量)の値を New Location にする必要はなさそうです。 
では、 Local と World の違いは何でしょうか。これは憶測ですが基準となる軸のことを指していると思っています。つまり、Local の場合はローカル座標(相対座標)を軸とした移動で、World は世界座標を軸とした移動になるということです。
例えば、以下の図のようなローカル座標があるとします。

f:id:pickles-ochazuke:20170104032751j:plain

このローカル座標は、ターゲット自身の座標です。この状態で AddActorLocalOffset の Delta Location に(0, 10, 0)の Vector を設定すると、Y軸方向に 10 進みます。これは下図のように前方に進んでいるように見えます。

f:id:pickles-ochazuke:20170104032849j:plain

では、この Local 座標の Z 軸を 90 度回転します。すると下図のようになりました。

f:id:pickles-ochazuke:20170104032917j:plain

この状態で先ほどと同じように移動させてみましょう。Y 軸方向に 10 進みます。これは、下図のようになります。

f:id:pickles-ochazuke:20170104032938j:plain

つまり、 AddActorLocalOffset はターゲットが回転すると、その影響を受けて移動をするということです。
逆に AddActorWorldOffset はターゲットが回転をしても影響ありません。ローカル座標ではなく世界座標を軸に移動しているからです。もちろん世界座標が回転をすれば、AddActorWorldOffset は影響を受けます。この場合 AddActorLocalOffset は影響を受けないはずです(憶測です……)。
また、ターゲットが親子関係を持っている場合、AddActorLocalOffset はターゲット自身の軸と親の軸、両方の軸を見ている(合わせている?)ようです。ややこしいのですが、例えば親が Z 軸右に 90 度回転していて、ターゲット自身も Z 軸右に 90 度回転している場合、二つの回転を合わせた Z 軸 180 度回転した軸を基準に移動するようになります。
 
以上、Offset 系の説明でした。長々と説明しましたが、説明を読むよりも実際にBPを組んでみたほうが実感が湧くと思います。自分もこの記事を書きながら実行をするなかでいくつか疑問点が出て、実際に試して疑問を解消したので手で動かすことをオススメします(ただ手を動かすのではなく、考えて動かすこと)。
 
最後に、とても参考になった記事
以上です。初めての BP の記事を書いたので間違っているところがあるかもしれません。もし間違いに気付いた方がいらっしゃれば、コメントで指摘していただけると嬉しいです。