2017年、Vim周り見直し

半年に1回は見直しています。今回は結局大して変えませんでした。

世間では、Neovimに乗り換えましたとか、プラグイン管理をdein.vimに乗り換えましたという人が多いようですが、自分はNeovimは、まだ不安があるのと、そんなにメリットが分かっていないので、もうちょい様子見。
結局 最新のKaoriya版MacVimに。

dein.vimも設定ファイルを書き換えるのがめんどくさいのと、Neobundleでも速度に満足しているので、今回は見送り。

継続して使用するプラグイン

Neobundle

プラグイン管理。dein.vimへの移行が推奨されていますが現状に満足しているのでそのまま。
半年後に再検討予定。

unite

インクリメンタルサーチで色々探して、色々出来る

unite help

全ヘルプ内をインクリメンタルサーチで探せて便利

machit

括弧の上で%を押すと対応する反対側の括弧に飛べるけど、それをいろんなものに拡張してくれる。
begin,endとか、とか。

vim-indent-guides

インデントに色を付けて見やすくする

vim-quickrun

コードをすぐに実行して確認

neco-look

lookを使って英単語保管機能

vim-bufonly

BufOnlyで自分以外のbufferを削除する

syntastic

syntax checkプラグイン

neosnippet.vim, neosnippet-snippets

スニペットプラグイン。あまり使いこなせていない。

vimfiler

ファイラープラグイン。あまり使いこなせていない。

Omnisharp, vim-dispatch

C#でインテリセンスを効かせるために。

vim-csharp

C#シンタックスハイライト

lightline

挿入モード、ヴぃジュアルモードなどのモードが見やすくなる

vim-easy-align

コード整形プラグイン

vim-textobj-indent, vim-textobj-user,

インデントが揃っている部分をテキストオブジェクトにしてくれる

vim-commentary

コメントアウトしたりコメントインしたりを簡単に

今回から入れてみたプラグイン

vim-colors-solarized

カラースキームsolarized。長いことdesertで固定されていたので、ちょっと気分を変えてみることに。

vim-endwise

Ruby向けにendを自動挿入してくれる。しかしRubyのコードを描く頻度は少ない。

vim-monster

Ruby用の補完。しかしRubyのコードを描く頻度は少ない。

ruby_hl_lvar

Ruby用のローカル変数ハイライト。しかしRubyのコードを描く頻度は少ない。

vim-closetag

tagを閉じてくれる

vim-gitgutter

Git管理下のファイルをVim上で変更内容を確認する

vim-fugitive

VimからGitを使いやすくしてくれる

vim-quickhl

一度に複数の検索結果をそれぞれ異なる色でハイライトできる

yankround

ペースト時にyankの履歴を辿れる

使用を停止、もしくは一時停止するプラグイン

vim-trailing-whitespace

行末にあるスペースを可視化してくれる。
見えると、消したくなる。そして消すのがあまりにめんどくさいので、使わないことに。

unite-mark

マークした箇所をUniteで探して飛べる
結局、マークをあんまり使わなかった

vimshell

VimからShellを起動するスクリプト
結局、あんまり使わなかった

vim-visualstar

ビジュアルモードで選択して、*を押したときに選択した内容で検索をできる。
結局、あんまり使わなかった

vim-ref

vimで辞書をみるプラグイン
結局、あんまり使わなかった

vim-surround

テキストを囲むことに特化したプラグイン シングルクオートとダブルクオートの入れ替えなど
結局、あんまり使わなかった

onedark

AtomのOne Darkを再現するためのカラースキーマ
c#ではイマイチな気が...

AnsiEsc.vim

ログファイルを色づけしてくれる
結局、あんまり使わなかった

ctrlp

yankroundと一緒に使うことでyankの履歴を表示して選択して、ペーストってできる。
自分の環境では何故かうまく動作しなかったのと、Unite yank で良いかなぁと。

vim-processing

processingとvimを連携するプラグイン。もうprocessingを使うことは、ほぼほぼないだろうということで。

AndroidManifest.xml:20: error: Error: No resource found that matches the given name (at 'theme' with value '@style/Theme.IAPTheme のエラー対応

UnityでAdMobを入れ直したからか、Android版をビルドするときに以下のようなエラーが出るようになっちゃいました。

CommandInvokationFailure: Failed to re-package resources.
/Users/wakepon/Library/Android/sdk/build-tools/23.0.2/aapt package --auto-add-overlay -v -f -m -J "gen" -M "AndroidManifest.xml" -S "res" -I "/Users/wakepon/Library/Android/sdk/platforms/android-24/android.jar" -F bin/resources.ap_ --extra-packages com.chartboost.sdk.unity:com.android.vending.billing:com.google.unity:com.unity.purchasing.googleplay:com.unity.purchasing -S "/Users/wakepon/projects/Solokus/Temp/StagingArea/android-libraries/GoogleAIDL/res" -S "/Users/wakepon/projects/Solokus/Temp/StagingArea/android-libraries/GooglePlay/res" -S "/Users/wakepon/projects/Solokus/Temp/StagingArea/android-libraries/common/res"

stderr[
AndroidManifest.xml:16: error: Error: No resource found that matches the given name (at 'value' with value '@integer/google_play_services_version').

AndroidManifest.xml:20: error: Error: No resource found that matches the given name (at 'theme' with value '@style/Theme.IAPTheme').

]
stdout[
Configurations:
 (default)

Files:
  AndroidManifest.xml
    Src: () AndroidManifest.xml

Resource Dirs:
Including resources from package: /Users/wakepon/Library/Android/sdk/platforms/android-24/android.jar
applyFileOverlay for drawable
trying overlaySet Key=app_banner.png
trying overlaySet Key=app_icon.png
applyFileOverlay for layout
applyFileOverlay for anim
applyFileOverlay for animator
applyFileOverlay for interpolator
applyFileOverlay for transition
applyFileOverlay for xml
applyFileOverlay for raw
applyFileOverlay for color
applyFileOverlay for menu
applyFileOverlay for mipmap
Processing image: res/drawable-xhdpi/app_banner.png
Processing image: res/drawable-ldpi/app_icon.png
Processing image: res/drawable-mdpi/app_icon.png
Processing image: res/drawable-hdpi/app_icon.png
    (processed image res/drawable-ldpi/app_icon.png: 97% size of source)
Processing image: res/drawable-xhdpi/app_icon.png
    (processed image res/drawable-mdpi/app_icon.png: 95% size of source)
Processing image: res/drawable-xxhdpi/app_icon.png
    (processed image res/drawable-hdpi/app_icon.png: 95% size of source)
Processing image: res/drawable-xxxhdpi/app_icon.png
    (processed image res/drawable-xhdpi/app_icon.png: 92% size of source)
    (processed image res/drawable-xhdpi/app_banner.png: 93% size of source)
    (processed image res/drawable-xxhdpi/app_icon.png: 93% size of source)
    (processed image res/drawable-xxxhdpi/app_icon.png: 91% size of source)
    (new resource id app_banner from xhdpi-v4/drawable/app_banner.png #generated)
    (new resource id app_icon from ldpi-v4/drawable/app_icon.png #generated)
    (new resource id app_icon from mdpi-v4/drawable/app_icon.png #generated)
    (new resource id app_icon from hdpi-v4/drawable/app_icon.png #generated)
    (new resource id app_icon from xhdpi-v4/drawable/app_icon.png #generated)
    (new resource id app_icon from xxhdpi-v4/drawable/app_icon.png #generated)
    (new resource id app_icon from xxxhdpi-v4/drawable/app_icon.png #generated)
]
exit code: 1
UnityEditor.Android.Command.Run (System.Diagnostics.ProcessStartInfo psi, UnityEditor.Android.WaitingForProcessToExit waitingForProcessToExit, System.String errorMsg)
UnityEditor.Android.PostProcessor.Tasks.TasksCommon.Exec (System.String command, System.String args, System.String workingdir, System.String errorMsg, Int32 retriesOnFailure)

対処

Plugins/Android/GoogleMobileAdsPlugin/AndroidManifest.xmlにある、

<!-- InAppPurchase Activity -->
<activity android:name="com.google.android.gms.ads.purchase.InAppPurchaseActivity"
    android:theme="@style/Theme.IAPTheme"/>

という部分をコメントアウトしたらビルドが通るようになりました。

AdMobで自社広告を出すときにアイテム課金に対する広告を入れられるとか、そんなんらしいので、その機能を使わないならコメントアウトしても大丈夫みたいです。

ゲーム中にバンドルバージョンを表示する

バグ報告を受けたときに「えっ、それどのバージョンのロムで発生したの?」って聞きたいときにタイトル画面などでバンドルバージョンを表示するようにしておくと便利だったりします。

バンドルバージョン自体はUnityEditor.PlayerSettings.bundleVersionで取得できるのですが、厄介なのは、これはUnityEditorで動かしている時以外は取得できないことです。

じゃあ、UnityEditor以外でバンドルバージョンを知るために、一旦ファイルに書き出しておこう!っていう発想になったりします。

Unityの中の人に質問したら、Stack Over Flowに、同様のことを質問しているのがありましたよーって教えてくれました。

これです↓
stackoverflow.com

実装説明

まず、最初にCurrentBundleVersion.csというファイルを作っておきます。

中身は、こんな感じです。

public static class CurrentBundleVersion
{
	public static readonly string version = "0.0";
}

次に、BundleVersionChecker.csという名前の以下のようなスクリプトをEditorフォルダ以下に置いておきます。

using UnityEngine;
using UnityEditor;
using System.IO;

[InitializeOnLoad]
public class BundleVersionChecker
{
    const string ClassName = "CurrentBundleVersion";
    const string TargetCodeFile = "Assets/" + ClassName + ".cs";

    static BundleVersionChecker () {
        string bundle_version = PlayerSettings.bundleVersion;

        string last_version = CurrentBundleVersion.version;
        if (last_version != bundle_version) {
            Debug.Log ("バージョンが新しくなりました!" + TargetCodeFile + "内に書かれたバージョンを" + last_version +"から" + bundle_version + "に変えます。" );
            CreateNewBuildVersionClassFile (bundle_version);
        }
    }

    static string CreateNewBuildVersionClassFile (string bundle_version) {
        using (StreamWriter writer = new StreamWriter (TargetCodeFile, false)) {
            try {
                string code = GenerateCode (bundle_version);
                writer.WriteLine ("{0}", code);
            } catch (System.Exception ex) {
                string msg = " threw:\n" + ex.ToString ();
                Debug.LogError (msg);
                EditorUtility.DisplayDialog ("Error クラスを作りなおし中にエラーが発生しました!", msg, "OK");
            }
        }
        return TargetCodeFile;
    }

    static string GenerateCode (string bundle_version) {
        string code = "public static class " + ClassName + "\n{\n";
        code += System.String.Format ("\tpublic static readonly string version = \"{0}\";", bundle_version);
        code += "\n}\n";
        return code;
    }
}

このBundleVersionChecker.csのstaticコンストラクタが起動すると、CurrentBundleVersion.cs内のversionを書き換わります。

BundleVersionChecker.csはEditorフォルダ以下に置かれているので、コンパイルが走るタイミングでスタティックコンストラクタが呼ばれて書き換えてくれます。


サンプルプロジェクトをgithubに置いておきます。
github.com

起動するとバージョンが表示されて、しばらくするとフェードアウトするようになっています。

OnTriggerEnter2DとOnCollisionEnter2Dの違い

OnTriggerEnter2DとOnCollisionEnter2Dの違いが分からん!

更に言うと、OnCollisionExit2DとOnTriggerExit2Dの違い、OnCollisionStay2DとOnTriggerStay2Dの違いも分からん!

っとなったので調べました。2Dについて書いていますが、基本3Dも一緒だと思います。

1.引数が違う

OnCollisionEnter2DとOnTriggerEnter2Dですが、よくよく見ると引数が違います。

void OnTriggerEnter2D( Collider2D other) { ... }
void OnCollisionEnter2D ( Collision2D other ) { ... }

1つ目の違いはここです。

綴りが似ているので最初気が付きませんでした。しかし、CollisionとColliderってどう違うんでしょう?

CollisionとColliderの違い

Collisionは衝突が発生した時の情報を受け渡しするためのクラスのようです。衝突時の衝突点や相対速度、衝撃の強さなどの情報が保持されています。

Unity - Scripting API: Collision


Colliderは、衝突判定をさせるためのコンポーネントでGameObjectにアタッチして使うクラスです。

Unity - Scripting API: Collider

2.使用する場面が違う。

実は使い分けは簡単で、ColliderのisTriggerがオンの時は、OnTrigger〜系のコールバック、オフの時はOnCollision〜系のコールバックを使えばOKです。

ちなみに同時に両方呼ばれることは無いみたいです。どちらかしか呼ばれません。

しかし、ColliderのisTriggerフラグって何なんでしょう?

トリガーってなに?

ColliderはisTriggerというフラグを持っています。これを有効にすると Rigidbody の衝突判定を行わなくなります。

分かりやすい例を挙げます。

f:id:wkpn:20161003120454p:plain

図で、青い四角も赤い四角も、どちらもBoxCollider2Dがついています。さらに青い方には、Rigidbody2Dもついているので、ゲームをスタートすると重力によって落下し始めます。

f:id:wkpn:20161003120504p:plain

isTriggerがオフのときには、下図のように赤い四角の上に青い四角が乗っかります。

f:id:wkpn:20161003120511p:plain

isTriggerをオンにすると、下図のように赤い四角に乗らずにスルーしまて落下し続けます。(OnTrigger系のCallbackは発生します。)

ちなみに、赤い四角、青い四角、どちらか一方だけでもisTriggerを有効にすれば、すり抜けるようになりTrigger系のコールバックが呼ばれるようになります。

まとめ

  1. 衝突して反射するような物理挙動をするオブジェクトに仕込むときはOnCollision〜系のコールバックを使う
  2. isTriggerフラグを立てて、触れたかどうかだけ判断したいようなオブジェクトに仕込むときはOnTrigger〜系のコールバックを使う
  3. それぞれ引数に入ってくる型が違うので注意

【Unity道場】Unity 5.4 & 5.5 新機能キャッチアップ講座に行ってきた。

Unity 5.4 & 5.5 新機能キャッチアップ講座」に行ってきました。

このような回を無料かつ軽食付きで開催してくれるUnity Japan様には頭が上がりません。ありがとうございます。

個人的に気になったポイントと所感をメモ。

Unity5.4

GPU Instancing

  • ライトプルーブの影響をうけられないとか、色々と制約が多いようなので、結局使い所が無いような気も... 何に使うのが良いんだろう?
    • 追記:弾幕シューティングになんか良いんじゃない?というご意見を頂きました。確かにそれは良さそう。

Transform周りがSIMDを利用するようになった

  • 使ってなかったのかぁ。
  • Transform周りだけなのかなぁ。Vector系の演算は全部使うようにできんのだろか?

処理のマルチスレッド化

  • 5.3 -> 5.4 -> 5.5 と徐々に進んでいるらしい
  • メインスレッドとレンダースレッドで分かれているだけ?
  • どこまでスレッドセーフなプログラムを意識すべきなのかが気になる。
  • メインスレッドとレンダースレッドだけなら、そんなに意識しなくても大丈夫そうだけど...
  • プロファイラーでマルチスレッドっぷりを確認できるらしい。

VRのSingle-Pass Stereo Rendering

  • パス変更回数が減るので負荷減
  • 色んなバッファを両眼で使いまわすのかなぁ
  • やったことないけど両眼用の画を作るときってシャドウマップを作るパスは一回しか走らせないのかな?
  • Image Effectは両眼の画に対してまとめてやるので交じる可能性があるらしい

AndroidのIL2CPP対応

  • ファイルサイズはmonoより大きくなるらしい
  • もちろんビルド時間は長い

Light Probe Proxy Volume

  • 初めて知った。
  • ライトプルーブってオブジェクト単位で使用するプルーブを決めるけど、それだと大きいオブジェクトだと破綻しちゃう
  • それを解決するために空間を区切って、区切られた空間単位でプルーブを決めるっぽい。たぶん。

Unity5.5

RigidBody2Dにsimulatedというパラメータが追加される

  • オブジェクトのアクティブ/非アクティブを繰り返すと、内部ではコライダーの生成と破棄をしていて、コストが有った。
  • simulated: offは破棄しないで物理演算から除外出来る
  • オブジェクト生成代わりに、ObjectをPoolしてアクティブ/非アクティブの切り替えることは多々あるので、これは良いことを知った。
  • 早く5.5来て欲しい。

Full Binary Shader Serialisation

  • 消費メモリ減少
  • コンパイル時間減少
  • Shader Binaryってどんだけ互換性あるんだろう?
  • プラットフォーム切り替えが遅くなる?

iOSで新しい画像フォーマットに対応

  • ASTC 6x6 〜 16x16
  • 圧縮率:クオリティ比率はかなり良い
  • ただし、A8以上のチップ。つまりiPhone6以上。
  • それ以下の場合TrueColorになる!
  • って、しばらくは使えないってことじゃない?

ライン&トレイルレンダラーがまともに

  • 今まではクオリティが低くて使えなかったらしい
  • これは使いたい!

その先のUnity

Monoのバージョンアップ

  • 拍手が起きてた
  • Mono4.6、C#6.0 対応
  • まだ何も出てきてないし、正直、遠い未来なのではないかという不安が...

2D

  • Tilemapが追加
  • Z軸でのソート
  • 早く来て欲しい!

Unityで transform.localPosition.x = 1.0f; ができないわけ

C#初心者の私がUnityで最初戸惑ったのはtransform.localPosition.x = 1.0f;というようなことができないことです。

これをやろうとすると、

error CS1612: Cannot modify a value type return value of `UnityEngine.Transform.localPosition'. Consider storing the value in a temporary variable

というエラーが出ます。UnityEngine.Transform.localPositionは変更できないよって言われてます。

なんで、こんなことになるかというと、localPositionが値型で、なおかつプロパティだからです。

Transformの定義を見ると、

public Vector3 localPosition { get; set; }

というようになっています。

これが、プロパティでなく、

public Vector3 localPosition;

という形であれば、localPosition.x = 1.0fは可能です。

また、Vector3が参照型(class)であった場合も、transform.localPosition.x = 1.0f;という風に書くことができます。

localPositionは値型を返すプロパティなので、メモリ上に一時的にできた一時変数が返されてしまうのです。
そこに値を入れたところで何も起きません。なのでエラーになるのです。

C++で考えると、プロパティは以下のような関数があるようなものです。

const Vector3 GetLocalPosition() { return localPosition; }
void SetLocalPosition( const Vector3 pos ) { localPosition = pos; }

そう考えると、Vector3で渡さないといけないのが理解しやすいんじゃないかと思います。

P.S 2018.11.25
自分の理解が浅はかだったので修正しました。

UnityでUnit Testを行う

先日、勉強会でUnity Tests Runnerというのものがあることを知りました。

もともと、Unity Test Toolsというものの一部だったのが、Unity5.3から組み込みになったらしいです。

docs.unity3d.com

というわけで使ってみました。

使い方は簡単で、図のように

f:id:wkpn:20160925160828p:plain

「create」 -> 「Editor Test C# Script」

を選び、スクリプトファイルを作ります。スクリプトはEditorフォルダ以下に置いて置きます。

Editorフォルダ以下に置いておかないと、

The type or namespace name `NUnit' could not be found. Are you missing a using directive or an assembly reference?

というエラーが出ますのでご注意を。

できたスクリプトは、以下のようになっています。EditorTest()の中身がテストコードになっています。

using UnityEngine;
using UnityEditor;
using NUnit.Framework;

public class NewEditorTest {

	[Test]
	public void EditorTest()
	{
		//Arrange
		var gameObject = new GameObject();

		//Act
		//Try to rename the GameObject
		var newGameObjectName = "My game object";
		gameObject.name = newGameObjectName;

		//Assert
		//The object has a new name
		Assert.AreEqual(newGameObjectName, gameObject.name);
	}
}

EditorTestを書き換えて、自分のテストしたい内容に書き換えても良いですが、テスト項目が増えるたびに新たに関数を作ったほうが良いでしょう。頭に[Test]属性をつけておくと、それがテストコードになります。

例えば、自分は以下のようなテストを書いています。ちなみにclass名は何でも良いみたいです。

public class WKLibraryTest {
    [Test]
    public void SwapTest()
    {
        int i1 = 0;
        int i2 = 1;
        Utils.Swap< int >( ref i1, ref i2 );
        Debug.Assert( i1 == 1 && i2 == 0 );
    }

    [Test]
    public void Tuple2Test()
    {
        MyTuple2 tuple_test2 = new MyTuple2( "tuple2", 0 );

        Debug.Assert( tuple_test2.Item1 == "tuple2" );
        Debug.Assert( tuple_test2.Item2 == 0 );
    }
}

できたテストはエディター上から走らせることができます。

「Window」->「Editor Tests Runner」を選びます。

f:id:wkpn:20160925161157p:plain

すると以下のような窓が出てきます。

f:id:wkpn:20160925161214p:plain

「Run All」を押すと、全部、「Run Selected」だと選択しているもの、「Rerun Failed」だと前のテストで失敗したものをテストします。

成功すると以下のように緑のチェックが付き、

f:id:wkpn:20160925161236p:plain

失敗すると赤いチェックが付きます。

f:id:wkpn:20160925161252p:plain

テスト書くの面倒くさいので、あんまりやりたくはないのですが、ちょっとしたオレオレUtilityをチェックするのに使おうと思います。