お茶漬けびより

学んだことを整理する場所です。主に、C++, Unreal Engine 4 (UE4) を扱っていました。最近は、仕事方面で使っている言語やツールを紹介したいと思います。たまに趣味や雑記も。

Microsoft の CI ツールが多くて思考停止したので、整理してみる

【経緯】

唐突にCIツールを使ってみようと思い、Jenkins を自宅サーバ(久々に起動)に入れてみるも、家で作っているのはVisual C++ なので意味ないのでは? と気づき、調べているとMicrosoft のCI ツールを発見。TFS、VSTS、VSO……何がどう違うのか。

【CIとは】

Ceizokuteki Integration のこと……ではなく、Continuous Integration のこと。つまり継続的統合。Cは、コンテニューだと思っておけば覚えやすいかも。まだ利用したことないので理解は浅いけど、変更した内容をすぐに反映、ビルド、テストをすることでバグを早期発見し、品質を高める方法。

で、今回はそのCI環境を作るためのツールを調べたところ、Microsoft の CI ツールが複数あって、混乱したので調べた。

今回紹介するのは、以下

上から時代が古い順に並べたつもり。

簡単に説明すると、初めに Microsoft 製 CI ツールが出たのが、TFS。CI のための基本的な機能(ビルド、テスト、リリースなど)を提供してくれる。ただし、TFS を動かすためのサーバは自分たちで用意する必要がある。

次に VSO 。簡単に言うと Visual Studio のオンライン版。さらに機能が追加され、TFS のような機能も備えている。要は VS + TFS かも。

VSTS。これが今一番新しい。TFS のような機能をクラウドサービスとして提供している。サーバを持つ必要がないので、CI に集中することが出来る。

で、VSTS を動かしているのが Azure。Azure が動かしているので(?)簡単に Azure と連携をすることが出来る。Web 系開発のときに Azure との相性が良い。

気にする必要があるのは、TFS と VSTS。Azure は人による。

TFS より VSTS の方が便利そうだけど、TFS はローカルで構築することが出来るので、全く利用価値がないわけではない。

全体としては以上。一つ一つ紹介していく

Team Foundation Server(TFS)】

大きな機能として、バージョン管理、アジャイル開発をするときに便利なツールやビルド、パッケージ、テスト、リリースを自動で行うなどの機能を備えている。

ローカルで解決したいときは、こいつをインストールする。

Visual Studio Online(VSO)】

特に重要ではないので簡単に説明する。

VS + TFS のオンライン版。つまりクラウドサービス。現在は、Visual Studio Team Services(あとで紹介)という名前に変わっている。なので、説明は VSTS に譲る。

Visual Studio Team Services】

一番名前が長い。CIのための基本的な機能はもちろん。サーバの構築が不要で、サインアップするだけで利用することが出来る。

このサービスは、Azure の上で動いているので、Azure のサービスの一つだと思って良さそう。個人で使うだけなら無料で利用可能(利用人数によるが)。Azure との相性が良いので、Azure を使った、Web アプリを開発したり、Xamarin を使ったスマフォアプリ開発などに便利(どちらも作ったことないので見当違いなこと書いてるかも……)。

CI 機能使わないから関係ないと思っている人にも知っていて欲しいのが(ここまで読んでいるか怪しいけど)、バージョン管理。

例えば、バージョン管理のためのサーバが欲しい。けど、Github は無料だと公開しないといけない恥ずかしいって人は、VSTS を使うと良いかもしれない(あまりそういう籠もる姿勢はおすすめしないけど)。なんとバージョン管理をプライベートで利用できる。バージョン管理のツールは Git に近い感じ。Git も使うことが出来る。

Visual Studio 2017 では、VSTS を利用するための機能が強化されるそうなので、VSTS を検討する余地はあるかと。 

【参考資料】

Team Foundation Server - Visual Studio

www.visualstudio.com

blogs.msdn.microsoft.com

Visual Studio Team Services - Visual Studio

  • Azure

docs.microsoft.com

www.atmarkit.co.jp

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 の記事を書いたので間違っているところがあるかもしれません。もし間違いに気付いた方がいらっしゃれば、コメントで指摘していただけると嬉しいです。

プログラミングするときに使うショートカットキー集

個人的によく使うショートカットキーをまとめてみました。
随時更新
 
環境は、ノートパソコンの一画面を想定
以下のショートカットキーを載せています。
Widnows10
ノートで開発するとき画面が一画面かつ小さいので作業がしづらいです。
なので、Windows10から追加された仮想デスクトップを使っています。
 
仮想デスクトップ間の移動
Windowsキー + Ctrl + (← or →)
アプリケーションの切り替え
Alt + Tab
 
 
 
 
 
 
 
 
 
Visual Studio 2017 RC
Visual Stduio のショートカットキーは、最近調べ始めたのでところどころマウス使っています。
&& は、「その後に続けて」という意味で使っています
 
タブ切り替え
Ctrl + Tab
Ctrl + K && Ctrl + C
Ctrl + K && Ctrl + U
矩形選択
Shift + Alt
文字検索
Ctrl + F
文字置換
Ctrl + H
入力補間
Ctrl + Space
ビルド
Ctrl + Shift + B
デバッグなしで開始
Ctrl + F5
デバッグの開始
F5
 
 
 
Google Search
あまりショートカット気にしなかったのですが、使ってみると便利でした。
 
 検索バーに移動
/(全角でも可。ただし検索バーに「・」が表示される)
検索結果に移動
Tab
検索結果の移動
(↑キー, ↓キー) or ( j, k )
 
 
 
Microsoft Edge
最近使い始めました。とくに不満なく使えています。
 
タブを開く
Ctrl + T
タブを閉じる
Ctrl + W
戻る
Ctrl + ← or Backspace
進む
Ctrl + →
アドレスバーに移動
Ctrl + L