「Unity」カテゴリーアーカイブ

【Unity】新しくなった4.6の新GUIでスクロールビューを実装してみる(後編)

前回に引き続き、unity4.6で実装された新GUIを使ったスクロールビューとアコーディオンの作り方についてみていきます。途中からになっていますので前回を見てない人は前の書いからどうぞ。

今回はスクロール内のアコーディオン、それにスクロール制御のスクリプトです。

ボタンを押すとアコーディオンが開くようにする

ボタンと展開される詳細部分をまとめた入れ物から用意します。
とりあえず前に作った10個ほどのボタンは消して、新しく作っていきましょう。
Verticalの下に新しくGameObjectを作って、名前を「Accordion」に変えます。その下に2つのGameObjectを入れます。名前を「Heading」と「Collapse」にします。

Headingの下にはUI->Buttonゲームオブジェクト、Collapseの下にはUI->Textゲームオブジェクトを入れます。

AccordionにLayout->Vertical Layout Groupコンポーネントをつけます。

HeadingにLayout->Layout ElementコンポーネントをつけてPreferred Heightに60を入力します。Headingの子のButtonを選択してInspectorビューをみてください。Rect TransformコンポーネントのAnchorsの上にアンカープリセットを開くボタンがあります。AnchorPresetsパネルをだしてAltキーを押すと、ポジションも一緒に変えてくれるプリセットが表示されます。右下にある縦横両方を最大限広げるプリセットを選びます。141211-0004

CollapseにはLayout->Vertical Layout Groupコンポーネントをつけます。

Collapseの縦サイズを固定にします。可変でもいけるようにしたかったですが、この後のアニメーションの都合でどうしても固定にしないとうまくいきませんでした。UI->Layout ElementコンポーネントをつけてPreferred Heightを80にします。スクリーンショット 2014-12-11 20.21.24

ではCollapseの部分が最初は閉じていて、ボタンを押すと開くように作ってみましょう。

ここではunityのAnimatorを使って開閉のアニメーションを実装したいと思います。AnimatorはMechanimというunityの特徴的なアニメーション管理方法で、Stateという状態をブレンドしたりしてアニメーションの間を補完する動きを作ってくれるみたいです。

まずAccordionにMiscellaneous->Animatorコンポーネントを追加します。まだAnimatorControllerは作っていないのでメニューからAssets->Create->Animator Controllerを選択します。ProjectビューをみるとNew Animatorができているので、名前を「ExpandAnimator」とでもしておきます。
できたExpandAnimatorを先ほど作ったCollapseにあるAnimatorコンポーネントのControllerプロパティに放り込んでください。

まずClosedから。Hierarchyビューでアニメーションの対象となるCollapseを選択してあるのを確認して下さい。Animationビューを開いてください。AddCurveボタンがでています。
AddCurbeを押すとセーブするファイル名を聞かれますのでClosed.animにしてセーブするとAnimatorビューにClosedというStatsが新しくできました。

Animationビューをみてください。丸いアイコンが赤く表示されています。記録モードになっています。今、Collapseが選択されているはずです。InspectorビューでLayout ElementコンポーネントのPreferred Heightを0にします。これで0秒の位置にキーフレームが打たれました。Closedはこれだけでかまいません。

AnimationビューのOpenと書かれてあるリストボックスから[Create New Clip]を選択します。

141208-0006ファイル名はOpen.animにします。Collapseを選択してLayout ElementコンポーネントのPreferred Heightを80で記録します。

Animatorビューを開いてください。何も表示されていなかったらHierarchyビューでCollapseを選択してください。Closedを選択してから右クリックを押し、Make Transitionを選択します。一見何も起こっていないようですが、このままカーソルをOpenの上にまで持ってくると、Closedから伸びる矢印が表示されます。ここで左クリックで確定です。同じようにOpenからもTransitionをClosedに向かって付けます。

この状態でゲームを再生(MacだとショートカットはCommand+P)してみると、Collapseがぱくぱくと閉じたり開いたりしています。おっと、Collapseの中心点を変えるのを忘れていました。CollapseのPivot.YをInspectorビューで1に変えてもう一度再生してみてください。上から下に、開いたり閉じたりするアニメーションに変わりましたね。

ではボタンを押すと開いたり閉じたりするようにします。Animatorビューの左下にあるParametersというボタンの+を押します。Boolを選択して名前をOpenにします。ClosedからOpenに伸びている矢印を選択し、ConditionsをExit Timeから今作ったOpenに変えます。条件はtrueのままにしておきます。もうひとつのOpen->Closeの矢印でもConditionsをOpenにして、条件をfalseに変えます。141208-0008

ここで再生してみます。アニメーションは始まりませんね。Animatorビューで先ほど作ったOpenパラメータのチェックボックスをOnにしてみましょう。Collapseが開きます。Offにすると閉じます。

ここまで来るとあと一息です。

CollapseにScriptを付けます。Collapseを選んでInspectorビューでAdd Componentボタンを押し、New Scriptを選択するとファイル名を入力できますので「AccordionExpander」と入力。LanguageはCSharpにします。

Accordion Expander(Script)コンポーネントがCollapseに付加されました。Scriptのファイル名をダブルクリックするとMonoDevelopが開いて編集画面がでてきます。

このソースを貼り付けてください。

HierarchyビューでButtonを選択し、InspectorビューのButton(Script)コンポーネントのOnClick()プロパティの+ボタンを押します。ターゲットになるオブジェクトにCollapseを放り込んで、先ほど作ったAccordionExpanderスクリプトコンポーネントのOnClick関数を選択します。

さあ、ゲームを再生してみてください。ボタンを押すとCollapseの中身が閉じたり開いたリします。

Accordionをプレファブに適用するためApplyをして、Accordionプレファブをたくさん並べてからゲームを再生すると、最初アコーディオンは閉じて並んでいて、ひとつを開くと下のアコーディオンも位置が下がることが分かります。

スクロールの中心位置をスクリプトで制御する

一番下のボタンをクリックしたときスクロールが上にあがるようにしてみます。

AccordionExpander.csを次のように書き換えます。

このスクロールの位置がピボットに変換されることで下の方もいい感じに広がるのは私にしてはいい思いつきだと思ったのですが、どうでしょう。

これでスクロールの出来上がりです。どんなサイズのゲーム画面にもぴったりフィットしていて、まるでスマホのアプリ画面のようです。

スクリーンショット 2014-12-11 18.33.26

 

パトラッシュ・・・

これだけ書くのに疲れました。記事が2回に分かれたのも初めてです。簡単にスクロールビュー作れた、ひゃっほーと思ったのに、説明するとこんなに長いとは。しかも、書いてみて分かったのですが、決して簡単とは言えませんね。普通にHTMLなどで構成するのに較べるとかなり大変です。自分で実装すること考えるとすごい楽だったんですけどね。。

せめて動画での説明だったらもうちょっと簡単に思えるかもしれません。Unityの新UIの説明がテキストよりも動画の方が充実している理由が分かった気がします。

それではこの辺で。

 

 

 

【Unity】新しくなった4.6の新GUIでスクロールビューを実装してみる(前編)

こんにちわ。unityの仕事ください。と言い続けているつもりで4年。いまだunityの仕事に巡りあえず。今回初めてunityの仕事がきて久しぶりに触りました。新しくインストールした4.6では2Dが作りやすくなったおかげで思ったより早くできました。アコーディオンとスクロールビューがそれなりに使えそうでしたので紹介します。開閉が画面内で行われるよう調整したものです。

2Dオブジェクトを置いてみよう

とりあえずスクロールの背景になるパネルでも置いてみます。メニューからGameObject->UI->Panelを選択してみましょう。
Hierarchyビューをみてください。Panelが作成されましたね。選択するとInspectorビューに情報が表示されます。

スクリーンショット 2014-12-07 21.52.27
PanelはCanvasという新しいオブジェクトの下に作られました。EventSystemも新たに作られています。
Canvasは2D描画に必ず必要なルートになる領域なので、Canvasがない状態でUIオブジェクトが作成された時には自動的に作成されます。
EventSystemはGUIを操作するために必要なオブジェクトで、これも無ければ自動的に作れます。

Vertical Layout Groupでボタンを縦に並べよう

パネルの下にもう1つパネルを作ります。
Hierarchy上でPanelを選択した状態で右クリックをしてUI->Panelを選択しましょう。
Panelの下にPanelが置かれます。ちなみに先ほどと同じようにメニューからPanelを作るとCanvasの下に作られるので移動させてください。同じような操作でも結果が違う、unityってこういう直感的にどうなるか分かりづらい操作がけっこうありますね。
新しく作ったPanelの名前をVerticalに変えます。

オブジェクトを置いてみます。ボタンでも並べてみましょう。
Verticalの下にUI->Buttonを選択してButtonを置いてください。

Buttonをたくさん並べるのでButtonを大量作成します。Buttonを選んでコピー・ペーストすればいいんですが、ここはプレファブにしておきましょう。複数あるオブジェクトは必ずプレファブにしておくのがunityのやり方です。
ButtonをProjectビューに放り込んでプレファブに。HierarchyのButtonが青くなったらプレファブになった証拠。Hierarchyビューで青くなったButtonを選択してコピーペーストを繰り返します。10個くらい作ったらいいでしょう。

Buttonが同じ所に重なっていますね。オートレイアウトを使うので手で並べる必要はありません。Verticalを選択してInspectorビューにAddComponentでLayout->Vertical Layout Groupコンポーネントを選択します。Buttonが縦に並びましたね。

スクリーンショット 2014-12-07 22.53.05
Vertical Layout Groupは子のオブジェクトを縦に隙間なく並べてくれます。

これだと縦にぴっちりでボタンの縦サイズを制御しにくいので、VerticalにLayout->Content Size Fitterコンポーネントも追加します。Vertical FitをPreferredSizeにします。
Buttonに縦サイズを入力しましょう。ButtonにLayout->Layout Elementコンポーネントを追加し、PreferredHeightに60と入力します。Inspectorビューの上部にあるPrefabツールのApplyボタンを押せばPrefabが置き換わり、コピー先のPrefabにも反映されます。全てのボタンのPrefferdHeightが60になりました。

Verticalの縦がPanelを越えて伸びたでしょうか。

スクリーンショット 2014-12-07 23.12.33

Verticalが画面に表示された時、スクロールが一番上の位置にあって欲しいです。
Verticalの上のPanelにもUI->Vertical Layout Groupコンポーネントを追加し、VerticalのPivotを1にしましょう。Verticalの上端がPanelの上端にぴったり重なりました。なんでこうなるか、説明はうまく出来ません。でも次のような操作をしてみれば感覚的に分かるかもしれません。ギズモトグルをピボットに変えて、InspectorのPivotでYと書いてあるラベルを掴んで左右にマウスを動かしてみてください。画面内で青いドーナツ状のピボットが上下に動き、それがパネル内の位置を変えていることが視覚的に分かるかと思います。

スクリーンショット 2014-12-07 23.34.28

Scroll Rectでスクロールする画面に

さて、Panelにスクロールビューの機能を持たせたいと思います。ここで名前をScrollViewに変えておきましょう。意味はないですが、分かりやすくするためです。
ちなみにHierarchyビューで名前を変えると、scriptの方で指定していたのと整合性がとれずしょっちゅうscriptの方で手直しが必要になりました。機能に合わせて名前を変えることは多いと思うので、自動でscriptの方も修正してくれると良いのですが今のとこそういう方法もなさそうなのでscriptの方でうまいこと名前と関係なく紐付けるよう組むのがコツになってきそうですね。

ScrollViewにUI->Scroll Rectコンポーネントを付け加えます。
縦にスクロールするだけでいいのでHorizontalのチェックは外しておきます。
Scroll RectのContentプロパティにVerticalを放り込んでください。
これで実行するとスクロールできる画面ができました。ボタンを増やしたり減らしたりしても自動でスクロール領域が計算されていい感じです。

スクリーンショット 2014-12-08 0.06.26

スクロールバーを付ける

メニューからGameObject->UI->Scrollbarでスクロールバーを作成し、Canvasの下に置きます。InspectorビューでScrollbar(Script)コンポーネントのDirectionを「Bottom To Top」に変えます。RectTransformのwidthの値を24くらいに調整して、アンカープリセットをaltを押すとでてくる縦にぴったり、右にくっつけるものを使います。141211-0003

ScrollViewのScrollRect(Script)コンポーネントにあるVertical Scrollbarプロパティに作成したScrollbarを設定します。ScrollViewのサイズはスクロールバーと重ならないよう調整しておきましょう。

長くなってきましたので、今日はこの辺りにしておきます。

今回まったくScriptを書いてませんね!すごいです。ちょっとコンポーネントはいろいろ付けないといけないですけどね。続きは、ボタンで展開するアコーディオンと、スクロール位置の制御についてみていきたいと思います。

【Unity】新しくなった4.6の新GUIでスクロールビューを実装してみる(後編)

【Unity】ドラッグで回転盤を回転させるスクリプト2

前に
【Unity】ドラッグで回転盤を回転させるスクリプト
を書きました。続きです。

作ったアプリは

農薬希釈表
おもっさまミカメジャーナル
価格:無料  平均評価:5.0(1)

デザイン協力:Studio tama,syu 音素材:魔王魂

しかしいくつか問題がありました。

1.指で中央部分を横切るようにスワイプすると回転がぎゅんっ!となる
2.かちっ、とちょうどよいところで止まって欲しい
3.ルーレット盤のように指を離しても慣性で少し動いて欲しい

まず3の慣性は、指を離した後に
[javascript]disc.rigidbody.AddTorque (Vector3.forward * (10 * rotatePower)); // 慣性で回り続ける[/javascript]
とやるとうまくいきました。が!この後、2を解決しようと摩擦をつける物理法則だとかみえないストッパーだとかいろいろ試し始めたのですが、物理演算を使おうというこの発想がそもそも間違いでした。
ここは最近のWEBサイトでよくあるスライドショーと同じで、24度回転するごとに現在の表示倍数を1,2,3とカウントし、指を離したらそのカウントした数に24度掛けたとこまで自動で回してやればいいんです。
もちろん左回りの場合は算出した度数から24度ひいたところに回してやります。
これでかちっと止まるように。

[javascript]
// 他のオブジェクトとのリンク:
public var dummyPointer : Transform; // 空のゲームオブジェクトだけでいい (見えないけどね)
public var disc : Transform; // メインの回転盤
public var currentCursor : int;
public var audioClip : AudioClip;

// Variables:
private var dummyOffset : float;
private var discOffset : float;
private var discSpilitNumber : int = 15;
private var rotatePower : float; // 0より大きいなら右回り
private var autoMove : boolean = false; // 半端な位置からの移動

// A Flag:
private var mouseIsUp : boolean = true;

// Raycast SetUp:
var hit : RaycastHit;

function Update () {
var rotation ;

// マウス押したか:
if (Input.GetMouseButton(0)){

// 判定のRaycast発射:
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);

// 光線が特定の名前のオブジェクトにあたった:
if (Physics.Raycast (ray, hit) && (hit.transform.name == "disc")){

// 常にダミーはあたった箇所を向く:
dummyPointer.LookAt(hit.point, Vector3.forward);

// マウスを押したときの初期処理:
if(mouseIsUp){

// ダミーとメイン回転盤の角度を覚えておく
dummyOffset = dummyPointer.eulerAngles.z;
discOffset = disc.eulerAngles.z;

// 最初のクリックでなくなる:
mouseIsUp = false;

}else{

// 最初のクリックでない (押し続け)
// ダミーから回転盤の回転をセットすることができる:
var z :float = discOffset + (dummyPointer.eulerAngles.z – dummyOffset);
rotatePower = z – disc.eulerAngles.z;
disc.eulerAngles.z = z;
}
}

autoMove = false;

} else {
// クリックが終わったらからフラグも戻す:
mouseIsUp = true;
autoMove = true;
disc.rigidbody.AddTorque (Vector3.forward * (10 * rotatePower)); // 慣性で回り続ける
}

disc.transform.position = new Vector3(0, 0, 0);

// 特定のポイントで止める
if (autoMove){
if (rotatePower < 0){
rotation = Quaternion.Euler(0, 0, currentCursor * (360/15));
} else {
rotation = Quaternion.Euler(0, 0, (currentCursor * (360/15)) + (360/15) );
}
disc.rotation = Quaternion.Slerp(disc.rotation, rotation, 0.1);
}

var oldCurrentCursor = currentCursor;
currentCursor = disc.eulerAngles.z / (360/discSpilitNumber);
if (oldCurrentCursor != currentCursor){
audio.PlayOneShot(audioClip);
}
}

[/javascript]

1についても簡単な方法がありました。真ん中付近をタッチで反応しなくしてやればいいのです。
穴の開いたモデリングをしてそこにColliderをつけるのではMeshColliderとなってしまい計算負荷が高いので、かぶせるように別のColliderを入れました。

SphearColliderはもっとも計算が軽いうえに、ぴったりサイズに収まるのでおあつらえむきですね。

【Unity】ドラッグで回転盤を回転させるスクリプト1

Unityで回転盤のようなものをドラッグで回転させる方法を考えていたのですが、UnityのCommunityでまさにこれだ!という回答をみつけました。

How to rotate a GameObject?

[javascript]
// 他のオブジェクトとのリンク:
var dummyPointer : Transform; // 空のゲームオブジェクトだけでいい (見えないけどね)
var disc : Transform; // メインの回転盤

// Variables:
private var dummyOffset : float;
private var discOffset : float;

// A Flag:
private var mouseIsUp : boolean = true;

// Raycast SetUp:
var hit : RaycastHit;

function Update () {

// マウス押したか:
if (Input.GetMouseButton(0)){

// 判定のRaycast発射:
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);

// 光線が特定の名前のオブジェクトにあたった:
if (Physics.Raycast (ray, hit) && (hit.transform.name == "hayami_base")){

// 常にダミーはあたった箇所を向く:
dummyPointer.LookAt(hit.point);

// マウスを押したときの初期処理:
if(mouseIsUp){

// ダミーとメイン回転盤の角度を覚えておく:
dummyOffset = dummyPointer.eulerAngles.y;
discOffset = disc.eulerAngles.y;

// 最初のクリックでなくなる:
mouseIsUp = false;

}else{

// 最初のクリックでない (押し続け)
// ダミーから回転盤の回転をセットすることができる:
disc.eulerAngles.y = discOffset + (dummyPointer.eulerAngles.y – dummyOffset);
}

}

}else if (!mouseIsUp){
// クリックが終わったらからフラグも戻す:
mouseIsUp = true;
}
}
[/javascript]

このスクリプトをMainCameraにアタッチして、dummyPointerに空のGameObjectを、discに回転させたい物体をいれ、hit.transform.name == “hayami_base”と判定しているところにはクリックして回転させるオブジェクトの名前を入れればすぐ使えるようになります。

ダミーのオブジェクトをLookAtでクリックしてる点の方向に向かせ、その角度を使用するというのはまさに目から鱗でした。LookAtという便利関数を使うために、間にオブジェクトをかませることでややこしい数学とか使わなくてもいけるもんなんですね!
あとはこれをタッチポインタ向けに書き換えればいいだけ。

続きの記事書きました。