FreelyApps

個人によるアプリ開発の日記です。アプリの収入だけで生活できるようになるのが目標です。UnityでAndroid向けのゲームアプリを作成しています。


    アプリ『トランプ・ジン・ラミー』を公開しました。
    Android/iOS https://goo.gl/PYKFYG

    カテゴリ:Unity > UI

      このエントリーをはてなブックマークに追加 Clip to Evernote
    最近気付いたことなのでいつからある機能なのかわかりません。少なくとも今使っているUnity5.3.4f1 Personalには以下の機能があります。

    シーンビュー上で3D/2Dに関わらずゲームオブジェクトが重なってしまうことがあります。選択したいものの一部がクリックできれば選択状態にできますが、大きいものが手前に来るなどしているとクリックできず選択できないことがあります。

    シーンビュー上でクリックを繰り返すと、選択されるゲームオブジェクトが切り替わっていきます。クリックしたところにレイキャストして貫通したゲームオブジェクトを順番に選択しているような挙動をします。
    以下はUIでの例です。キャンバスが複数あり、UIは階層構造を持っています。クラブのQを選択したいのですが、上に重なっているUIがあるため直接は選択できません。何回かクリックすることでクラブのQが選択状態に切り替わりました。


    3Dでも同じようなことができます。2つのときはうまくいったのですが、3つ以上のゲームオブジェクトが重なっているときはうまくいくこともあれば、選択できないこともあったのでよくわかりません。
    あと位置移動のためのギズモをクリックしたときは選択切り替えは起こりません。それはゲームオブジェクト平面上で動かすためのショートカットが優先されるからです。


    重なったゲームオブジェクトをシーンビュー上で選択するには、そのゲームオブジェクトがあるところを何回かクリックしてみると良いです。これに慣れるとUnity UIを作るのが楽になります。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    開発中のスピードのアプリのUIがほぼ完成してきました。ゲーム的に重要なのは難易度ごとのAIの作成が残っていて、他にはタイトルやら細かな部分を作ることが残っているところです。
    今週くらいには予約を始めて4月中にはリリースできると良いかなという感じです。 

    トランプのアプリは今までと同じように名前をつけるので、『トランプ・スピード』 という名前にします。スピードは日本では有名なゲームなので、わかりにくいことはないと思います。シリーズものみたいなことで名前はこうすることにしました。
    スピードはトランプの中では変わったものになります。普通のゲームは順番にカードを出していくときに一人ずつ順番を守ります。 特に思考が要求されるゲームではそうです。スピードは出し方も重要ですが、どちらかと言えばスポーツよりで以下に早くカードを出せるかというゲームになります。アプリでスピードを再現するにあたり、カードの出した順番が見えることが重要だと思いました。
    当たり前のことを言うようですが、後に出したカードは表示が前に来ると、後に出したのだと知覚できます。プログラム的には表示の優先度のことです。現実でのカードは厚みを持ち、出されていくカードは重なっていきます。表示位置をずらしたり、3Dモデルを使って影を落とすことも効果的だと思いますが、最も重要なのは前面に表示されているカードがより後に重ねたものであるということです。

    2週間くらい前の画面が以下になります。
    old-input-ts-main
    画面上側のスペードの10と画面下側のハートの9が他のカードに覆いかぶさられているのがわかります。本来ならこれらのカードは移動中なので、後に出したカードのはずです。つまり、スペードの10とハートの9は前に表示されるべきです。このときはUIの優先度を制御してなかったので、このようになっていました。

    今は以下のように正しい表示になっています。優先度が動的に変わっていることを示すためgifになっています。
    input-ts-main
    クリックしたカードが最も前に表示されるようになっています。更に自分と相手のカードについても順番を考慮しています。相手と自分のカードで後に出されたものほど前に表示されます。

    どのように作っているかというと、自分と相手の場札(横に4枚並んだカード)がひとつのUIになっています。構造を見れば察しがつくとは思いますが、一応解説します。
    Cardsというのが表示のための部分です。Cardsの下に1枚のカードに対応するother0~3とmy0~3があります。otherは相手のでmyは自分の方のカードです。Unity UIではヒエラルキー上で見れる階層で下にあるものが最も上に表示されます。(同じCanvas内での話です。)カードを出すという処理をするときに対応する表示用のUIのtransformを取得し、SetAsLastSiblingで子の中で最も後ろに置くということをしてやれば表示を最優先にできます。
    ts-inputUI
    Inputがあるのは表示の優先度が変わると、それらにButtonをアタッチして押せる用にしているとまずいからです。常に固定した位置にタッチ判定を置くためにより優先されるところに入力用の透明なUIを配置しています。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    UIの位置を調整する場合はスクリーン座標を基準に考えるのが最も良いです。スクリーン座標とは表示するディスプレイ上でのピクセル単位の座標です。
    Unityでは左下が(0,0)、右上が(幅,高さ)となるように座標を定めています。カメラのところにちょろっと説明が載っています。
    こういったゲームビューなら右上の座標は画面のサイズになります。
    gameview

    なぜスクリーン座標で考えると良いのかというと、画面上でどこに表示されているかを直接表しているためです。画面上の位置が表示にそのまま関係するため最もわかりやすいのです。

    3DとUIを連携したい場合
    わかりやすい例で言うと3D空間上にいる物体の近くにUIを常に出したいといったことがあるでしょう。これはキャラクターにHPのバーを表示し続けるといったことが該当します。
    キャラクターが3Dだとすると、キャラクターの位置は3D空間上での位置を表しています。(モデルの中心位置に一致することでしょう。)x,y,zの3成分があるベクトルで表されますが、この数字はワールド座標であるはずです。空間上の位置から画面上のどこ(スクリーン座標)に表示されるのかを求める必要があるわけです。これはキャラクターを移しているカメラから変換行列をかけてもらい求めます。Unityではこの行列計算は、カメラコンポーネントを取得してWorldToScreenPointを位置に適用するだけなので簡単です。
    キャラクターのスクリーン座標がわかったら、UIの位置を補正するなどしてUIのスクリーン座標を決めます。頭上にHPを出したければ、キャラクターのスクリーン座標に適当な量yを増やせばいいです。このスクリーン座標をUIの座標にして、それをUIにセットすれば目的が達成されます。RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform rect, Vector2 screenPoint, Camera cam, out Vector2 localPoint)を使えば、あるRectTransform内でのローカル座標を求めることができます。rectは設定したいUIの親になることがほとんどになるでしょう。camはCanvasに使っているカメラを渡します。オーバーレイモードならnullにします。localPointには結果を取得するための変数を渡します。これで得られたlocalPointを設定したいUIのRectTransform.localPositionに設定すると完成です。

    UI同士を連携したい場合
    UIのCanvasが異なるなど単純には位置を求められない場合もスクリーン座標を介することで位置を連携することができます。
    あるUIの位置がスクリーン座標でどこになるかが分かれば良いことになります。これはRectTransformUtility.WorldToScreenPoint(Camera cam, Vector3 worldPoint)を使うと可能です。なぜかこれについてはドキュメントに載っていないようです。使い方は引数からわかるようにUIを表示しているカメラとRectTransform.position(ワールド座標)を渡します。
    スクリーン座標からUIの座標を求めることは既に述べたので、これでどちらにも変換ができます。


    UIのもつ座標→スクリーン座標とその逆であるスクリーン座標→UIのもつ座標の変換方法があれば自由に位置を調整できるということになります。
    • UIのもつ座標→スクリーン座標はRectTransformUtility.WorldToScreenPoint
    • スクリーン座標→UIのもつ座標はRectTransformUtility.ScreenPointToLocalPointInRectangle
    を使うことで可能です。
    注意点はピボットの位置がRectTransformの位置である(localPositionとかはピボットの位置を表しているということ)ということです。変換を行うときに微妙に位置がずれるときはピボットの位置がセンターだったり、トップだったりと統一がされていない可能性があります。

    意外とありそうなミスとしてはアクティブでないUIの座標を取得してしまうことです。このときの座標は正しくないようなので、起こりやすい間違いです。 これは消していたいUIの座標を取りたいという時に困るのですが、どうしようもないようです。

    以上のような変換はスクリプトで制御したい場合に必要になることが多いでしょう。Canvasの異なるUI同士の座標をそろえたりする機能が今のところなさそうなので、こういった方法が要ると思っています。
    もっと簡単な方法があると良いのですが…… 

    • カテゴリ:
      このエントリーをはてなブックマークに追加 Clip to Evernote
    Unity UIにはOutlineというコンポーネントがあります。
    実は影をつけるエフェクトもそうなのですが、単にコピーを下に描いているだけのものです。コピーの数は上下左右で4つです。そのため描画する文字は5倍になります。
    outline
    OutlineコンポーネントのEffect Distanceを大きな値にすると4つのコピーがあることがわかります。

    outline-edge
    「あ」の右下のはらいの部分で縁がいびつにになっているのがわかります。大きな文字だと意外と気になることもあります。
    4つコピーを配置することでも十分なこともあるのですが、もっと多くのコピーが存在している方が文字の縁が綺麗になります。ある文字から等距離にコピーを配置していけばうまくいきます。つまりコピーはオリジナルの文字列から一定距離の円周状に配置します。
    Unite2015 uGUIの拡張と応用」を参考に拡張したOutlineコンポーネントを作ってみました。拡張したOutlineコンポーネントCircleOutlineのソースコードはこの記事の一番下に置いておきます。(Unity 5.2.3では動いていますが、Unity 5.3以降でBaseMeshEffectの使い方が変わっている可能性があります。実際5.2で何回か変わっていて、そのたびに少しずつ変えています。)

    CircleOutlineで縁をつけたものが以下のようになります。10個のコピーを使った例が下の文字になります。縁が丸みを帯びて滑らかになっているのがわかります。
    circleoutline

    これはアウトラインが単なるコピーによってできていることを示す動画です。
    かなり離れたところに出るように設定してあるので、増えていくと円形の模様になっています。
    ol
     
    コピーしているという性質上オリジナルのアルファを下げていくと、コピーが重なっているところが目立ってきてしまいます。不透明にして使うとコピーがオリジナルに隠れて最も見やすいです。
    アウトラインをつけられるのはUIの要素のText以外にもImageも可能だったりします。

    ソースコードを以下に載せておきます。 

    • カテゴリ:
      このエントリーをはてなブックマークに追加 Clip to Evernote
    Unity 5.2以前のUnity UIでは文字は4つの頂点で作られていました。今回5.2にアップデートしてみると文字を作るための頂点数が6つに増えていました。一文字表示するのに6つの頂点(2つの三角形)で描画することになります。 
    正確に言うと頂点の数は4つですが、三角形を2回書くために左上と右下の頂点が2回使われます。これで6つの頂点が使われることになります。

    6verts
    画像を良く見ると黒い線が入っています。これはワイヤフレームも表示するようにしたためです。
    一文字につき2つの三角形で構成されているのがわかると思います。3角形ひとつを描くには3つの頂点が必要なので、6頂点で一文字になります。

    頂点の並びは次のようでした。
    vertex
    これはBaseMeshEffectというUIにエフェクトをつけるときに使う基底クラスを使って調べました。頂点の情報をいじることで変形したり、色を変えたりすることができます。
    上の画像では、各頂点に異なる6色を使うようなエフェクトを作り適用しています。ななめに色が分断されているのは面が分かれてしまっているためです。(これにより5.2ではグラデーションをかけるエフェクトをつくるのが面倒になりました。文字のグラデーションのエフェクトを作っている人がいましたので、リンクを張っておきます。さけのさかなのブログより「uGUIでグラデーション文字 その2」)

    Unity5.2以前では、エフェクトをかける基底クラスはBaseVertexEffectというものでした。Unity5.2からBaseMeshEffectというクラスに変わってしまったので、作り方が少し変わります。フォーラムにこのように作れば変更をあまりしなくて良いというのが載っていました。
    以前はvoid ModifyVertices(List<UIVertex> verts);をオーバーライドしていましたが、void ModifyMesh (Mesh mesh);をオーバーライドするように変わりました。MeshからList<UIVertex>をつくるVertexHelperというものができたので、それを使うと以前の書式で書くことができます。
    頂点を直接いじっていたのがメッシュをいじることに変わったので、メッシュから頂点に変換してからエフェクトをかけ、頂点からメッシュに変換するという手順にすれば、以前と同じように使えます。
     

    • カテゴリ:
      このエントリーをはてなブックマークに追加 Clip to Evernote
    9/7の夜にUnity 5.2がリリースされました。今回も色々な変更がされています。
    自分の開発環境でも既にアップデートを行い、5.2.0f3にバージョンが上がりました。
    2

    リリースノートをみると本当に多くのことを行っているのがわかります。全部を見ても仕方ないので、気になったものだけ見るのが役に立つと思います。

    個人的にはUIに追加されたドロップダウンが一番大きいものだと思います。AndroidやiOSなどのモバイル端末では画面が小さいため、オプション画面のように選択肢を並べると画面の大きな領域を使います。
    ドロップダウンは通常は小さいラベルみたいな表示なっていて、押すとリストを表示してその中から選択することができるというUIです。 
    dd
     
     項目を増やしていってもスクロールで対応しているし、ドロップダウンの領域外をクリックしたらドロップダウンを閉じるようになっていました。最近のアプリでよくある処理が組まれているので、使いやすくて良さそうです。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    Unityにはリッチテキストという機能があります。
    文字列にHTML風のタグを入れるとそれを解釈して、表示してくれる機能のとこです。

    たとえば、
    <color=red>赤色になる</color>
    というようにすると、
    赤色になるというように赤色になって表示されます。

    <size=50>大きさを指定した</size>
    というようにすると、
    50ピクセルで表示されるようになります。

    この指定はUIの要素のプロパティで指定した値よりも優先されます。
    UI.Textコンポーネントのフォントサイズを80にして、
    <size=100>で他の部分より大きくすると初めの文字だけ大きくする表現ができます。

    私が失敗したのは、Canvas Scalerの設定で画面の大きさ次第でスケールがかかるようにしていた時のことです。
    スマホの解像度はかなり差があるので、画面ごとに合うように縮小・拡大が自動でされるように指定しています。
    そのため、画面の解像度が高くなったときにピクセル数の指定が意図どおりにならないことがあるのです。
    100ピクセルの大きさで指定しても、解像度がいくつの端末で見るかによってかなり異なります。
    1920x1080と960x540の端末で見比べれば、2倍の差があることになります。

    基準となる解像度で何ピクセルになるべきかを決め、
    現在の解像度に合わせてピクセルを変更すれば良いことになります。

    ここでは縦幅を基準にして、横幅の変化は考えないことにします。
    1920x1080で100ピクセル分の大きさにしたいのであれば、
    "<size=" + (100 * Screen.height / 1920) + ">"
    という文字列を作り、
    スクリプトから設定するということをすれば、どのような解像度の端末でも同じような見た目になります。

    計算で求めて対処できますが、
    素直に新しいTextコンポーネントを用意し、そのフォントサイズを変更する方が楽で良いと思います。 【文字の大きさを変えるときの注意点】の続きを読む

      このエントリーをはてなブックマークに追加 Clip to Evernote
    UnityのUIは4.6から今の形になりました。
    この仕組みは正式名称でUnity UIと言います。リリース前はuGUIと呼ばれていたのでuGUIで説明されている場合や新GUIと呼ばれる場合もありますが、いずれも古い呼び方になります。

    それまではスクリプトから呼び出す、関数の呼び出しでUIを作るか、
    GUITextureといったコンポーネントをつけて作ることになっていました。
    ただUnityのエディタ上で直感的に作り、処理も軽いということができていませんでした。

    NGUIという有料のアセットが最も使いやすく有名でしたが、
    95$という値段がしました。
    また、細かい制御をするには結構マニュアルを読まないといけなくて、大変でした。
    処理はモバイルでも動くくらい軽量で、スマホにリリースするにはNGUIしかないというくらいでした。

    Unity4.6でUIが強化されたことにより、
    Unityでアプリを作っていくことができると思いました。
    UIをなくすというのは、ほぼ考えられないので、UIを作ることが楽であることは重要です。
    これからもっと使いやすくなることを願っています。

    今のところマニュアルが英語のものしかないので、日本語のものがほしいです。
    ここに公式ページでのチュートリアルビデオがあるので、これを見て学ぶのが良さそうです。
    英語ですが、頑張って聴けばなんとかなる……はず。

    このページのトップヘ