PUN Classic (v1)、PUN 2、Boltはメンテナンスモードとなっております。Unity2022についてはPUN 2でサポートいたしますが、新機能が追加されることはありません。お客様のPUNプロジェクトおよびBoltプロジェクトが停止することはなく、将来にわたってパフォーマンス性能が落ちることはありません。 今後の新しいプロジェクトについては、Photon FusionまたはQuantumへ切り替えていただくようよろしくお願いいたします。

6-プレイヤーのカメラワーク

このセクションでは、プレイヤを追従するCameraWorkスクリプトを作成する方法を説明します。 このセクションはネットワーキングと関連性がないため、簡潔に説明します。

目次

CameraWork Scriptを作成

  1. CameraWorkという名前の新しいC#スクリプトを作成します。
  2. CameraWorkの内容を以下のように置換します:

        using UnityEngine;
    using System.Collections;
    
    namespace Com.MyCompany.MyGame
    {
        /// <summary>
        /// Camera work. Follow a target
        /// </summary>
        public class CameraWork : MonoBehaviour
        {
    
    
        #region Public Properties
    
        [Tooltip("The distance in the local x-z plane to the target")]
        public float distance = 7.0f;
    
        [Tooltip("The height we want the camera to be above the target")]
        public float height = 3.0f;
    
        [Tooltip("The Smooth time lag for the height of the camera.")]
        public float heightSmoothLag = 0.3f;
    
        [Tooltip("Allow the camera to have a vertical from the target, for example giving more view of the scenery and less ground.")]
        public Vector3 centerOffset = Vector3.zero;
    
        [Tooltip("Set this as false if a component of a prefab being instantiated by Photon Network and manually call OnStartFollowing() when and if needed.")]
        public bool followOnStart = false;
    
        #endregion
    
        #region Private Properties
    
        // cached transform of the target
        Transform cameraTransform;
    
        // maintain a flag internally to reconnect if the target is lost or the camera is switched
        bool isFollowing;
    
        // Represents the current velocity, this value is modified by SmoothDamp() every time you call it.
        private float heightVelocity = 0.0f;
    
        // Represents the position we are trying to reach using SmoothDamp()
        private float targetHeight = 100000.0f;
    
        #endregion
    
        #region MonoBehaviour Messages
    
        /// &lt;summary&gt;
        /// MonoBehaviour method called on GameObject by Unity during initialization phase
        /// &lt;/summary&gt;
        void Start()
        {
            // Start following the target if wanted.
            if (followOnStart)
            {
                OnStartFollowing();
            }
    
        }
    
        /// &lt;summary&gt;
        /// MonoBehaviour method called after all Update functions have been called. This is useful to order script execution. For example a follow camera should always be implemented in LateUpdate because it tracks objects that might have moved inside Update.
        /// &lt;/summary&gt;
        void LateUpdate()
        {
            // The transform target may not destroy on level load,
            // so we need to cover corner cases where the Main Camera is different every time we load a new scene and reconnect when that happens
            if (cameraTransform == null && isFollowing)
            {
                OnStartFollowing();
            }
    
            // only follow is explicitly declared
            if (isFollowing)
            {
                Apply ();
            }
        }
    
        #endregion
    
        #region Public Methods
    
        /// &lt;summary&gt;
        /// Raises the start following event.
        /// Use this when you don't know at the time of editing what to follow, typically instances managed by the photon network.
        /// &lt;/summary&gt;
        public void OnStartFollowing()
        {         
            cameraTransform = Camera.main.transform;
            isFollowing = true;
            // we don't smooth anything, we go straight to the right camera shot
            Cut();
        }
    
        #endregion
    
        #region Private Methods
    
        /// &lt;summary&gt;
        /// Follow the target smoothly
        /// &lt;/summary&gt;
        void Apply()
        {
            Vector3 targetCenter = transform.position + centerOffset;
    
            // Calculate the current & target rotation angles
            float originalTargetAngle = transform.eulerAngles.y;
            float currentAngle = cameraTransform.eulerAngles.y;
    
            // Adjust real target angle when camera is locked
            float targetAngle = originalTargetAngle;
    
            currentAngle = targetAngle;
    
            targetHeight = targetCenter.y + height;
    
            // Damp the height
            float currentHeight = cameraTransform.position.y;
            currentHeight = Mathf.SmoothDamp( currentHeight, targetHeight, ref heightVelocity, heightSmoothLag );
    
            // Convert the angle into a rotation, by which we then reposition the camera
            Quaternion currentRotation = Quaternion.Euler( 0, currentAngle, 0 );
    
            // Set the position of the camera on the x-z plane to:
            // distance meters behind the target
            cameraTransform.position = targetCenter;
            cameraTransform.position += currentRotation * Vector3.back * distance;
    
            // Set the height of the camera
            cameraTransform.position = new Vector3( cameraTransform.position.x, currentHeight, cameraTransform.position.z );
    
            // Always look at the target    
            SetUpRotation(targetCenter);
        }
    
    
        /// &lt;summary&gt;
        /// Directly position the camera to a the specified Target and center.
        /// &lt;/summary&gt;
        void Cut( )
        {
            float oldHeightSmooth = heightSmoothLag;
            heightSmoothLag = 0.001f;
    
            Apply();
    
            heightSmoothLag = oldHeightSmooth;
        }
    
        /// &lt;summary&gt;
        /// Sets up the rotation of the camera to always be behind the target
        /// &lt;/summary&gt;
        /// &lt;param name="centerPos"&gt;Center position.&lt;/param&gt;
        void SetUpRotation( Vector3 centerPos )
        {
            Vector3 cameraPos = cameraTransform.position;
            Vector3 offsetToCenter = centerPos - cameraPos;
    
            // Generate base rotation only around y-axis
            Quaternion yRotation = Quaternion.LookRotation( new Vector3( offsetToCenter.x, 0, offsetToCenter.z ) );
    
            Vector3 relativeOffset = Vector3.forward * distance + Vector3.down * height;
            cameraTransform.rotation = yRotation * Quaternion.LookRotation( relativeOffset );
    
        }
    
        #endregion
    }
    
    }
  3. スクリプトCameraWorkを保存します。

リアルタイム3DやVectors、ベクトル、クォータニオンを使い始めたばかりの場合には、プレイヤーを追従する数学理論は難しいかもしれません。 このチュートリアルでは説明しませんが、ご興味のある場合には説明しますので、お気軽にお問い合わせください。

このスクリプトは難しい数学に関するだけのものではありません。アクティブにプレイヤーを追従するという重要な機能も設定されます。 これを理解することが重要です。なぜプレイヤーを追従するタイミングを制御する必要があるのでしょうか。

プレイヤーを常に追従した場合に、一般的に何が起きるかを想像してください。 プレイヤーでいっぱいのルームに接続すると、相手のプレイヤーのインスタンスのCameraWorkスクリプトは、プレイヤーを映すためにそれぞれ「メインカメラ」を制御しようとぶつかり合います。 こういった状態を避けて、コンピュータの前にいるユーザーを表すローカルプレイヤーのみを追従するべきです。

1つのカメラに対して複数のプレイヤーインスタンスが存在する場合の問題を把握できたので、それを防ぐ方法を以下で説明します。

  1. ローカルプレイヤーにのみCameraWorkスクリプトを添付する。
  2. 追従するプレイヤーがローカルプレイヤーかどうかに応じてオンとオフを切り替え、CameraWorkの動作を制御する。
  3. CameraWorkをカメラに取り付け、シーン内にローカルプレイヤーインスタンスがある場合は注意をして、そのプレイヤーのみを追従するようにする。

他にも方法はありますが、これらの3つの方法の中から選ぶとしたら2つ目のオプションをお勧めします。 3つの方法には大差はありませんが、2つ目のオプションはコーディングが最も少なく、非常に高い柔軟性があります。

  • パブリックプロパティfollowOnStartを公開しましたので、非ネットワーク化された環境でこれを使用する場合はtrueに設定してください。 例:テストシーンやまったく異なるシナリオ

  • ネットワークベースのゲームで動作する際、プレイヤーがローカルプレイヤーであると検出した場合にはパブリックメソッドOnStartFollowing()を呼び出します。 これは、作成されたスクリプトPlayerManagerで実行されます。このスクリプトについては、プレイヤープレハブネットワーキングの章で説明します。

前に戻る

ドキュメントのトップへ戻る