うにty生活

UnityChanを生活させたい

ピン/シグナル/マーカー設置システムを作ってみた #34

 

f:id:tubakihimeLoveHate:20201217020035j:plain

 

今回は最近の協力ゲームでは必須の機能!

仲間などに意思表示するためのシグナル(ピン立て)機能を作成します。

 

 

 

 

 

どんなピン/シグナル/マーカーにするか

みんな大好き(知らんけど)Fortniteの、シグナルシステムを参考にしようかなと考えてます。

余談ですが最近のfortniteは有名どころとコラボしまくって結構おもしろいです笑

 

色々呼び方あると思いますが、以下「ピン」に統一します。

見てわかる範囲ですが、Fortniteのピンの特徴としては以下の通りです。

fortniteでマーカーを設置している画像

マーカーが画面外に出た時



 

Fortniteのピン機能

・指定箇所にピンを立てる

・動かない(または動く)

・ピンを指したオブジェクトのアイコン表示させる

・どの距離でもピンの大きさが同じ

・アイテムの上にピンが表示される

・ピンが画面外に出た時に、画面の四角を移動する

・障害物で表示切り替え

・距離を表示etc...

 

いろいろ挙げましたが今回は以下の仕様を実装します

実装する機能

・指定箇所にピンを立てる

・ピンを指した場所から動かない

・障害物で表示切り替え

 

こんなイメージ

ピンを指すイメージ

 

準備

ピンを用意

適当に作成しました。以下の画像はご自由に使ってください。

グリーンバックにしているので、ご使用の際は背景を透過してから使用すること推奨

 


視点移動

クリックした場所にピンを立てるので、視点操作はあってもなくてもいいのですが一応

現在のUnityちゃんの視点や動きを紹介しておきます。

 

コード

 

gistcee3a5249862de6ecdec4929980c30b8

カメラは固定で、このコードは縦方向のみの視点移動を行います。

横方向はキャラクターの子にして、キャラクター移動に依存させています。

※動画内のズーム機能はついてません。

 

 

過去にもカメラ紹介してます

【改良版】追従+マウス視点移動のTPSカメラ #18.1 - うにty生活

 

Unityちゃん移動方法

キャラクターの動かし方を見直してみた #15 - うにty生活

 

個人的なことを言うとUnityちゃんの顔が見えなくなるカメラはあまり好きじゃないです。が、簡単に実装できるカメラを一つ作成しておきかたっかので作りました。

 

照準はOverlayのCanvasの中央にドットを配置しているだけです。


 

ピンを立てる

ピンを立てるためのイメージはこんな感じ

ピンを表示するまでの手順

 

①ユーザーからアクション(クリック)を受け取る

②PinPointを作成する

③PinPointからRayを飛ばして、位置情報や、物に隠れてないかを判断

④ピンの描画

 

※PinPointはUnityの単語ではありません。自分で適当につけた名前です。

  

コード解説

CreatePinPoint

 

CreatePinPointはカメラにアタッチします。クリックした場所からRayを飛ばして衝突検知した場所にPinPointオブジェクトを作成します。(PinPoint自体は透明で、見えるようなものではありません)

 

12行目 pinPoint

ピン情報を保持、発信するプレファブで構成は以下の通りです。

PinPointの設定

 

このPinPointにアタッチされているスクリプトはこちら↓↓↓

 

 PinSystemOverlay

 

簡単に概要を説明するとこのスクリプトがアタッチされたオブジェクトの、位置場所によってUIをCanvas上で移動させたり、障害物があれば非表示にする判定を行います。

 

 

11行目 pinPrefab

Canvas上に表示するピンのイメージプレファブで、OpenPrefabした時の構成は以下の通りです。

Cnavas(Overlay)
└ pinUI
    └ image

pinUIの設定

pinUI-imageの設定項目



上記プレファブのImageコンポーネントにアタッチされている画像はこちらで載せている画像を使ってます。

※ただここは任意で良いので、ピンっぽい画像ならなんでもいいです。

 

 

基本的な流れとして、Canvas上での「pinUI」の位置決定方法は、Start()内の手順で行います。

20行目 ScreenPositionの取得

21行目 Canvas上のlocalPositionを取得

22行目 Canvas上にピンのイメージを配置

 

衝突検知+表示制御+位置決定をLateUpdate()内で行っています。

30行目で障害物検知としてカメラに向かってRayを飛ばして、

カメラに到達しなかったものや、カメラとの間に障害物がある場合は表示されません。

 

次に画面内検知は二重で行っています。

33行目 Vector3.Dotでは、カメラベクトルとPinPointからカメラ方向へのベクトルの内積を取得。視野範囲を決定しています。

この範囲から外れたら、画面外と言うことなのでpinUIは非アクティブにしています。

 

OnBecameVisibleとOnBecameInvisible

最初はカメラフレームへのIn/Out判定に

OnBecameVisibleメソッドOnBecameInvisibleメソッドをセットで使用していました。

OnBecameVisibleメソッドは、オブジェクトがカメラフレームにInしたとき、

OnBecameInvisibleメソッドは、オブジェクトがカメラフレームからOutしたときを検知して動作します。

 

確かに、説明の通りに動いてはいるのですが、検証しているうちにカメラがPinPointの裏側を向いていても反応することが判明しました。

これによってカメラを挟んだPinPointと対角線にもUIが表示される問題があったため、今回の方法になりました。

 

視野範囲のコードはいろんなところで使えそうだし、応用が効きそう!

 

ピンシステムの完成!

 

まとめ

スクリーン座標からCanvasにUIを表示させて、さらにそれを動かし続けるのはまじで苦労しました。

座標を取得・変換する流れはこの通り

WorldPoint取得→ScreenPointに変換→配置したい親のlocalPositionに変換

 

2日間くらい悩んでいたので、Twitterで質問してできたコードです。

協力していただいた方々、どうもありがとうございます。

 

 やっとUnityちゃんを登場させることができました!

以前登場させたのが過去記事なので、8ヶ月ぶりです...笑

その間はshaderやparticleの学習に励んでいたので、表現力は豊かなUnityちゃんをこれからもお届けします!