質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Q&A

解決済

1回答

2710閲覧

unityのcinemachineでデビルメイクライを再現したい

mekacon

総合スコア1

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

0グッド

0クリップ

投稿2020/08/22 15:07

前提・実現したいこと

unityのcinemachineについて
デビルメイクライのようなカメラワークを作りたい。
ロックオンすることでプレイヤーとターゲットを常に映り込むようにする。
その状態で任意に周囲を回転できる。

発生している問題・エラーメッセージ

1.プレイヤーとターゲットが見切れる、距離が離れすぎる
2.ロックオンを外すとカメラアングルが変わる

試したこと

1.Cinemachine FreeLook Cameraを使用し、ゲームパッドのスティックで回転は可能
その時に見切れと離れすぎが顕著に発生する。

2.ロックオンとオフで別々のvirtual cameraを作成priorityの変更で切り替えを行っている。
ロックオンとオフで別々にカメラの位置が保持されておりカメラが切り替わるとき、一方が反対側にあれば回り込むように移動する。
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

当初はCinemachineTargetGroupCinemachineGroupComposerを組み合わせるとそれらしい動きになるんじゃないか...と思ったのですが、CinemacineFreeLookと併用するとなんだか挙動が不安定で思い通りにいかず、方針を変えて「プレイヤーとロックオンターゲットの中間地点にオブジェクトを配置し、CinemacineFreeLookはそれを注目させ、軌道の半径はプレイヤーとターゲットの距離に比例させる」といった方法でできないか試してみました。

下記のようなスクリプトを作成し...

C#

1using System.Linq; 2using Cinemachine; 3using UnityEngine; 4 5public class TargetSelector : MonoBehaviour 6{ 7 // 今回の実験では、さしあたりボタン入力でロックオン・ロック解除を行うことにした 8 [SerializeField] private string targetingKey; 9 [SerializeField] private string untargetingKey; 10 11 // このタグを持つオブジェクトをロックオン候補とすることにした 12 [SerializeField] private string targetCandidateTag = "Enemy"; 13 14 // ロックしているターゲットに照準を重ねて表示することにする 15 [SerializeField] private Transform reticle; 16 17 // FreeLookカメラをここにセットしておく 18 [SerializeField] private CinemachineFreeLook freeLook; 19 20 // 注目点の移動のスムージング時間 21 [SerializeField][Range(0.0f, 2.0f)] private float focusSmoothTime = 0.5f; 22 23 // カメラの軌道サイズ変更のスムージング時間 24 [SerializeField][Range(0.0f, 2.0f)] private float orbitSmoothTime = 0.5f; 25 26 private readonly float[] orbitBaseHeights = new float[3]; 27 private readonly float[] orbitBaseRadii = new float[3]; 28 private float orbitScale; 29 private float orbitVelocity; 30 private Transform focus; 31 private Vector3 focusPosition; 32 private Vector3 focusVelocity; 33 private Transform currentTarget; 34 35 private void Start() 36 { 37 // カメラの注目点を作成し、freeLookにはそれを注目させる 38 var focusObject = new GameObject("Focus"); 39 this.focus = focusObject.transform; 40 this.focusPosition = this.transform.position; 41 this.focus.position = this.focusPosition; 42 this.freeLook.Follow = this.focus; 43 this.freeLook.LookAt = this.focus; 44 45 // 基準となるfreeLookの軌道サイズを覚えておく 46 this.orbitScale = 1.0f; 47 for (var i = 0; i < 3; i++) 48 { 49 var orbit = this.freeLook.m_Orbits[i]; 50 this.orbitBaseHeights[i] = orbit.m_Height; 51 this.orbitBaseRadii[i] = orbit.m_Radius; 52 } 53 } 54 55 private void Target() 56 { 57 // currentTargetにターゲットをセットすることでロックオンを表現する 58 // 今回の実験では、さしあたりプレイヤーと一番近いターゲット候補を選択してロックオンする 59 // 併せて、ロック中であることを示すため照準を表示する 60 var nearestTarget = GameObject.FindGameObjectsWithTag(this.targetCandidateTag) 61 .Where(c => c.transform != null) 62 .Select(c => (c.transform, Vector3.Distance(c.transform.position, this.transform.position))) 63 .OrderBy(cp => cp.Item2) 64 .Select(cp => cp.Item1) 65 .FirstOrDefault(); 66 this.currentTarget = nearestTarget; 67 this.reticle.gameObject.SetActive(true); 68 } 69 70 private void Untarget() 71 { 72 // currentTargetをnullにして照準を非アクティブにすることでロック解除 73 this.currentTarget = null; 74 this.reticle.gameObject.SetActive(false); 75 } 76 77 private void Update() 78 { 79 if (Input.GetButtonDown(this.targetingKey)) 80 { 81 this.Target(); 82 } 83 84 if ((this.currentTarget == null) || Input.GetButtonDown(this.untargetingKey)) 85 { 86 this.Untarget(); 87 } 88 89 this.UpdateFocus(); 90 this.UpdateOrbits(); 91 if (this.currentTarget != null) 92 { 93 this.reticle.position = this.currentTarget.position; 94 } 95 } 96 97 private void UpdateFocus() 98 { 99 // ロックオン状態の場合、注目点はプレイヤーとターゲットの中間点に向かって移動させる 100 this.focusPosition = this.transform.position; 101 if (this.currentTarget != null) 102 { 103 this.focusPosition = Vector3.Lerp(this.focusPosition, this.currentTarget.position, 0.5f); 104 } 105 106 this.focus.position = Vector3.SmoothDamp( 107 this.focus.position, 108 this.focusPosition, 109 ref this.focusVelocity, 110 this.focusSmoothTime); 111 } 112 113 private void UpdateOrbits() 114 { 115 // 軌道サイズの大ざっぱな見積もりとしてプレイヤーとfocusの距離を使う 116 // ただし、初期ボトムリグ半径を下回らないようにする 117 var bottomRadius = Mathf.Max( 118 this.orbitBaseRadii[2], 119 Vector3.Distance(this.transform.position, this.focus.position)); 120 this.orbitScale = Mathf.SmoothDamp( 121 this.orbitScale, 122 bottomRadius / this.orbitBaseRadii[2], 123 ref this.orbitVelocity, 124 this.orbitSmoothTime); 125 126 // 軌道サイズを調節する 127 for (var i = 0; i < 3; i++) 128 { 129 this.freeLook.m_Orbits[i].m_Height = this.orbitScale * this.orbitBaseHeights[i]; 130 this.freeLook.m_Orbits[i].m_Radius = this.orbitScale * this.orbitBaseRadii[i]; 131 } 132 } 133 134 private void OnDisable() 135 { 136 // プレイモード終了時に軌道設定がそのまま残ってしまうのを防止するため 137 // オブジェクトが無効化されたタイミングで軌道サイズを元に戻しておく 138 for (var i = 0; i < 3; i++) 139 { 140 this.freeLook.m_Orbits[i].m_Height = this.orbitBaseHeights[i]; 141 this.freeLook.m_Orbits[i].m_Radius = this.orbitBaseRadii[i]; 142 } 143 } 144}

それをプレイヤーにアタッチして、インスペクター上でそれぞれのフィールドをセットして実行したところ下図のような動きになりました。

図

今回のコードでは、コード中のコメントで申し上げたように大ざっぱにカメラリグの大きさを調節しているだけなので、見切れを完全に防止することはできませんでした。ですがおおむね適切なスケールで表示されるんじゃないかと思います。

それと今さらですが、あいにくデビルメイクライをプレイしたことがなく、実際のゲームの操作感がどのようなものなのかわかりません。もし「このような挙動を再現したい」といった点がありましたら、参考になりそうな動画などありましたらご提示いただければ、可能であれば修正してみようと思います。

投稿2020/08/23 13:31

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問