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