けいごのなんとか

Unityユーザーとしてのブログ。ギリギリ路線走ってます。

WebPlayerでの公開をかっこ良く - WebPlayerTemplateを使う

みなさん、ユニティちゃんのunitypackageに「WebPlayerTemplates」が含まれているのをご存知ですか?

WebPlayerTemplatesを使用すると下記URLのようなHTMLページがすぐ作れちゃいます。

http://unity3d-jp.github.io/unitychan2d/

f:id:anchan828:20140622132457p:plain

できること

シェアボタン

TwitterFacebookのシェアボタンがWebPlayerの右下に表示されます。

f:id:anchan828:20140622132656p:plain

使い方

WebPlatyerTemplatesAssetsフォルダ直下に置きましょう

f:id:anchan828:20140622132259p:plain

Edit -> Project Settings -> Playerの所にあるWebPlayer Templateで使いたいテンプレートを選択するだけです。

f:id:anchan828:20140622132031p:plain

FacebookでURL共有した時の挙動(OGPの設定)

[注意] この設定は unity3d-jp/webplayer-templates · GitHub のWebPlayerTemplateで行うことが出来ます。ユニティちゃんパッケージに含まれているものでは出来ません(2014/06/22 現在)

何も設定していない時、FacebookでWebPlayerを共有しようとすると残念な見た目になります。

f:id:anchan828:20140622133452p:plain

WebPlayerTemplateを使用するとサムネや説明が追加されて良くなります。

f:id:anchan828:20140622134007p:plain

仕様的な説明

サムネはビルド直前に開いているシーンをサムネとして使用します。 TemplatesEditorScriptフォルダにあるWebPlayerTemplatesPostProcessBuild.csは絶対に削除しないでください。

using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;

public class WebPlayerTemplatesPostProcessBuild
{
    [PostProcessBuild]
    public static void OnPostprocessBuild (BuildTarget target, string pathToBuiltProject)
    {
        if (target == BuildTarget.WebPlayer) {
            Application.CaptureScreenshot (pathToBuiltProject + "/thumbnail.png");
        }
    }
}

説明(og:description)の記入はPlayer Settingsから行うことが出来ます。

f:id:anchan828:20140622134400p:plain

サムネと説明はビルドごとに毎回上書きされてしまうので注意してね。

AssetDatabase.StartAssetEditing

この情報はUnity Documentation Tabsでも閲覧することが出来ます

Unity Documentation Tabsで閲覧する場合のURLはこちら(EN)またはこちら(JP)です


まとめて編集&再インポートに使用する

インポート中にダイアログを表示させるのには「EditorUtility.DisplayDialog」を使用しますが複数のアセットの再インポートを行う場合は「AssetDatabase.StartAssetEditing」と「AssetDatabase.StopAssetEditing」を使用します。こうすることでStartAssetEditingとStopAssetEditingに囲まれたインポート処理中はダイアログ表示が自動で行われるようになります。

例としてサウンドのインポート設定を3Dから2Dへ変更します。

using UnityEngine;
using UnityEditor;
 
public class AudioImporterSettings
{
    [MenuItem("Assets/Apply 2D Sound")]
    static void Apply2DSound ()
    {
        var sounds = Selection.GetFiltered (typeof(AudioClip), SelectionMode.DeepAssets);
        
        AssetDatabase.StartAssetEditing ();
        foreach (var sound in sounds) {
            
            var path = AssetDatabase.GetAssetPath (sound);
            
            var audioImporter = AudioImporter.GetAtPath (path) as AudioImporter;
            
            if (audioImporter == false)
                continue;
            
            audioImporter.threeD = false;
 
            AssetDatabase.ImportAsset(path);
            
        }
        AssetDatabase.StopAssetEditing ();
        AssetDatabase.Refresh ();
        
        Debug.Log ("done.");
    }
    
    [MenuItem("Assets/Apply 2D Sound",true)]
    static bool IsFolder ()
    {
        var sounds = Selection.GetFiltered (typeof(AudioClip), SelectionMode.DeepAssets);
        return sounds.Length != 0;
    }
}

動画を再生するにはvideoタグをサポートしたブラウザが必要です。

コンポーネントの順番を変更する「Component Move Up」「Component Move Down」をコードで管理する

何度も「Move Up」とか押しまくるの疲れたので作ってみた

Github - https://github.com/anchan828/ComponentOrderAttribute

コンポーネントの「Move Up」「Move Down」をコードで自動管理

ComponentOrderAttribute

ComponentOrderAttribute(uint order)

指定した順番通りに並び替える。

ただしTransformは必ず一番上でなければいけない。

using UnityEngine;
using System.Collections;

[ComponentOrder(1)]
public class Order1 : MonoBehaviour
{
}

ComponentOrderAttribute(Type type)

指定したTypeの直下に移動する

using UnityEngine;
using System.Collections;

[ComponentOrder(typeof(Rigidbody))]
public class OrderRigidbody : MonoBehaviour
{
}

タグ、レイヤー、シーン、インプット名を定数で扱う

結構前にシーン名とタグ名をタイプセーフに扱いたかったので作ってました。

スクリプトでシーン名を扱うのをタイプセーフにしてみた

http://anchan828.tumblr.com/post/37544410340

Tag名を定数で扱えるように

https://gist.github.com/anchan828/3cf9014a8493ab023925

今だとこちらが最新なのかな

【Unity】シーン名を定数で管理するクラスを生成する拡張機能 - コガネブログ

【Unity】タグ名を定数で管理するクラスを生成する拡張機能 - コガネブログ

他にも定数で管理したいところはあるので前作ったのを整理して公開してみました。

「Layer」「NavMeshLayer」「SortingLayer」「Input」が追加されてます。

anchan828/namecreator · GitHub

使い方

各クラスファイルが作成されるのはUnity起動直後か、メニューからの手動か。

メニューからはAssets/Name Creator/Force Rebuilds で実行できます。

全部生成したくない、いらないって人はここの行( link )をコメントアウトすればいいです。

Name Creator

色んな文字列情報をタイプセーフに使うやつ

TagName

LayerName

NavMeshLayerName

SortingLayerName

InputName

SceneName

テンプレートファイルにカスタムキーワード追加

Unity.app/Contents/Resources/ScriptTemplatesにあるテンプレートファイルに自由にReplaceできるキーワードを追加する

デフォルトでサポートされているのは

key 説明
#NAME# 拡張子なしのファイル名に変換
#SCRIPTNAME# 半角スペース無しで拡張子無しのファイル名に変換
#SCRIPTNAME_LOWER# 半角スペース無しで拡張子無しの全て小文字のファイル名に変換。ただし最初の文字をhogeのように小文字にするとmyHogeとなる。

こんな風にライセンスを追加(YEARとOWNER)

/*
Copyright (C) #YEAR# #OWNER#

This software is provided 'as-is', without any express or implied
warranty.  In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
   claim that you wrote the original software. If you use this software
   in a product, an acknowledgment in the product documentation would be
   appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
using UnityEngine;
using System.Collections;


public class #SCRIPTNAME# : MonoBehaviour {

    // Use this for initialization
    void Start () {
    
    }

    // Update is called once per frame
    void Update () {

    }
}

文字を入れ替える方法はなんでもいいんだけど、必須なのはOnPostprocessAllAssets内でAssetDatabase.ImportAsset (path, ImportAssetOptions.ForceUpdate);を呼び出すこと。 インポート処理を強制的に実行します。(今回はコンパイル処理をキャンセルしたみたいに受け取ってもらえればOK)

そうしないと入れ替えた後のインポート処理がコンパイル後まで待たされてしまうのでコンパイルエラーになる。

using System;
using System.IO;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;

public class NamespaceGenerator : UnityEditor.AssetPostprocessor
{

        // ここをいじる
        static string[] keys = new []{
        "YEAR","OWNER",
        };

        static void OnPostprocessAllAssets (string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromPath)
        {
                foreach (var path in importedAssets) {
                        if (path.Contains (".cs") 
                                || path.Contains (".js") 
                                || path.Contains (".boo") 
                                || path.Contains (".shader") 
                                || path.Contains (".compute")) {
                                for (int i = 0; i < keys.Length; i++) {
                                        var key = keys [i];
                                
                                        var text = File.ReadAllText (path);
                                        if (text.Contains ("#" + key + "#")) {
                                                text = ReplaceText (key, text);

                                                StreamWriter writer = new StreamWriter (path, false, new System.Text.UTF8Encoding (true, false));
                                                writer.Write (text);
                                                writer.Close ();

                                                AssetDatabase.ImportAsset (path, ImportAssetOptions.ForceUpdate);
                                        }
                                }
                        }
                }
        }
        
        // ここをいじる
        static string ReplaceText (string key, string text)
        {
                
                switch (key) {
                case "YEAR":
                        // こんな感じでReplace
                        text = Regex.Replace (text, "#" + key + "#", DateTime.Now.Year.ToString());
                        break;
                case "OWNER":
                        text = Regex.Replace (text, "#" + key + "#", "Keigo Ando");
                        break;
                default:
                        break;
                }

                return text;
        }
}

ゲームオブジェクトのスクリプトが「Missing」になった時のリカバリー

このような時に出来るだけ素早く元に戻す。

f:id:anchan828:20140104011644p:plain

まずこのような事になる場合

  • Unityの管理外でスクリプト名の変更をした
  • Unityの管理外でスクリプトファイルの階層構成を変更した

が挙げられます。つまり、Unityが把握してない所で変更したら「誰だお前!?」となる。

Missingになった時でもデータは保持されている

Missingになっていてもシリアライズされたデータは保持されている。

なのでシリアライズされたプロパティのデータの型やプロパティ名を、既存の(MonoBehaviourを継承した)クラスのプロパティと照らし合わせ、一致しているものが多い順に表示してみた。

f:id:anchan828:20140104012411p:plain

一番一致しているプロパティが多いものはGoogleみたいに「もしかして」を付けてみた。

f:id:anchan828:20140104012427p:plain

現在の問題点としては

Missingとなった時のプロパティの照らし合わせで配列(Generic、Array)とUnityEngine.ObjectとEnumは照らし合わせを行っていない。ちょっと面倒なので...

MonoBehaviourのCustomEditorを作成しているので、他でMonoBehaviourのCustomEditorを作成していたらどっちかが動作しなくなる。