kidoOooOoooOOom

ゲーム開発やってます

UnityでScriptableObjectを用いて設定管理

拡張エディタやImporterの設定ファイルとして、ScriptableObjectが使用できる。
tsubakit1.hateblo.jp


例えば今回は、画像ファイルをUnity上にインポートする際に、特定のフォルダ配下の場合はTrue color にしたりmip mapをOFFにするといった自動設定を行うため、下記のようなScriptableObjectを用意する。

    [CreateAssetMenu(fileName = "TextureImporterConfig")]
    public class TextureImporterConfig : ScriptableObject, ISerializationCallbackReceiver
    {
        public List<TextureSetting> textureSettings = new List<TextureSetting> ();

        public Dictionary<string, TextureSetting> textureSettingsDic;

        public void OnAfterDeserialize()
        {
            textureSettingsDic = new Dictionary<string, TextureSetting> ();

            foreach (var item in textureSettings)
            {
                if (textureSettingsDic.ContainsKey(item.targetPath) == false)
                {
                    textureSettingsDic.Add(item.targetPath, item);
                }
            }
        }

        public void OnBeforeSerialize()
        {
        }
    }

    [System.Serializable]
    public class TextureSetting
    {
        public string targetPath;
        public TextureImporterType importType;
        public bool mipmapEnabled;
        public TextureImporterFormat importFormat;
        public string packingTag;
    }


CreateAssetMenu属性を付随すると、Asset Menuでこのclassのオブジェクトを生成できるようになる。
ただし、ScriptableObjectはDictionary型を直接シリアライズできないので、List型で一旦保持しておき、ISerializationCallbackReceiverのOnAfterDeserialize()の中でDictionary型へ変換するようにした。

これでUnity Editor上でも設定を変更できるようになったのだが、Editor上での変更が一向にassetファイルに反映されなかった。
調べてみると、自分で SetDirty をして変更通知をしてから asset を 保存するのが必要だった。
docs.unity3d.com

というわけで下記クラスを追加し、Editor上で Save Asset ボタンを押すと変更内容がassetファイルに反映されるようにした。

    [CustomEditor(typeof(TextureImporterConfig))]
    public class TextureImporterConfigEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            DrawDefaultInspector();

            if (GUILayout.Button("Save Asset"))
            {
                TextureImporterConfig configTarget = target as TextureImporterConfig;
                EditorUtility.SetDirty(configTarget);
                AssetDatabase.SaveAssets();
            }
        }
    }

UnityでFBXファイルをインポートした時のデフォルト設定を自動化

Maya等で作成した3Dモデルが含まれるFBXファイルはUnity上にドラッグ&ドロップするだけでインポートが可能だが、デフォルト設定では色々とまずいので設定を変える必要があったりする。
インポートするファイルの数がたいしたことなければ問題ないが、100を超えるような物量に毎回同じ設定変更を行うのは効率が悪いので、スクリプトで自動化する。

Unityでは、AssetPostprocessorというクラスを継承すれば、インポート時のパイプラインにフックして特定の処理を行うことができる。
docs.unity3d.com


例えば、UnityとMayaでスケールの設定が異なっているため Modelのscale sizeを1から100に変更したいような場合は OnPreprocessModel() で値を変更すればおk。

void OnPreprocessModel ()
{
	var modelImporter = assetImporter as ModelImporter;
	modelImporter.globalScale = 100;
}

Importで生成された Materials に対して、特定のshader 割り当ておよび、パラメータ設定を行いたい場合は、OnPostprocessModel で生成されたMaterial に対して変更すればおk。

void OnPostprocessModel (GameObject gameObject)
{
	foreach (Transform item in gameObject.transform) {
		if (item.gameObject.GetComponent<Renderer> () == null) {
			continue;
		}

		foreach (Material material in item.GetComponent<Renderer>().sharedMaterials) {
			// shader を変更
			material.shader = Shader.Find ("HogeHogeShader");

			// shader のパラメータを変更
			material.SetFloat ("_HogeHogeParam", 0.1f);
			material.SetTexture ("_SampleCube", Resources.Load ("sample_texture") as Texture);
		}
	}
}

Unity上ですでにimport済みのファイルをReimportした場合もこの処理は走るので、せっかく設定したカスタム値を上書きしないように制御する必要があるので注意。

Unityでアプリ起動時の画面向き設定

スマホの縦向きのレイアウトしか考慮しない場合は縦向き固定にする。
[Build Settings] から [Player Settings]を開き、Resolution and Presentation のところの Orientation を変更する。
Portrait: 縦向きでホームボタンが下固定
PortraitUpsideDown: 縦向きでホームボタンが上
LandscapeLeft: 横向きでホームボタンが右
LandscapeRight: 横向きでホームボタンが左
Auto Rotation: スマホの向きに合わせてアプリも回転

Monodevelop ショートカットメモ

とりあえず使いそうなのメモ


コードスニペット: 予約語を入れて tab 2回
定義へジャンプ: 変数を選択して cmd + y
参照先リストアップ: cmd + shift + y
リファクタリング: Cmd + r
指定行へ移動: Cmd + L
コメント挿入: ///
矩形範囲選択: option + マウスドラッグ

ファイルのタブを左移動: cmd + shift + {
ファイルのタブを右移動: cmd + shift + }
左にインデント: cmd + {
右にインデント: cmd + }

ファイル内検索: cmd + f
複数ファイル対象検索: cmd + shift + f
ビルド: cmd + b
ファイル名検索: cmd + shift + D

Phoenixでcrud操作できるところまで

昨日に引き続き、elixir と Phoenixを軽く触ってみる。

Phoenix は default で postgreSQL を使うので、それをローカルのmacに環境構築する。
参考にしたのはこちら。qiita.com

$ brew install postgresql
$ initdb /usr/local/var/postgres -E utf8
$ postgres -D /usr/local/var/postgres

これでデータベース一覧が取得できれば成功
$ psql -l

だが、自分のmacではエラーになった。どうやらバンドルインストールされたのがあるらしく下記対応で起動できるよういなった。

$ curl -o fixBrewLionPostgresql.sh http://nextmarvel.net/blog/downloads/fixBrewLionPostgres.sh
$ chmod 777 fixBrewLionPostgresql.sh
$ ./fixBrewLionPostgresql.sh

これでおk。

.zshrc
あたりに下記の設定をしておけば

$ export PGDATA=/usr/local/var/postgres

今後は下記のコマンドで起動停止できる。
$ pg_ctl -l /usr/local/var/postgres/server.log start
$ pg_ctl -l /usr/local/var/postgres/server.log stop


今回のphoenix アプリ向けに postgresにユーザ作成
$ createuser -P -d postgres

default では password も postgresになっている。
phoenixのtestで使うDB の設定は config/test.exs に書かれている。

# Configure your database
config :phoenix_training, PhoenixTraining.Repo,
  adapter: Ecto.Adapters.Postgres,
  username: "postgres",
  password: "postgres",
  database: "phoenix_training_test",
  hostname: "localhost",
  pool: Ecto.Adapters.SQL.Sandbox

以下のコマンドでデータベースが作成される。
$ mix ecto.create

データベースを確認する。
$ psql -l

phoenix_traning_devが作成されていることが確認できる。

                                       List of databases
        Name         |  Owner   | Encoding |   Collate   |    Ctype
---------------------+----------+----------+-------------+-------------
 phoenix_traning_dev | postgres | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8


下記のようなコマンドを実行すると、User CRUDの各ファイルが作成される。
$ mix phoenix.gen.html User users name:string email:string bio:string number_of_pets:integer

ファイル生成後、

Add the resource to your browser scope in web/router.ex:
    resources "/users", UserController

とあるので、router.exに定義を追加する。

その後、

Remember to update your repository by running migrations:
    $ mix ecto.migrate

とあるので、migrateを実行する。

サーバを起動して、localhost:4000/users でアクセスすると User の CRUD アプリが動く。
f:id:gidooom:20151007160618p:plain


user crud のために自動生成されたソースは下記の通り。
https://github.com/kidooom/phoenix_training/commit/336236aee52c95b2daf18ee9d80c589d862df876

elixir と phoenixを軽く触ってみる

elixir の wikipedia
Elixir (プログラミング言語) - Wikipedia

Elixir (エリクサー)は並列処理、関数型に対応した、Erlangの仮想環境(BEAM)上で動作する汎用プログラミング言語である。ElixirはErlangで実装されているため、分散システム、耐障害性、ソフトリアルタイムシステム等の機能を使用することができるが、拡張機能として、マクロを使ったメタプログラミング、そしてポリモーフィズムなどのプログラミング・パラダイムプロトコルを介して実装されている


elixir のインストール

$ brew update
$ brew install elixir

これでok.
iex でインタラクティブシェルが立ち上がる。
$ iex

文字列の連結は + じゃなくて <> を使う。

iex(1)> "hello" + " world"
** (ArithmeticError) bad argument in arithmetic expression
    :erlang.+("hello", " world")
iex(1)> "hello" <> " world"
"hello world"
iex(2)> 

rubyと同様に#{}によって式展開

iex(2)> "10 + 20 = #{10+20}"
"10 + 20 = 30"

リストとタプル。
リストは Linked list に対し、タプルは要素を連続したメモリ上に保存している。
リストの更新や追加に比べて、タプルの更新は要素全体をコピーして生成するのでコストが高い。
変更されないようなデータをタプルにした方がよさげ。

iex(4)> %{hoge: 100, huga: 200}
%{hoge: 100, huga: 200}
iex(5)> 
nil
iex(6)> map =  %{hoge: 100, huga: 200}
%{hoge: 100, huga: 200}
iex(7)> map.hoge
100
iex(8)> %{map | hoge: 300}
%{hoge: 300, huga: 200}
iex(9)> map.hoge          
100
iex(10)> map = %{map | hoge: 300}
%{hoge: 300, huga: 200}
iex(11)> map.hoge                
300
iex(12)> 


実際にelixirプロジェクトを作成する。

$ mix new
で空プロジェクトが作成される。
$ mix test
でとりあえずtestが通れば問題無し。

hello world を出力する

defmodule Hello do

  def world do
    IO.puts "Hello World"
  end
end

Hello.world

フィボナッチ数列

defmodule Fib do
  def fib(0) do 0 end
  def fib(1) do 1 end
  def fib(n) do fib(n-1)+fib(n-2) end
end

IO.puts Fib.fib(10)


Railsライクな web framework の Phoenixもとりあえず動かしてみる。

install
$ mix archive install phoenix

new project
$ mix phoenix.new .

launch
$ mix phoenix.server

これで、localhost:4000 でアクセスできる。


ひな形プロジェクトに対し、/hello ページを追加する。
変更したコードは下記の通り。
https://github.com/kidooom/phoenix_training/commit/801f9039014d4d629dafbf5772826ff73140ebbe

これで、localhost:4000/hello
で動く。簡単。

gruntでjshintとjscsのlintをタスク化

jshintのチェックルールを.jshintrcに、jscsのチェックルールを .jscsrc とかで用意しておき、下記をGruntfile.js に追加する。

  grunt.initConfig({
    jshint: {
      files: [
        'lib/**/*.js',
        'test/**/*.js',
        '*.js',
      ],
      options: {
        jshintrc: '.jshintrc'
      }
    },
    jscs: {
      src: [
        '*.js',
        './**/*.js'
      ],
      options: {
        config: ".jscsrc",
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks("grunt-jscs");

  grunt.registerTask('lint', ['jshint', 'jscs']);

これで grunt lint を実行すれば OK.