今回は戦闘中のカメラワークを作成したいと思います。
前回は戦闘中の攻撃を受けた時のダメージテキストにアニメーションをさせて表示する機能を作成しました。
ユニティちゃんのRPGを作ってみようの他の記事は
から見ることが出来ます。
今回は戦闘シーンで攻撃をする側、される側のキャラクターをカメラがフォーカスして映し出してわかりやすくしてみます。
ただ、今回作成した機能だとカメラが接写していてヌルーっと動くため、ちょっと3D酔いします・・・(^_^;)
キャラクターを全部を写すカメラ、攻撃時のカメラ、攻撃される側のカメラなど複数のカメラを作って切り替えたり、
そもそもカメラワーク機能を取り付けず今まで通り全体像を写すカメラ一つのまま動かさないというのでもいいかもしれません。
カメラワークの作成
それではカメラワーク機能を作成していきましょう。
今回はCinemachineの仮想カメラを使って機能を作成していきます。
Cinemachineについては
を参照してください。
Cinemachineがインストールされていない場合はPackage Manager等を使ってCinemachineをインストールしてください。
仮想カメラはMain Cameraの位置や角度等を操作するもので、名前の通りカメラ機能自体を持っているわけではありません。
設定等は全て仮想カメラ等のCinemachineの機能から出来、Main CameraにはCinemachinBrainコンポーネントが取り付けられ、仮想カメラの設定で管理されるようになります。
キャラクターの初期位置を変更する
今回のカメラワークの機能を取り付けるとキャラクターがうまく見えないという状況になるので、BattleシーンのヒエラルキーのBattleBasePositionの子要素の位置を変更します。
AllyPos0のTransformのPositionのXを3.5
AllyPos1のTransformのPositionのXを4
AllyPos2のTransformのPositionのXを4.5
AllyPos3のTransformのPositionのXを5
EnemyPos0のTransformのPositionのXを-3.5
EnemyPos1のTransformのPositionのXを-4
EnemyPos2のTransformのPositionのXを-4.5
EnemyPos0のTransformのPositionのXを-5
としました。
設定値は任意です。
上のような感じにしました。
Cinemachineの仮想カメラの作成とカメラターゲットの作成
まずはCinemachine関連のオブジェクトを入れておく空のゲームオブジェクトを作成します。
ヒエラルキー上で右クリックからCreate Emptyを選択し、名前をVirtualCameraとします。
VirtualCameraゲームオブジェクトのTransformのPositionとRotationのXYZは全て0にします。
UnityメニューのCinemachine→Create Virtual Cameraを選択し、作成されたCM vcam1をVirtualCameraゲームオブジェクトの子要素にドラッグ&ドロップします。
ヒエラルキー上に既に仮想カメラを作成している場合はCM vcam2やCM Vcam3等と最後の数値が増えていきます。
仮想カメラを作成するとMain CameraにCinemachine Brainコンポーネントが自動で取り付けられます。
CM vcam1の設定は後でやります。
次にVirtualCameraゲームオブジェクトを選択した状態で右クリックからCreate Emptyを選択し、名前をCameraTargetとします。
TransformのPosition、RotationのXYZを全て0にします。
TransformのPositionの位置は任意です。
CameraTargetは仮想カメラCM vcam1が映すターゲットに使用する空のゲームオブジェクトでCameraTargetを移動させる事でカメラが自動でキャラクター等を写すようにします。
仮想カメラCM vcam1の設定
先ほど作成した仮想カメラCM vcam1を選択し、インスペクタの設定をします。
TransformのPositionのXを0、Yを4、Zを-10とします。
RotationはLookAtに見る対象を設定することで直接変更する事は出来ません。
LookAtには先ほど作成したCameraTargetを設定します。
Field Of ViewにはMain Cameraと同じ60を設定し、Near Clip Planeに0.1を設定します。
AimをComposerにして、Lookahead Timeを0、Lookahead Smoothingを10とします。
Horizontal DampingとVeritical Dampingを1にして、移動スピードの減衰値を設定します。
カメラが映す向きを変える時にパッと変えたい場合はAimの設定をComposerからHard Look Atに変更してください。
ここまでのVirtualCameraの階層は以下のようになります。
戦闘用キャラクターにカメラが映すポイントとダメージ表示ポイントを作成する
今回カメラワーク機能を取り付けるのでそのキャラクターのどのポイントを映すか?という位置を表す空のゲームオブジェクトを作成します。
またダメージポイントの表示位置もキャラクターの位置ではなくキャラクターの子要素に作成してそこに表示するようにします。
Assets/RPG/Prefabs/Characters/Ally/BattleUnityChanを選択した状態で右クリックからCreate Emptyを選択し、名前をCameraShootingPointとします。
CameraShootingPointはカメラが映すポイントに移動させます。
ユニティちゃんのお腹辺りにCameraShootingPointを移動させました。
次はダメージポイントを表示する位置を作成します。
同じようにCreate Emptyで空のゲームオブジェクトを作成し名前をDamageDisplayPointとします。
同じようにダメージポイントを表示したい位置に移動させます。
ダメージテキストを表示しているEffectNumericalDisplayScriptスクリプトを修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public void InstantiatePointText(NumberType numberType, Transform target, int point) { var cameraShootingPoint = target.Find("DamageDisplayPoint"); var rot = Quaternion.LookRotation(target.position - Camera.main.transform.position); if (numberType == NumberType.Damage) { var pointTextIns = Instantiate<GameObject>(damagePointText, cameraShootingPoint.position + offset, rot); pointTextIns.GetComponent<TextMeshPro>().text = point.ToString(); Destroy(pointTextIns, 3f); } else if (numberType == NumberType.Healing) { var pointTextIns = Instantiate<GameObject>(healingPointText, cameraShootingPoint.position + offset, rot); pointTextIns.GetComponent<TextMeshPro>().text = point.ToString(); Destroy(pointTextIns, 3f); } } |
引数で受け取ったtargetの位置にそのまま表示していましたが、targetの子要素のDamageDisplayPointゲームオブジェクトを探し、その位置にダメージテキストを表示するようにします。
以下の戦闘用キャラクターにも同じように作成してください。
Assets/RPG/Prefabs/Characters/Ally/BattleYuji
Assets/RPG/Prefabs/Characters/Enemy/ElfPrefab
Assets/RPG/Prefabs/Characters/Enemy/GloblinPrefab
Assets/RPG/Prefabs/Characters/Enemy/GoblinWarriorPrefab
カメラの動きを管理するBattleCameraManagerスクリプトの作成
次にAssets/RPG/Scripts/Battleフォルダに新しくBattleCameraManagerスクリプトを作成し、CM vcam1ゲームオブジェクトに取り付けます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class BattleCameraManager : MonoBehaviour { // カメラのターゲット [SerializeField] private Transform cameraTarget; // カメラのターゲットの初期位置 private Vector3 initCameraTargetPosition; // カメラの初期位置 private Vector3 initCameraPosition; // カメラがキャラクターを移した時の位置 private Vector3 close_UpCharacterPosition; // カメラのオフセット位置 [SerializeField] private Vector3 offset = new Vector3(0f, -1f, 9f); // Start is called before the first frame update void Start() { initCameraTargetPosition = cameraTarget.position; initCameraPosition = transform.position; // キャラクターに接写した時のカメラ位置を設定 close_UpCharacterPosition = transform.position + offset; } // ターゲットのキャラクターを接写 public void Close_UpCharacter(GameObject target) { var cameraShootingPoint = target.transform.Find("CameraShootingPoint"); cameraTarget.position = cameraShootingPoint.position; transform.position = close_UpCharacterPosition; } // 初期位置に戻す public void SetInitPosition() { cameraTarget.position = initCameraTargetPosition; transform.position = initCameraPosition; } } |
cameraTargetはCameraTargetゲームオブジェクトをインスペクタで設定します。
initCameraTargetPositionはCameraTargetの初期位置を設定します。
initCameraPositionはカメラ自体の初期位置を設定します。
close_UpCharacterPositionはカメラがキャラクターを写した時に移動させる位置を設定します。
offsetはカメラ位置のオフセット値で、カメラがキャラクターを写した時のに移動させる位置を作成する時に使います。
Startメソッドではカメラターゲット、カメラの初期位置を設定し、カメラの初期位置とoffset値からカメラがキャラクターを接写した時のカメラ位置を設定しています。
Close_UpCharacterメソッドは引数で受け取ったターゲットからCameraShootingPointを探し、その位置にcameraTargetを移動し、カメラ位置をclose_UPCharacterPositionに移します。
CM vcam1のLookAtにはCameraTargetが設定されているので、CameraTargetの位置を引数で受け取ったターゲットの位置にする事で、仮想カメラがそちらの方向を向くようになります。
SetInitPositionメソッドはキャラクターの接写をやめて全体図を写す時に呼び出し、カメラターゲットとカメラ位置を初期位置に戻します。
カメラ操作メソッドの呼び出し処理を追加する
カメラ操作はBattleCameraManagerスクリプトで行えるようになりました。
後はキャラクターの攻撃のタイミング等でその機能を呼び出してカメラを操作するだけです。
BattleManagerスクリプトに処理を追加
BattleManagerスクリプトに処理を追加します。
まずはフィールドにbattleCameraManagerを追加し、インスペクタで設定出来るようにします。
1 2 3 4 5 | // 戦闘シーンのカメラ管理スクリプト [SerializeField] private BattleCameraManager battleCameraManager; |
MakeAttackChoiseメソッドの最初にBattleCameraManagerスクリプトのSetDefaultPositionメソッドを呼び出します。
キャラクターがコマンドを選択している時はカメラやターゲットを初期位置にします。
1 2 3 4 5 6 | // キャラクターの攻撃の選択処理 public void MakeAttackChoise(GameObject character) { // カメラターゲットを移動 battleCameraManager.SetInitPosition(); |
CharacterBattleScriptに処理を追加
CharacterBattleScriptに処理を追加します。
battleCameraManagerフィールドの追加とStartメソッドでBattleCameraManagerスクリプトの取得を行います。
1 2 3 4 5 6 7 | // 戦闘シーン用のカメラ管理スクリプト private BattleCameraManager battleCameraManager; private void Start() { battleCameraManager = FindObjectOfType<BattleCameraManager>(); |
BattleCameraManagerスクリプトはシーン上に一つだけなのでFindObjectOfTypeで取得しています。
次にUpdateメソッドでキャラクターが攻撃等の対象に対しての行動を起こす時にBattleCameraManagerスクリプトのClose_UpCharacterメソッドを呼び出し、現在のターゲットを接写します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | void Update() { // 既に死んでいたら何もしない if (isDead) { return; } // 自分のターンでなければ何もしない if (battleState == BattleState.Idle) { return; } // アニメーションが終わっていなければ何もしない if (!isDoneAnimation) { return; } // 現在のターゲットを接写する battleCameraManager.Close_UpCharacter(currentTarget); |
ChooseAttackOptionsメソッドの最初でBattleCameraManagerスクリプトのClose_UpCharacterメソッドを呼び出し自身のキャラクターを接写するようにします。
1 2 3 4 5 6 | // 選択肢から選んだモードを実行 public void ChooseAttackOptions(BattleState selectOption, GameObject target, Skill skill = null, Item item = null) { battleCameraManager.Close_UpCharacter(this.gameObject); |
Guardメソッドは敵が防御をした時に呼び出されますが、そこでも同じようにBattleCameraManagerスクリプトのClose_UpCharacterメソッドを呼び出します。
1 2 3 4 5 | // 防御 public void Guard() { battleCameraManager.Close_UpCharacter(this.gameObject); |
これで機能が出来上がりました。
実際に動かして確認してみましょう。
上のようになりました。
終わりに
3DのRPGだとカメラワークをどうするか悩みますね、戦闘に参加しているメンバーをうまく映さなければいけませんし、カメラの動きによっては3D酔いしますし・・・・。
カメラを動かすよりカメラは常に全体を映しておいて、キャラクターが敵に近づいて攻撃をするというような作りにするのもいいかもしれません。
この作品はユニティちゃんライセンス条項の元に提供されています