Unityで移動するカーソルを止めるイベントの作成とイベント部分にカメラをフォーカスする機能

今回はアクションゲーム等に登場するアクションイベントの一つでバーの上をスクロールするカーソルを特定の位置で止める機能の作成をしたいと思います。

カーソルのイベント発生地点に主人公が移動した時にはキャラクターを映していたカメラをイベント部分にフォーカスし、イベントが終わったらカメラを元の位置に戻す機能も取りつけます。

今回のカーソルのイベントは二通りの方法で作成します。

  • 一つ目はUIを使ったカーソルイベント
  • 二つ目は3Dオブジェクトを使ったカーソルイベント
  • です。

    元々はUIを使ったカーソルイベントだけ作成していたんですが、UIを動かすのは動作が遅くなりそうなので?

    普通に3Dオブジェクトを動かすカーソルイベントの方法も作りました。

    3Dオブジェクトを使った方では3Dのカーソルを動かすので立体になり正確な位置で止めたつもりがうまく止まっていなかったように見えてしまう事もあります。

    イベント部分のカメラの写し方を変えると良さそうですが・・・・。

    お好きな方法で作成してみてください。

    スポンサーリンク

    UIを使ったカーソルイベント

    まずはUIを使ったカーソルイベントを作成していきましょう。

    カーソルイベントのオブジェクトを作成

    カーソルイベントゲームオブジェクト

    ヒエラルキー上で右クリック→Create Emptyを選択し、名前をCursorEventに変更します。

    その子要素に右クリック→3D Object→Cubeを選択し名前をWallにします。

    壁のインスペクタ

    ↑のようにCubeのサイズを調整し、カーソルイベントを張り付ける壁を作成します。

    次にCursorEventの子要素に右クリック→UI→Sliderを選択し、カーソルイベント用のスライダーUIを作成します。

    カーソルイベントUIのインスペクタ

    UIを他のゲームオブジェクトと同じ空間に表示させる為CanvasのRender ModeをWorld Spaceに変更します。

    さきほど作成した壁の大きさと合うようにScaleを調整します。

    カーソルを動かすスクリプトChangeValueを作成する

    次にCanvasの子要素のSliderに新しいスクリプトChangeValueを作成し取りつけます。

    Start関数内でスライダーのinteractableをfalseにしています。

    UIのスライダーはマウスで移動させる事が出来るのが本来の使い方なのでinteractableをfalseにしないとマウスでも移動出来てしまいます。

    なのでStart関数内でinteractableをfalseにしてマウスでは動かせないようにしておきます。
    (スクリプトではなくインスペクタのinteractableのチェックを外す事でも同じです)。

    Update関数内ではカーソルが動いている方向で処理を分け、スライダーの値を足したり引いたりしています。

    カーソルの動くスピードはインスペクタで設定出来るようにし、Time.deltaTimeをかける事でパソコンの処理速度で変化がないようにします。

    OnOffMeter関数はカーソルの移動をするかしないかを切り替える関数です。

    Judge関数はカーソルが指定範囲内ならtrue、指定範囲外ならfalseを返す関数です。

    指定範囲はインスペクタで設定出来るようにしています。

    カーソルイベントが発生したらOnOffMeter関数を呼び出してカーソルを動かし、イベントが終了したらOnOffMeter関数を呼び出しカーソルを止めるという感じになります。

    スライダーUIのインスペクタ

    ↑のようにChangeValueスクリプトをSliderに取り付け値を設定します。

    成功範囲を作成する

    次はさきほど設定した数値の成功範囲を視覚的にわかるように成功範囲部分を見た目でわかるようにします。

    Sliderの子要素に右クリック→UI→Imageを作成します。

    カーソルイベント成功範囲

    ↑のようにサイズと位置を調整し、指定した数値の範囲と合うようにします。

    このImageのサイズは親要素であるSliderの幅などに合わせて調整する必要があります。

    動かすカーソルのImageを変更する

    次は動かすカーソルのImageを変更します。

    Sliderの子要素のHandle Slide Area→Handleを選択し、Source Imageを変更します。

    カーソルイベントのカーソル

    ↑のようにSource Imageをストップウォッチに変更しました。

    カーソルイベントが発生する範囲を作成する

    次はカーソルイベントが発生する範囲を作成し、キャラクターがその範囲に侵入したらイベントを起動させます。

    カーソルイベントの発生範囲

    CursorEventの子要素に右クリック→Create Emptyを選択し名前をSearchAreaとします。

    インスペクタのAdd ComponentからPhysics→Box Colliderを追加しサイズを調整し、Is Triggerにチェックを入れ物理的に当たらないようにします。

    MeterSearchCharaスクリプトは後で作成します。

    これでイベント部分の作成が終了しました。

    カーソルイベント実物

    ↑が実際に作成したイベント部分のゲームオブジェクト、UI、キャラクター検知エリアになります。

    これでUIを使ったカーソルイベント部分が出来たので後は3Dオブジェクトと共通の機能部分を作成します。

    以下の3Dオブジェクトを使ったカーソルイベントを飛ばして共通部分の機能を作成していってください。

    3Dオブジェクトを使ったカーソルイベント

    3Dオブジェクトを使ったカーソルイベントを作成していきます。

    ヒエラルキー上で右クリック→Create Emptyを選択し名前をCursorEvent2にします。

    3Dオブジェクトを使ったカーソルイベント階層

    ↑が実際に作成するカーソルイベントの3Dオブジェクトの階層になります。

    イベントの壁を作成

    CursorEvent2の子要素に右クリック→3D Object→Cubeを選択し名前をWallにします。

    3Dオブジェクトを使ったカーソルイベントの壁

    サイズを調整し壁を作成します。

    カーソルが移動する部分を作成

    次にカーソルが移動する部分を作成します。

    ヒエラルキーで右クリック→3D Object→Cubeを選択し名前をBarとします。

    カーソルの移動するバー

    ↑のようにサイズを調整しIs Triggerのチェックし物理的に当たらないようにします。

    またBar用にBarColorというMaterialを作成し設定します。

    Assetsエリアで右クリック→Create→Materialを選択します。

    Bar用のマテリアルを作成

    ↑のようにマテリアルが作成されるので名前をBarColorとします。

    MaterialのAlbedoを変更

    Albedoの右側の色選択部分をクリックし色を変更します。

    色は青色にしてA(Alpha)を100にし、RenderModeをTransparentにして透明部分を反映させるようにします。

    マテリアルが出来たらマテリアルをBarにドラッグ&ドロップします。

    カーソルが止まったら成功とする範囲を作成

    次はBarの子要素に右クリック→3D Object→Cubeを選択し名前をHitAreaとします。

    カーソルイベントの成功エリア

    ↑のようにサイズを調整し、Box ColliderのIs Triggerのチェックをいれます。

    HitArea用にもマテリアルを作成し設定してください(作り方はBarの時と同じです)。

    カーソルが範囲内にあるかどうか判定するCheckValueスクリプトの作成

    HitAreaにはCheckValueスクリプトを新しく作成し取りつけます。

    OnTriggerStay関数でHitArea内に侵入してきたのがCursorタグが設定されたゲームオブジェクトだった時にjudgeをtrueにし、

    OnTriggerExit関数で範囲外に出たのがCursorタグが設定されたゲームオブジェクトだった時にjudgeをfalseにしています。

    Judge関数はjudge変数の値を返すだけです。

    動かすカーソルの作成

    次に動かすカーソルを作成します。

    Barの子要素に右クリック→3D Object→Cubeを選択し名前をCursorとします。

    動かすカーソル

    Box ColliderのIs Triggerにチェックを入れます。

    Cursor用にもマテリアルを作成し設定してください。

    CursorはRigidbodyを使って動かすのでインスペクタのAdd ComponentからPhysics→Rigidbodyを取りつけます。

    RigidbodyのIs kinematicにチェックを入れておきます。

    カーソルを動かすMoveCursorスクリプトの作成

    Cursorを動かすスクリプトMoveCursorを作成しましょう。

    動かすスピードはインスペクタで設定出来るようにしています。

    RigidbodyのMovePosition関数を使ってCursorを移動させています。

    Mathf.Sinを使って-1から1の値が切り替わるように引数にTime.time(Unity起動からの経過時間)を設定します。

    Time.timeにspeedをかけることによって移動するスピードを変化させています。

    カーソルを移動させるのはX軸だけなのでY、Z軸は元の位置をそのまま設定しています。

    この処理で一つ問題になるのが、カーソルイベント発生時のカーソルの位置が固定にはならないところです。

    X軸の位置をMathf.Sin(Time.time)で指定している為Unityの起動からの時間によって位置が変わる為です。

    どうしても固定の初期位置にしなければならない時は自前でX軸の値を変更し、指定範囲外に来たら逆向きにカーソルを移動させる処理を記述するといいと思います。

    カーソルイベント部分詳細

    ↑がイベント部分をアップにした画像です。

    Barの範囲内にCursorとHitAreaが含まれるように作成しており、CursorはBarの箱の中を移動するような感じになります。

    CursorゲームオブジェクトにはCursorというタグを作成し取りつけておいてください。

    カーソルイベントの検知エリア

    次はカーソルイベントに突入するエリアを作成します。

    カーソルイベントの検知エリア

    CursorEvent2の子要素に右クリック→Create Emptyをし名前をSearchAreaとします。

    インスペクタのAdd ComponentからPhysics→Box Colliderを追加しIs Triggerにチェックを入れます。

    MeterSearchCharaスクリプトは後で作成します。

    3Dオブジェクトで作成したカーソルイベント部分

    ↑が実際に作成した3Dオブジェクトのカーソルイベント部分になります。

    後はUIカーソルイベントと共通の部分を作成していきます。

    共通部分のスクリプト作成

    ここからはUI、3Dオブジェクトで作成したカーソルイベントで使う共通の部分を作成していきます。

    それぞれで違うスクリプトを使っている所もあるので、一部変更する必要はあります。

    キャラクター操作スクリプトEventCharacterMoveの作成

    まずは主人公操作スクリプトを作成していきます。

    主人公が通常時の状態とカーソルイベントの状態の時で処理わけをしています。

    SetState関数内ではイベントの状態になった時に主人公のアニメーションを立っている状態へと遷移させ、イベントから復帰後に他のアニメーションにならないようにします。

    またイベント発生時にカメラがイベント部分にフォーカスする時、キャラクターが間に入ってしまうとイベント部分が見えなくなってしまうので、

    イベント時には登録したキャラクターの体をすべて見えないようにしています(インスペクタで見えなくする体を設定する)。

    ↑のスクリプトはUIを使ったカーソルイベント時のもので3Dオブジェクトのカーソルイベントを使う場合はコメント化している部分を使い、UIで使っている部分を削除してください。

    イベント時の主人公の処理を見てみましょう。

    イベント時にSPACEキーを押してイベントが成功したか失敗したかで処理わけをしています。

    成功時にはカーソルの動きを止めてカメラのフォーカスをイベント部分からキャラクターへと変更します。

    またキャラクターの状態の変更、カーソルイベントの成功の通知、カーソルイベントの解除をします。

    失敗時にはカーソルの動きを止めてカメラのフォーカスをキャラクターに戻し、

    主人公の状態の変更、カーソルイベントの解除をするという流れになっています。

    主人公キャラクターにはPlayerというタグを作成し取りつけておいてください。

    キャラクター検知スクリプトMeterSearchCharaの作成

    次にキャラクターの検知とイベントの終了を管理するMeterSearchCharaスクリプトを作成しSearchAreaに取り付けます。

    SearchAreaの範囲内にキャラクターが侵入した時にカメラをイベント部分にフォーカスしたりキャラクターの状態を変更したりしています。

    イベントが発生するのは侵入者がキャラクターでこのカーソルイベントがすでに動いていない、イベントを成功していないという条件になります。

    Main Cameraの設定

    次にカメラの設定をしていきます。

    カメラがキャラクターを追従するようにFollowTargetスクリプトを設定

    キャラクターが通常の動きをしている(カーソルイベント中ではない)時はMain Cameraがキャラクターを追いかけて表示するようにします。

    Main Cameraのインスペクタを表示し、Add ComponentからScripts→UnityStandardAsset.Utility→Follow Targetを追加します。

    MainCameraのインスペクタ

    Targetには主人公キャラクターを指定し、主人公を写すカメラの位置をOffsetで指定します。

    イベント部分にカメラをフォーカスするスクリプトMoveCamera

    次にカーソルイベントが始まる前にキャラクターを写していたカメラをカーソルイベントにフォーカスするスクリプトMoveCameraを作成します。

    カメラをイベント部分にフォーカスする時と通常時のカメラに戻す処理で分けています。

    カメラをイベント部分にフォーカスする時の処理では最初にSetMoveFlag関数が呼ばれ、現在のカメラの位置をdefaultCameraPositionに入れておきます。

    MeterSearchCharaスクリプトでSetMoveFlagと同時にSetFollowTarget関数も呼んでいますが、SetFollowTarget関数ではキャラクターを追従するようにしているFollowTargetスクリプトを無効化してます。

    これはカメラの位置を移動させる時にFollowTargetスクリプトが動作してしまうとカメラ位置が変わらない為です。

    Update関数内でVector3.Lerpを使ってカメラをスムースに移動させ、指定した位置に近付いたらmoveFlagをfalseにしカーソルが動くようにしています。

    カメラを通常の位置に戻す場合はカメラが元の位置に戻ったらFollowTargetスクリプトを有効化し、キャラクターを動かせる状態にしています。

    UI、3Dオブジェクトどちらのカーソルイベントを使うかによってスクリプトを一部変更する必要があります。

    イベントが成功したかどうかを表示するテキストUI

    イベントが成功したか失敗したかを表示するテキストUIを作成しましょう。

    今回は面倒くさいので解りやすくする為、簡易的にしましょう。

    本来であればイベントが終了した時にテキストUIのプレハブを一時的に表示するという処理にするのがいいと思います。

    ヒエラルキー上で右クリック→UI→Panelを選択しパネルを作成します。

    Panelの子要素に右クリック→UI→Textを選択しテキストUIを作成します。

    イベントの情報を表示するテキストUI

    ↑のような階層が出来ました(Canvasは自動的に作成されます。作成されなかった場合はUI→Canvasを作成し、同じ階層を作ってください)。

    PanelのWidthとHeightを調整しサイズを小さくします。

    イベント情報表示UIの位置

    ↑のようにイベント部分とかぶらないような位置にCanvasを移動させておきます。

    EventCharacterMoveスクリプトのインスペクタのTextを指定する場所に今作成したTextをドラッグ&ドロップしておきます。

    これでイベントが成功したか失敗したかの表示がテキストに表示されるようになります。

    カーソルイベントを実行して確認する

    それでは完成した機能をUI、3Dオブジェクトの両方で確認してみましょう。

    主人公キャラクターのインスペクタを表示し、EventCharacterMoveの設定をします。

    EventCharacterMoveの設定

    ↑のようにEventCharacterMoveとEventCharacterMove2とありますが、これはわたくしの都合上ふたつのスクリプトに分かれています。

    EventCharacterMoveがUIカーソルイベント、EventCharacterMove2が3Dオブジェクトカーソルイベントの設定になります。

    UIを使ったカーソルイベント

    まずはUIを使ったカーソルイベントの確認をします。

    UIのカーソルイベント

    ↑のようにキャラクターがイベント部分に近付くとカメラがイベント部分にフォーカスされ、キャラクターが見えなくなります。

    イベントが失敗した時はイベントが終了し、テキストに失敗と表示され、再度イベント検知エリアに侵入するとイベントが開始されます。

    イベントが成功すると2度と同じイベントが発生しないようになります。

    UIのカーソルイベントの問題点としてはカーソルをストップウォッチにしたこと(カーソルが大きい)と成功したかどうかを実際は数値で判定している為、

    カーソルの止めた位置によっては成功しているように見えて失敗とされてしまう可能性があるところです。

    成功か失敗かの判定を数値で判定しているのでこういうことが起きてしまいますが、3Dオブジェクトと同様にコライダを使って侵入を検知した方が、

    見た目と実際が乖離する事はないと思います。

    UIの場合は2Dになるので、他のゲームオブジェクトが侵入したかどうかを検知するには

    コライダはAdd ComponentからPhysics 2Dを選択しその中から丁度いいコライダを選んで取り付ける必要があります。

    またスクリプトでは

    等の2D系のトリガーを使う必要があります。

    ちなみに3Dと2Dでの衝突の検知は別システムなのでお互いの検知は出来ません。

    3Dオブジェクトを使ったカーソルイベント

    次は3Dオブジェクトを組み合わせて作ったカーソルイベントを確認します。

    3Dオブジェクトのカーソルイベント

    動作はUIのカーソルイベントと同じですね。

    3Dオブジェクトなので厚みがあり若干位置合わせがしづらい感じがしますね。

    またカーソルはBarとHitAreaの領域を通過するのでカーソルが若干見えづらいということも発生します。

    これを解消するにはカーソルの移動する場所を少しずらすといいと思います。

    元のカーソルの移動場所

    ↑がカーソルが移動する場所です。

    カーソル位置を少し移動する

    ↑のようにカーソルの移動する位置を少し手前に移動します。

    コライダの中心とサイズを変更する

    カーソルの移動する場所が変わったのでHitAreaのコライダのCenterとSizeを変更し検知するエリアを広げます。

    検知するエリアを広げる

    変更すると↑のような検知エリアになります。

    実際に動かしてみると、

    カーソルが被らなくなった

    ↑のようにカーソルが少し手前で移動するので見づらくなる事はなくなります。

    ただカーソルが黒色なのでよくわかりませんな・・・・(^_^;)

    カーソルイベントとカメラのフォーカス機能を作り終えて

    これでカーソルイベントとカメラをイベント部分にフォーカスする機能が完成しました。

    最初はUIを使った処理だけ作成していたんですが、前述した通りの処理速度の問題がありそうなので3Dオブジェクトの方も作成しました。

    3Dオブジェクトのカーソルイベントを作成したことで数値で成功範囲を検知する必要がなくより簡単な処理で出来るようにもなりました。

    UIの方もコライダを使った処理の方がいいかもしれませんね・・・・。

    今回の機能はご依頼頂いた機能で、バーのイベント部分のみ作ろうと思ったんですが、実際に作り始めたらカメラのフォーカスの機能まで一緒に取り付けてしまって・・・・。

    一つの記事に色々な機能を詰め込むから長く解り辛い記事になるんでしょうね・・・・(^_^;)

    一つの記事には一つの機能を心がけたいと思います・・・・(-_-)

    個別の機能に関してはピックアップしてまた別記事として作成するのもありかもしれませんな・・・・うーむ。

    スポンサーリンク

    記事をシェアして頂ける方はこちら

    フォローして頂くとやる気が出ます

    コメント

    1. Mika より:

      遅くなりましたが、明けましておめでとうございます。(*´▽`*)
      (・_・D フムフムUIだとanime処理が重くなる…と( ..)φメモメモ(←本当に判っているのか(;´∀`))
      3Dはカメラ角度が胆ですね…。

      バーの成功を一つ追加して、失敗、ノーマルアイテムゲット、レアアイテムをゲットするミニゲームなんかにも応用できそうですね、色々と作成の夢(妄想)が広がります!

      • 明けましておめでとうございます(._.)

        UIの動作が遅くなるというのは体感でそんな感じがしただけで実際はどうなのかわかりません・・・(^_^;)

        スマフォ用のゲームで動作が問題なければ大丈夫だとは思うんですが、スマフォを持っていない為に確認出来ておりません。

        エミュレータを使ってみようかな・・・・。

        3Dの方はコライダを使っているのでわかりやすく成功と失敗が検知出来るので成功範囲を複数作るのも容易に出来ますね(^_^)v

        今更ながら2Dの方もコライダでよかったと思ってしまいました・・・。

        記事のカーソルを少しずらして動かす部分に画像と文章の不足分があったので足しておきました。