読者です 読者をやめる 読者になる 読者になる

CosやSinをテーブル引きにする効果

      • -

追記 2017/2/8 23:20

各所からツッコミを受けました。
テーブル引きの恩恵を受けるようなコードは、現在の実践環境ではあまりなく、普通に関数を使ったほうが有利というのが説が多いです。
以下のテストはキャッシュが効きやすい状態のテストなので一応、テーブル引きが勝っていますが、結構特殊な状況です。
ほんとうは、ちゃんと実際のゲーム中で計測するべきなんですけど、すいませんm(_ _)m

速度的なメリットは怪しいけどテーブル引きのメリットは、
通信量を落とせるとか(角度をfloatの32bitじゃなく8bitとか16bitで持ちたいとき)
値が実行環境に依存しないとか
というメリットがあると言われ、自分も納得しました。

      • -


CosやSinをテーブル引きにする効果

ゲーム制作において、高速化のためにCosやSinといった関数をテーブル引きにするというのは、よくある話である。

自分のゲーム制作環境でも少しでも処理を軽くするためにテーブル引きSin,Cosを作ってみようかと思ったのだけれど、そもそもどれぐらい処理の高速化が見込めるのか、Unity上で試してみた。

github.com

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestScript : MonoBehaviour {
    public int loopCount = 10000000;
    System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();

    public int tableSize = 360;
    public const float PI2 = Mathf.PI * 2.0f;
    float[] cosTable;

	void Start () {
        cosTable = new float[ tableSize ];
        for( int i = 0; i < tableSize; ++i )
        {
            float theta = (float)i / tableSize * PI2;
            cosTable[i] = Mathf.Cos( theta );
        }
    }

    [ContextMenu("Test Mathf")]
	void TestMathf () {
        stopWatch.Reset();
        stopWatch.Start();
        float sum = 0.0f;
        for( int i = 0; i < loopCount; ++i )
        {
            sum += Mathf.Cos( (float)i );
        }
		
        stopWatch.Stop();
        Debug.Log( "time : " + stopWatch.Elapsed + " sum, " + sum );
	}

    [ContextMenu("Test Cos Table")]
	void TestCosTable () {
        stopWatch.Reset();
        stopWatch.Start();
        float sum = 0.0f;
        for( int i = 0; i < loopCount; ++i )
        {
            sum += getCosFromTable( (float)i );
        }
        stopWatch.Stop();
        Debug.Log( "time : " + stopWatch.Elapsed + " sum, " + sum );
	}

	int getCosTableIndex ( float theta ) {
        return (int)( theta / PI2 * tableSize ) % tableSize;
    }

	float getCosFromTable ( float theta ) {
        int index = getCosTableIndex( theta );
        return cosTable[ index ];
    }
}


1000万回、Cosを計算して加算した結果、自分のMacbook Pro上で、Mathf.Cosは0.552秒、tableを使ったCosは0.453秒とTableを使ったほうが20%ぐらい高速だった。

もっと差が出るかと思っていたのだけど、そうでもなかった。

tableを使った方は精度がイマイチなのでご利用は計画的に。

UnityException: Unable to install APK! Installation failed. See the Console for details

UnityでAndroid版をBuild And Run しようとした時に、突如として表題の例外が発生するようになって困った。

answers.unity3d.com

こちらに解決策が↑

Player Settings -> Other Settingsで、Bundle Version Codeをあげたらインストールできた。

たまにUnityが落ちて、意図せずBundle Version Codeが下がっていることがあるので注意。

use of undeclared identifier 'Unity' とか 'UI' のエラー

UnityでiOS版のビルド時に、Scripting BackendをMono2xにしてStriping Levelを何某かにしていると、以下のようにXCode側でエラーが出ることがあるもよう。

f:id:wkpn:20170116200832p:plain

とりあえずstripping levelをdisabledにすれば、一応回避できる。

Mono2xでのビルドは、基本デバッグ用途でしか無いので、とりあえずこれで良いかな。

XCodeでビルドした時に「Appの有効なaps-environmentエンタイトルメント文字列が見つかりません」というエラーが出る

XCodeでビルドした時に「Appの有効なaps-environmentエンタイトルメント文字列が見つかりません」というエラーが出た。

これは証明書にPush Notificationが無いかららしい。

最近のXCodeは「Automatically manage signing」にチェックを入れておくと証明書を勝手に作ってくれるので、Capabilityの設定部分でPush Notification項目をONにすれば勝手に証明書側も更新してくれる。

f:id:wkpn:20170116200204p:plain

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

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