前提・実現したいこと
unityのcinemachineについて
デビルメイクライのようなカメラワークを作りたい。
ロックオンすることでプレイヤーとターゲットを常に映り込むようにする。
その状態で任意に周囲を回転できる。
発生している問題・エラーメッセージ
1.プレイヤーとターゲットが見切れる、距離が離れすぎる
2.ロックオンを外すとカメラアングルが変わる
試したこと
1.Cinemachine FreeLook Cameraを使用し、ゲームパッドのスティックで回転は可能
その時に見切れと離れすぎが顕著に発生する。
2.ロックオンとオフで別々のvirtual cameraを作成priorityの変更で切り替えを行っている。
ロックオンとオフで別々にカメラの位置が保持されておりカメラが切り替わるとき、一方が反対側にあれば回り込むように移動する。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答1件
0
ベストアンサー
当初はCinemachineTargetGroupとCinemachineGroupComposerを組み合わせるとそれらしい動きになるんじゃないか...と思ったのですが、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
総合スコア10811
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。