ラベル プログラミング_Unity の投稿を表示しています。 すべての投稿を表示
ラベル プログラミング_Unity の投稿を表示しています。 すべての投稿を表示

2023年12月31日日曜日

【Unity】アスペクト比を維持して固定値を使わずに整列させる

アスペクト比を維持して固定値を使わずに整列させる方法をなんと2つも説明します。

問題設定

まずは目指す状態について説明します。

上の画像では半透明の範囲に本の画像とその白背景のセットが2つ描かれています。また白背景は正方形で、本の画像はその中に収まります。つまり、本+白背景の縦横比は1:1になります。

整列の設定を上手く施すことで、中身を増減させても自動的に間隔を調整してくれます。実際私は、以下の画像を作る時に位置や大きさを入力しませんでした。


以降の章でこの自動整列の設定方法について解説します。

なお、この記事では横に整列させる方法を解説しますが、Horizontal←→Vertical、Width←→Heigh(t)と適宜変換すれば縦にも同様に整列させられます。

共通部分

自動整列を実装する方法は複数ありますので、まずはそれらの共通部分について説明します。

上の画像は本の画像と白背景のセットが2つある場合のヒエラルキーです。

上のヒエラルキーに登場するCanvas内のGameObjectが有するComponentを以下に示します。

  • Area(親オブジェクト)
    • Horizontal Layout Group
      • 横に整列させるやつ。今回の主役
      • Control Child SizeのHeighをTrueにして、子の縦の長さを親に合わせるようにする
      • Child Force ExpandはいずれもTrueに
    • Image
      • 半透明なやつ
  • GameObject 1(子オブジェクト)
    • 今は何もつけない
  • Background(孫オブジェクト)
    • Image
      • ただの白背景なので、Spriteは何も入れない
  • Book(孫オブジェクト)
    • Image
      • 本の画像を挿す
      • 画像の比を維持するため、Preserve Aspectをtrueに

これらに追加でComponentを加えるケースもあります。

Aspect Ratio Filterを子オブジェクトにつける方法

Areaに紐づける"Horizontal Layout Group"の"Control Child Size"のHeighがTrueになっている場合(上の画像)、子のオブジェクト(GameObject1)のHeightには何も入力できない状態になります。"Control Child Size"はその名の通り、子のWidthやHeightを親が決定するかどうかのフラグであり、Trueになると子オブジェクトに対するWidth/Heightの入力を受け付けなくなります。

子オブジェクトにてHeightが入力できない状態

本と白画像のセットの縦横比は1:1にするためには、Widthの値をHeightからコピーしてくる必要があります。そこで、子オブジェクトに"Aspect Ratio Filter"を適用します。

Aspect Ratio Filterはそのオブジェクトのアスペクト比を自動で決定するためのComponentです。Aspect Modeで"Height Controls Width"を選択すると、WidthがHeightの値から自動入力されます。このように設定することで、本+白背景を複製しても同じ親にある限り上手に間隔を作ってくれます。

しかし残念なことに、子オブジェクト以下をPrefab化してスクリプト上から複製すると自動整列が機能しません。Aspect Ratio FilterとHorizontal Layout Groupが共存すると発生する問題のようで、入力をロックする箇所が異なっていても動作しないようです(実際警告が出てる)。Aspect Ratio Filterが先にWidthやHeightをロックすることで後のLayoutGroupが動作できなくなり、機能しないのではないかと睨んでいます。Prefabから生成する場合は次の方法を試してみてください。

Aspect Ratio Filterを孫オブジェクトにつける

代替案として、子オブジェクトの代わりに孫オブジェクト(Background)にAspect Ratio Filterをつけることでも自動整列が可能です。その際、Aspect Modeを"Envelope Parent"に設定しましょう。Envelope Parentモード下では、元々設定していた孫オブジェクトの大きさを子の大きさによって拡大することが可能になります。

孫オブジェクト(Background)のComponent

上の画像ではW Deltaに82.79999と入力されています。これは親オブジェクトのHeightが182.79999で、元々設定されていた子オブジェクトのWidthが100であり、Envelope Parentによって引き伸ばされた分がW Deltaに入力されます。

この方法ではPrefabから生成しても自動整列が機能します。Aspect Ratio FilterとHorizontal Layout Groupが同じ箇所をロックすることもないので、警告も発生しません

余談

自動整列問題がややこしいのは、WidthやHeightを画面の大きさに応じて変化させようとするからです。WidthやHeightに固定値を入力させられれば、Layout Elementなどを利用してもっとわかりやすく自動整列を実装できます。まずは画面のサイズを最初に決めて、WidthやHeightに固定値を入力させるのが良いと思います(一敗)。

まとめ

  • XXX Layout Groupを親に設定して整列させる
  • Aspect Ratio Filterを子か孫に設定してアスペクトを維持させる
  • 画面のサイズは最初に決めよう


以上です。

2018年6月28日木曜日

【unity】コルーチンの中でwhile文を書いたら

  1. IEnumerator DealHard () {
  2. while (time > 0) {
  3. time -= Time.deltaTime;
  4.  
  5. lefttime.text = ((int)time).ToString ();
  6. }
  7. time = 0;
  8.  
  9. Debug.Log ("タイムアップ");
  10. }

このスクリプトは残り時間を計測しその秒数をテキストに出しています。

このコードではunityが途中でバグります。(それか一瞬でtimeが0になる)

どこが間違っているかお分かりですか?

  1. IEnumerator DealHard () {
  2. while (time > 0) {
  3. time -= Time.deltaTime;
  4.  
  5. lefttime.text = ((int)time).ToString ();
  6.  
  7. yield return null; // ここ
  8. }
  9. time = 0;
  10.  
  11. Debug.Log ("タイムアップ");
  12. }

正解は yield return null をwhileの中に書いていないことです。

そもそも Time.deltaTime は前のフレームと次のフレームの時間差を取るものです。
最初のコードでは無数の繰り返し処理が1フレームで行われてしまいます。
そして何やかんやでunityが死ぬ。

yield return null はそのフレームの作業を中断し次のフレームから再開させます。
つまり、 Time.deltaTime との相性がよくなるわけです。
よかった、これで解決ですね

2018年6月19日火曜日

【unity】GUI上でButtonの状態に応じてtextの色を変える

タイトルの問題に関して以下の英語の記事を参考にしました
というかほぼ答え感ある
https://answers.unity.com/questions/940456/how-to-change-text-color-on-hover-in-new-gui.html




ボタンにマウスを重ねた時にボタンじゃなくてテキストの色が変わってほしい!
黒色から赤色に変わってほしい!

テキストの色を変えるのは結構簡単に変えることができます。

ButtonコンポーネントのTransitionが "Color Tint" になっていることを確認して、
Transitionの中のTargetGraphicをTextを持っているオブジェクトに変えればいいだけです。

それでできるんかーい

ちなみにTargetGraphicにTextが出てこない場合はButtonとTextの親子関係を確かめてください。
デフォルトなら大丈夫です。

デフォルトの親子関係


しかーーーーし!!!

マウスを重ねている状態

これだと黒色から赤っぽい黒色に変わっただけです。
マウスを重ねた時に黒色から完全な赤色に変えるにはどうしたらいいのでしょうか。

答えはTextのフォントの色を白にし、ButtonのNomalColorを黒にすればいいのです。



ButtonのTrasitionでの色の変更はあくまで元々の色に新しい色でかけ算を行なっているだけです。
なのでもしフォントの色が完全な黒(=RGBが全て0)では、Buttonから色の変更を試みても掛けたら0になるので真っ黒のままになります(Buttonの色変更を受け付けない)。
黒色から赤っぽい黒色になったのもこれが原因。

それなら元々のフォントの色を完全な白(=RGBが全て1)にして、後から色を変えるときは全てButton側から行えば良いのです。


余談ですがこれの本領を発揮するのはButtonの表示を透明にすることにあります。

これが

こうじゃ


スクリプトなしでもそれっぽいUIが作れそうですね。これは強い。

2018年5月8日火曜日

【unity】ボタンのクリック領域がずれた

自分のホームページを作ってみたものの何もゲームがなくて寂しい...
ということで急遽ゲームを作っています。GW?知らないなぁそんなものは
その作業中ボタンの領域判定がずれてしまったことを記事にします。



これは1~15まで書かれたボタンをプレハブを使って設置しています。
グラデーションは気にしないでください。
これだけだと問題あるようには見えませんがカーソルを近づけると、



自分のカーソルとは違う場所に色がついています。
グラデーションは(ry

1. canvasの描画順


私が見落としていた部分がいくつかあって、その1つがcanvasの描画順です。



この画像では上から1,2,3,...,15とCloneが作られています。
数字は子オブジェクトのテキストに表示させています。
canvas内で上にある方が一番奥に描画されるので、ここでは"1"が最も奥に描画されます。
先ほど見ていただいた動画では10や15などの右端の数字の判定領域が大きくなっていました。
これは10や15がその行で最も手前に描画されるためです。

2. 子オブジェクトの範囲


次は知らなかったのですが、ボタンの有効範囲は子オブジェクトに影響されることです。
子オブジェクトが広かったらその分クリックされる範囲も大きくなります。
実は他サイト様を参考にしながら透明な画像を追加してみたり迷走していましたが、うまく行かず、試行錯誤すること30分。



ワイ「だめや......いろいろ追加してみたけど表示がおかしいままや.......ん?」



ワイ「めっちゃ広いやんけええええええええええええええええええ」

というわけでwidthを親オブジェクトと同じにするとうまくいきました。
テキストもクリックの領域に含まれるんですね。



3. まとめ


今まで何を喋ってきたのかというのを横からの投影図で表しました。
緑がボタンの範囲(= 本来押されてほしい場所)で、
青がその数字のクリックが有効な場所で、
灰色が描画順により無効になっている部分です。



(この図で余計にわかりにくくなったらすみません)