Unitytwitterfacebookhatenabookmarklineというわけで、グラボのDisplayPort端子にHDMIケーブルを刺そうと頑張ってしまった今日この頃です。見でHDMIと似ていたので「このグラボ2つHDMIあるじゃん!」とか悟ったのが軽率でした。デュアルディスプレイをすべくHDMI対応のモニタを買ったのにこの有様です。某密林で変換コネクタを注文し試しているところです。...と、どうでもいい前置きを挟んだところで、本日のお題は「3Dカメラ視点移動」です。実は今までのUnity歴で「3D空間を移動・探索する」というゲームをほとんど構築したことがなく、3Dにおけるカメラ移動やロックオンの実装方法はあやふやだったりします。あとがきカメラ移動用オブジェクトの作成3D空間でのカメラ移動と言えば、あるオブジェクトに対して回り込むようにカメラを移動させる必要があるため、メインカメラのGameObjectをそのまま動かすのは面倒です。いうことで、1つ空オブジェクトを作り、その子としてメインカメラを設定します。カメラの位置はゲームや場面に合わせて調整しましょう。あとは親となる移動用オブジェクトをくるくる回せば、子となっているメインカメラも相対的に移動します。当然ながら、作成した空オブジェクトは「視点移動のベースとなるオブジェクト」の位置に移動させる必要があります。プレイヤーキャラクターが基点になるので、今回もそれに合わせてみます。}}ここまでは何も難しいことはないですね。先程のカメラ移動用オブジェクトに対して回転を掛けます。「難しいこと考えずにカメラ移動用オブジェクトを回すだけでしょ?」とTransform.Rotateを使いましたが、見事に軸がブレで上手くいきませんでした。angle.y);}うわ、便利!最近できた関数かと思いきや、かなり前からあるようです。無知は罪であると思う。本記事の内容にTransform.RotateAround()は不適切だったので、transform.eulerAnglesに加減算する形に修正しました。以下のような感じです。angle.x);}あとはこれを呼び出す記述をUpdate()内に追加すれば、最低限のものはできます。視点移動の制限このままの場合、左右は問題ありませんが、上下に移動させた際に視点が1回転してしまいます。3Dゲームの多くは上下に対する角度制限がある印象なので、それに習ってみます。ここで面倒になるのは下方向に向けた場合で、X軸の角度的には0→360度になるため、Transform.eulerAnglesの値そのままで制限するのは厳しいです。X軸だけちょっと細工を入れます。);}三項演算子で「Transform.eulerAngles.xが180度以上であれば360度減算する」処理を入れます。超ダイレクトな方法ですが、これでX軸の角度が-180~180度の間になり、Mathf.Clamp()での制限が容易になります。ついでにカメラ視点移動を「マウス右クリック中」のみにしてみました。定数ROTATE_BUTTONで1を指定しておき、Update()内のrotateCmaeraAngle()呼び出し前にifで判定します。今日の3Dゲームでは必ずと言っていいほど備わっている「ロックオン」機能です。深く考えると「ロックオン可能な距離」や「複数のロックオン対象がいる場合の選別」などあれこれあるので、シンプルに「特定の判定に入った敵をロックオン」だけ考えてみます。下準備として、ロックオン対象を検知するためのオブジェクトを作成し、プレイヤーキャラクターの子オブジェクトとして設定します。検知用オブジェクトにはShpereColliderを設定し、IsTriggerにチェックを入れておきます。合わせて以下のスクリプトを作成し、こちらも設定します。}}SphereColliderに入った敵を取っておくだけのスクリプトです。1オブジェクトしか保持しないため、敵が単体ならまだしも、複数入ってくると使い物になりません。上にも書きましたが深く考えるとややこしいので、こんなものでいいでしょう。CameraControllerクラスを修正します。Vector3.up);}先述の視点移動制限があるため、至近距離でジャンプしてもそこそこ見やすい角度に収まります。視点のリセットせっかくなので視点をリセットする機能も付けます。深いことは考えずにプレイヤーキャラクターのtransform.rotation.yに合わせて移動用オブジェクトに回転をかけましょう。リセット用のキーはロックオンと同じ「R」でいきます。}}単に値を設定するだけでは瞬時に回転して味気ないので、iTween.RotateTo()を使用して徐々に変化するようにします。ハッシュのrotationにはtransform.eulerAnglesを指定しましょう。ちなみにtransform.forwardをiTween.ValueTo()やDOTween.To()等でプレイヤーの値に合わせることでも実現できますが、現在の向きと真反対を向いた際にイージングが上手くいかないので見送りました。あとがきそんなわけで、今更3Dカメラの動かし方についておさらいしてみました!あっさりできそうで意外と苦戦する部分が多かったです。今後が不安になるため、Unityユーザー間では常識っぽい処理も定期的に取り上げて書いていこうかと思います。現在開発中(?)のゲームは3Dっぽい2Dですが、今になって「3Dもいいなー」なんて思い始めたりしています。CharacterMotorを強引に2D向けに使用している上、そのCharacterMotor自体が古いスクリプトというのもあり、このまま開発するのは無理があるかもしれません。一応2Dっぽい動きにはなっている上、場面によって3D移動ができるようにもしたので、限界が来るまで粘りつつ、次の手を模索してみます。シェアするtwitterfacebookhatenabookmarklineコメントこんにちは、通りすがりで失礼します。Transform.Rotateで軸がブレたとのことですが、y軸回転させると斜めになっちゃう感じですかね?だとすると、Rotateメソッドの引数でSpace.Worldを指定すると、ワールド空間での回転になるので、たぶん期待する回転になると思います。デフォルトだとローカル空間です。PMmotoyamaさんコメントありがとうございます。Transform.Rotateで軸がブレたとのことですが、y軸回転させると斜めになっちゃう感じですかね?X軸とY軸を同時に回転させた際にZ軸まで回転し、傾いた視点になってしまいます。すると、Rotateメソッドの引数でSpace.Worldを指定すると、ワールド空間での回転になるので、たぶん期待する回転になると思います。指定が可能なことは知っていたのでWorldでの指定も試みましたが、改善しませんでした。Transform.RotateAround()は指定した点を中心に回転させる機能なので、用途が違うかなと仰る通り、本投稿のやり方にRotateAround()は不適当かと思います。してもRotate()での実現ができなかったため、違和感を抱きつつも使用しております。素直にtransform.eulerAnglesに回転量を加算するのが確実な気がしてきたので、その方向で考え直してみます。AMchiteさんご指摘ありがとうございます。確かに稀に逆さまになってしまいますね...。根本解決にはなりませんが、処理を`FixedUpdate()`内で行うように変えると少しはマシになるかもしれません。手元で軽く試した感じでは簡単に解決できそうにないので、対策を思いついたら追記します。PM記事のスクリプトでは「回転実行後に制限に合わせて角度を補正する」形になっていますが、これを「回転実行前に回転角度を制限内に収まる値に補正する」形に直すとどうでしょうか?具体的には`rotateCmaeraAngle()`を以下のように修正します。ツイートこのブログを書いている人りべるんアザラシが大好きな山梨県産Webエンジニア。2019年3月よりフリーランスSEとして東京で活動中。