徳島ゲーム開発ごっこ 技術ブログ

ゲームを作るために役に立ったり立たなかったりする技術を学んでいきます!

【Unity】StandardAssetsのCameras使用メモ

 プレイヤーが操作するオブジェクトの移動に合わせてカメラも動かしたい! 
 そんな状況あるよね(テレビショッピング風に)。
 ただ、カメラの挙動は奥が深いです。いろんなことを考えなくてはなりません。

 そんな奥深くなくていいから、パパっとカメラの挙動が作りたい。
 1週間ゲームジャムに参加したいけど、時間がないためカメラの挙動にそんな時間を割くことができない。
 そんなあなたにStandardAssets
 プロジェクトに組み込むだけで、カメラの挙動が簡単に作れちゃうぞ。
 今らなら税込み198……、いや無料か。

 というわけで今回はStandardAssetsCameraのアセットについてメモ書きでござい。
f:id:urahimono:20170603135422p:plain


この記事にはUnity5.6.1f1を使用しています。

はじめに

 早速カメラのStandardAssetsを組み込んでみましょう。
 メニューバーのAssetsからCamerasのPackageをインポートしちゃうぞ。

f:id:urahimono:20170603135328p:plain 

 Standard Assetsのカメラの種類は4種類あるようですね。

f:id:urahimono:20170603135422p:plain

  • CctvCamera
  • FreeLookCameraRig
  • HandheldCamera
  • MultipurposeCameraRig

 うーん、Prefab名だけではどんなカメラなのかよくわからないや。
 1つずつ見ていきましょうか。

CctvCamera

f:id:urahimono:20170603135543g:plain

 CctvCameraを使ってみました。
 まず、カメラの位置は動かない。
 そして、X軸・Y軸の回転で指定したターゲットに向くようにしているみたいですね。

f:id:urahimono:20170603135644p:plain

 Prefabの作りは階層がないシンプルな作り。
 以下のコンポーネントがアタッチされていました。

  • LookatTarget
  • TargetFieldOfView

AbstractTargetFollower

f:id:urahimono:20170603135657p:plain

 Prefabにアタッチされているコンポーネントとは違いますが、カメラ制御のコンポーネントにおいて、AbstractTargetFollowerは重要です。
 今回使用するカメラ制御用コンポーネントは、大体がこのクラスを継承しているようです。
 そのため、このクラスにあるプロパティはカメラ共通のプロパティになります。

プロパティ一覧

  • Target : Transform
     カメラの向きや移動する目標。
  • AutoTargetPlayer : bool
     有効にすることでPlayer*のついたTransformを上記のTarget**に自動で設定する。
  • UpdateType : UpdateType
     カメラの更新タイミング。

 Targetに指定するTransformは、スクリプト上でもSetTarget()Targetプロパティを使うことで取得・設定が可能みたいですね。
 AutoTargetPlayertrueにすることで、Targetnullの場合に、タグがPlayerのものをHierarchy上から検索し自動で設定してくれるようです。
 複数Playerがあった場合は、どれになるかしらないけど……。

f:id:urahimono:20170603135714p:plain

 UpdateTypeに指定できるタイプには以下の種類があるみたいです。

  • FixedUpdate
     FixedUpdate()で更新される。
  • LateUpdate
     LateUpdate()で更新される。
  • ManualUpdate
     自動では更新されなくなり、他のスクリプトからManualUpdate()を呼ぶことで更新されるようになる。

LookatTarget

f:id:urahimono:20170603135728p:plain

プロパティ一覧

  • RotationRange : Vector2
     X軸、Y軸のカメラの向く最大角度。
  • FollowSpeed : float
     ターゲットの方を向くまでの速度を指定する。

 RotationRangeにはX軸、Y軸のカメラの向く最大角度を指定できるみたいです。
 気を付けたいのは、設定した角度の半分ずつをプラスマイナスで使用するということ。
 例としては、70を設定した場合、初期のカメラ向きの-35度から+35度まで回転可能になります。
 360を超えて指定する場合は、回転に制限がなくなりますよー。

 FollowSpeedにはターゲットの方を向くまでの速度を指定するみたいです。
 ただ、Follow**Speed**という名前ではあるが、スクリプト上ではVector3.SmoothDamp()の第4引数として使用されるため、実際に使用される単位としては時間だったりします。
 そのため、設定する数値が小さければ小さいほど早くターゲットの方を向くのです。

設定する際の注意

 Start()にて初期のカメラの回転情報を保存しておき、ターゲットへの回転を掛け合わせることでカメラの回転を更新していく形のようです。
 そのため、初期状態のカメラの回転状態はとっても重要。

LookatTarget.cs

protected override void Start()
{
    base.Start();
    m_OriginalRotation = transform.localRotation;
}

 基本LookatTargetはX軸とY軸の回転しか用いないのだけど、初期状態でX軸に回転している状態だと計算の過程でZ軸まで回転してしまう可能性がでてきます。

f:id:urahimono:20170603135802p:plain
f:id:urahimono:20170603135815g:plain
f:id:urahimono:20170603135841p:plain

 ああー……、傾いてしまった。

TargetFieldOfView

 カメラのFieldOfViewを制御して、ズームを表現してくれるみたいです。
 ちなみにデフォルトではCctvCameraではデフォルトはdisableになってますよ。

f:id:urahimono:20170603135857g:plain

f:id:urahimono:20170603140024p:plain

プロパティ一覧

  • FovAdjustTime : float
     ターゲットにズームするまでの時間。
  • ZoomAmountMultiplier : float
     ズーム乗算値。
  • IncludeEffectsInSize : bool
     未使用。

 ZoomAmountMultiplierにはズーム乗算値(?)を指定するみたいです。
 設定する数値が小さければ小さいほど目標が大きく表示されます。
 IncludeEffectsInSizeはスクリプトを見る限り使われていないきがするんだけど……。

設定する際の注意

 ターゲットへのズームの計算には、ターゲットのGameObjectにあるRendererBoundsを利用して必要な大きさを計算しているようです。
 子のRendererBoundsも計算に含まれます。
 ただし、TrailRendererParticleSystemRendererは計算に含まれないので、その手のオブジェクトでは正しくズームされません。
 当然、Rendererのないターゲットには正しく動作しないことに注意が必要です。

f:id:urahimono:20170603140039g:plain

 どんどん近づいて行ってしまっています。

HandheldCamera

f:id:urahimono:20170603140144g:plain

 基本的な挙動はCctvCamera同じみたいですね。
 それに手ぶれが追加された感じです。

f:id:urahimono:20170603140233p:plain

 Prefabの作りはCctvCamera同様に階層がないシンプルな作り。
 以下のコンポーネントがアタッチされていました。

  • HandHeldCam
  • TargetFieldOfView

HandHeldCam

f:id:urahimono:20170603140247p:plain

 HandHeldCamLookatTargetを継承しているため、同じパラメータが存在します。

プロパティ一覧

  • SwaySpeed : float
     ランダム速度
  • BaseSwayAmount : float
     カメラ位置に対するブレの量。
  • TrackingSwayAmount : float
     ターゲット位置に対するブレの量。

 手ぶれのランダム性はMathf.PerlinNoise()を使って表現しているようです。
 次のPerlinNoiseのY地点に進む速度をSwaySpeedにて指定しているのかな。
 パーリンノイズについては、僕がまだまだ勉強不足なので割愛しますね。
 

設定する際の注意

 基本的にな挙動はLookatTargetを継承しているので、注意点もLookatTargetと同じかな。

FreeLookCameraRig

f:id:urahimono:20170603140532g:plain

 ターゲットに向かって移動して近づいていきます。
 マウスの位置に合わせて上下左右にカメラが向く機能がついていますね。

f:id:urahimono:20170603141148p:plain

 Prefabの作りは3つの階層の構成になっています。
 Rig - Pivot - Camera
 以下のコンポーネントがアタッチされていました。

  • FreeLookCam
  • ProtectCameraFromWallClip

FreeLookCam

f:id:urahimono:20170603141200p:plain

プロパティ一覧

  • MoveSpeed : float
     ターゲットに向かって移動する速度。
  • TurnSpeed : float
     カメラの回転速度
  • TurnSmoothing : float
     カメラの回転の補間速度。
  • TiltMax : float
     カメラのX軸の最大角度。
  • TiltMin : float
     カメラのX軸の最小角度。
  • LockCursor : bool
     カーソルを非表示にするかどうか。
  • VerticalAutoReturn : bool
     有効にすると自動でカメラのX軸回転を0に戻るようになる。

 MoveSpeedはスピードとは名ばかりでVector3.Lerp()の割合で使用されています。スピードじゃないです。
 TurnSmoothing0.0f指定すると補間されなくなります。ちなみに指定した数値はQuaternion.Slerp()で使用されますよ。
 TiltMinに指定した数値は、スクリプト上でマイナス値を掛けて使用されています。そのためエディタ上でマイナス値で設定すると大変なことになっちゃいます。
 VerticalAutoReturnを有効にした場合、TurnSmoothingに値を指定しておかないと、X軸回転が毎フレーム0になるのでたいへんなことになりました。

f:id:urahimono:20170603141225g:plain

 すげぇグラグラする。

設定する際の注意

 Prefabの各GameObjectの担当として、
 RigGameObjectがターゲットの位置に向かって移動していきます
 最終的にRigはターゲットとほぼ同じ位置になるはずです。
 そのままではカメラがターゲットにめり込んでしまいます。
 そこで子GameObjectであるPivotの位置を調整することでターゲットを映すのに最適な位置にする形で使用するみたいです。
 ちなみに、その子GameObjectであるCameraの位置は、後述のProtectCameraFromWallClipが固定してしまうため、あんまり位置調整には適さないみたいですね。

 カメラの向きの回転については、各GameObjectで担当が決まっているみたいです。
 Y軸回転はRigが、X軸回転はPivotGameObjectが担当しているようです。
 初期状態で担当している軸以外を回転しているとあんまりいいことはなさそうですねー。

 カメラの向きの操作更新はUpdate()で更新されており、UpdateTypeの指定は関係なかったりします。
 そのため、ManualUpdateを指定したところで、容赦なく勝手に更新されたりします。

 カメラの向きの操作の入力は、CrossPlatformInputManagerが使われているみたいですね。
 CrossPlatformInputについては昔に少しだけ調べたような気がするけど。
 
www.urablog.xyz

 ただ、カーソルのOnOffはInput.GetMouseButtonUp()を使用しています。
 うーん、統一感……。

ProtectCameraFromWallClip

 壁を素早くすり抜けるためのコンポーネントみたいですね。
 ここでいう壁とは、Colliderがあり、Rigidbodyがないオブジェクトのことを指すみたいです。
 Prefab構成一番下のCameraがついているGameObjectの位置を制御してすり抜け処理を行っているようです。
 初期のCameraの位置がデフォルトの位置扱いになるので重要になります。

f:id:urahimono:20170603141827g:plain

 ギュインと抜けます。ギュインと。

f:id:urahimono:20170603141915p:plain

プロパティ一覧

  • ClipMoveTime : float
     壁を検知した際に、壁の位置まで移動する時間。
  • ReturnTime : float
     壁をすり抜けた後に、デフォルトに位置まで戻る時間。
  • SphereCastRadius : float
     壁を検知する範囲。
  • VisualiseInEditor : bool
     壁を検知した際に、エディターのSceneビューに壁までのレイを表示するかのフラグ。
  • ClosestDistance : float
     壁を検知して、最も壁に近づいた際に、近づける最小距離。
  • DontClipTag : string
     壁と検知しないオブジェクトのタグ。

MultipurposeCameraRig

f:id:urahimono:20170603141926g:plain

 ターゲットに向かってカメラが移動します。
 カメラの向きはターゲットの進行方向に向くように回転してくれます。
 ターゲットの進行方向はTransform.forwardを使用するけど、設定しだいでRigidbody.velocityを使用することもできるみたいです。

f:id:urahimono:20170603142109p:plain

 Prefabの作りは3つの階層の構成になっています。
 Rig - Pivot - Camera
 以下のコンポーネントがアタッチされていました。

  • AutoCam
  • ProtectCameraFromWallClip

AutoCam

プロパティ一覧

  • MoveSpeed : float
     ターゲットに向かって移動する速度。
  • TurnSpeed : float
     カメラの回転速度。
  • RollSpeed : float
     Upベクトルの回転速度。Z軸の回転に対する速さかな。
  • FollowVelocity : bool
     有効にすれば、ターゲットの進行方向としてRigidbody.velocityを使用することが出来る。
  • FollowTilt : bool
     ターゲットのX軸の回転に対して、カメラの向きも対応するかのフラグ。
  • SpinTurnLimit : float
     回転量のリミット
  • TargetVelocityLowerLimit : float
     m_FollowVelocityが有効の場合、この値以上のRigidbody.velocityの場合にRigidbody.velocityが進行方向として有効となる。
  • SmoothTurnTime : float
     回転量の補間速度。

 やっぱりMoveSpeedはスピードとは名ばかりでVector3.Lerp()の割合で使用されています
 そしてRollSpeedもスピードとは名ばかりでVector3.Slerp()の割合で使用されています。

設定する際の注意

 m_FollowVelocityを有効にすることでRigidbody.velocityを進行方向の判定として利用することができます。
 ただし、使用されるRigidbodyには、継承元クラスであるAbstractTargetFollowertargetRigidbodyが使用されます。
 しかし、targetRigidbodyStart()の時点でしか設定されなかったりします。
 これはバグだろうか……。
 そのため、ランタイム中にターゲットを変更する場合などには、ターゲットのRigidbodyが使われません。
 ちなみに1週間ゲームジャムで使用した際は、以下のようにコードを修正しました

AbstractTargetFollower.cs

public virtual void SetTarget(Transform newTransform)
{
    m_Target = newTransform;
    if (m_Target != null)
    {
        targetRigidbody = m_Target.GetComponent<Rigidbody>();
    }
}

おわりに

 最終的に1週間ゲームジャムでは、MultipurposeCameraRigを使用しました。
 上記のようにバグらしき挙動は見られましたが、カメラの挙動作成の時間は削減できたので助かりました。
 それにしても、各スクリプトでプロパティ名などフォーマットに大分違いがみられたんだけど、いろんな人が作ってるのかなぁ。