3 - 動作とカメラ
概要
動作とカメラでは、プレイヤーの入力に基づくプレイヤーの動きと、正しいプレイヤーのオブジェクトを追う一人称カメラの追加により、既存のシーンを拡張しています。
#プレイヤーの動作
Fusionでは、動きなどtickごとに更新するゲームプレイコードは、Update / FixedUpdate
で実行すべきではありません。代わりに、FixedUpdateNetwork
を使用する必要があります。これにより、すべてのクライアントで動きがスムーズになり、正しく補間されるようになります。
新しいスクリプトを作成し、PlayerMovement
という名前を付けます。このスクリプトに、次のコードを持つ FixedUpdateNetwork
関数を追加します:
C#
public override void FixedUpdateNetwork()
{
// Only move own player and not every other player. Each player controls its own player object.
if (HasStateAuthority == false)
{
return;
}
Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * Runner.DeltaTime * PlayerSpeed;
Controller.Move(move + velocity * Runner.DeltaTime);
if (move != Vector3.zero)
{
gameObject.transform.forward = move;
}
}
HasStateAuthority
は、クライアントがオブジェクトを制御しているかどうかをチェックするために使用することができます。NetworkTransform
は、StateAuthority
から他のクライアントへの変更のみを同期させます。他のクライアントがオブジェクトの位置を変更した場合、その変更はローカルな変更にとどまり、将来的にネットワークからのデータで上書きされます。
Runner.DeltaTime
を使用してください!PlayerMovement
コンポーネントをプレイヤープレハブに追加します。
カメラ
カメラの設定には多くの方法(三人称、一人称など)があり、それらを実装する方法もさまざまです。マルチプレイヤーゲームでは、ローカルプレイヤーオブジェクトを追う単一のカメラが望ましい場合が多いです。これを実現するには、2つの一般的な方法があります。
- ローカルプレイヤーオブジェクトがスポーンされたら、カメラをインスタンス化する。
- カメラをシーンの一部にする。ローカルプレイヤーオブジェクトが生成されたときに、カメラを見つけ、カメラのターゲットをカメラに設定します。
このページでは、2番目の方法を使用します。
新しいスクリプトを作成し、名前を FirstPersonCamera
とします。そのスクリプトに次のコードを追加します:
C#
using UnityEngine;
public class FirstPersonCamera : MonoBehaviour
{
public Transform Target;
public float MouseSensitivity = 10f;
private float vertialRotation;
private float horizontalRotation;
void LateUpdate()
{
if (Target == null)
{
return;
}
transform.position = Target.position;
float mouseX = Input.GetAxis("Mouse X");
float mouseY = Input.GetAxis("Mouse Y");
vertialRotation -= mouseY * MouseSensitivity;
vertialRotation = Mathf.Clamp(vertialRotation, -70f, 70f);
horizontalRotation += mouseX * MouseSensitivity;
transform.rotation = Quaternion.Euler(vertialRotation, horizontalRotation, 0);
}
}
これは、非常にシンプルな一人称カメラの実装です。このコードにはマルチプレイの要素が含まれていません。このカメラは、Cinemachineを含むターゲットオブジェクトで動作する他のカメラ設定に置き換えることができます。
シーン内の MainCamera
GameObject に FirstPersonCamera
動作を設定します。ターゲットをドラッグする必要はありません。ターゲットは実行時にコードでセットアップされます。
ターゲットを割り当てるには、PlayerMovement
スクリプトを開いてください。カメラを格納するための変数を追加します:
C#
public Camera Camera;
そして、プレイヤーオブジェクトがスポーンされた時に、ローカルプレイヤーであれば、カメラを見つけて設定します。
C#
public override void Spawned()
{
if (HasStateAuthority)
{
Camera = Camera.main;
Camera.GetComponent<FirstPersonCamera>().Target = GetComponent<NetworkTransform>().InterpolationTarget;
}
}
NetworkObject
を初期化するときは、必ず Awake/Start
ではなく Spawned
を使用するようにしてください。Awake/Start
では、NetworkObject
がまだ使用できる状態でない可能性があります。
HasStateAuthority
はプレイヤーがコントロールするオブジェクトに対してのみ true となります。つまり、ローカルのプレイヤーオブジェクトのみで、他のプレイヤーオブジェクトは含まれません。最後に、一人称視点のゲームでは、プレイヤーキャラクターは視線方向に動くので、動きを少し調整します。Vector3 move
が計算される行を、以下のように置き換えてください:
C#
var cameraRotationY = Quaternion.Euler(0, Camera.transform.rotation.eulerAngles.y, 0);
Vector3 move = cameraRotationY * new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * Runner.DeltaTime * PlayerSpeed;
ボタン押下の対応
Unityでは、GetButtonDown
やupなどの1回限りの入力は、Update
の間に発生します。Fusionのゲームプレイでは、移動などのコードはFixedUpdateNetwork
で実行されるはずです。つまり、ボタンの状態を正確にトラッキングするためには、特別な処理が必要です。
FixedUpdate
でボタン押下をチェックする際にも同様の問題が発生しますFixedUpdateNetwork
でそのような入力を取り込むには、複数のアプローチがあります:
Update
でボタンを押したかどうかクエリを実行する。その結果をboolに保存して、ゲームロジックに使用する。FixedUpdateNetwork
の終了時にクリアします。- FusionのNetworkInputを
NetworkButtons
で使用します。 - 新しいUnity Input Systemを使い、
Update Mode
をManual Update
に設定し、FixedUpdateNetwork
でInputSystem.Update
を呼び出します。
ジャンプ
ボタン押下を処理する例として、プレイヤーのジャンプアクションを実装してみましょう。ここでは、前章で挙げたオプションのうち、オプション1を使用します。
まず、PlayerMovement
に以下の変数を追加します:
C#
public float JumpForce = 5f;
public float GravityValue = -9.81f;
private Vector3 velocity;
private bool _jumpPressed;
_jumpPressed
はボタンの状態を追跡するために使用されます。velocity
は、空中にあるKCCに人工重力を付加するためのものです。
ボタンが押された状態をポーリングするために、Update
ごとに以下のコードを追加してください:
C#
public override void Spawned()
{
if (HasStateAuthority)
{
Camera = Camera.main;
Camera.GetComponent<FirstPersonCamera>().Target = GetComponent<NetworkTransform>().InterpolationTarget;
}
}
そして、FixedUpdateNetwork
の終了時にジャンプ状態をクリアします:
C#
_jumpPressed = false;
Controller.Move
を呼び出す行の前に、以下を追加します:
C#
velocity.y += GravityValue * Runner.DeltaTime;
if (_jumpPressed && Controller.isGrounded)
{
velocity.y += JumpForce;
}
最後に、HasStateAuthority
チェックの直後に以下を追加し、地上にいるときの速度をリセットします:
C#
if (Controller.isGrounded)
{
velocity = new Vector3(0, -1, 0);
}
Unityに戻り、ゲームを起動し、Start Shared Client
を押します。Space
ボタンを押し、キャラクターがジャンプするのを確認します。
次ページ{Fusion 104 Shared](./fusion-104-shared)
Back to top