3 - 移動とカメラ
概要
ここでは、プレイヤーの入力に基づくプレイヤーの移動と、適切なプレイヤーオブジェクトに追従する一人称視点のカメラを、前章のシーンに追加します。
プレイヤーの移動
Fusionでは、毎ティック更新するゲームプレイのコード(プレイヤーの移動など)をUpdate
やFixedUpdate
で実行すべきではありません。かわりにFixedUpdateNetwork
を使用すべきです。このメソッドによって、全てのクライアント上で移動がスムーズに正しく補間されるようになります。
新規でスクリプトを作成して、名前をPlayerMovement
にし、以下のコードを追加してください。
C#
using Fusion;
using UnityEngine;
public class PlayerMovement : NetworkBehaviour
{
private CharacterController _controller;
public float PlayerSpeed = 2f;
private void Awake()
{
_controller = GetComponent<CharacterController>();
}
public override void FixedUpdateNetwork()
{
// FixedUpdateNetwork is only executed on the StateAuthority
Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * Runner.DeltaTime * PlayerSpeed;
_controller.Move(move);
if (move != Vector3.zero)
{
gameObject.transform.forward = move;
}
}
}
MonoBehaviour
のかわりにNetworkBehaviour
を継承することで、FixedUpdateNetwork
とネットワークプロパティ(詳細は後述)が使用できるようになります。
ボタン押下の処理
GetButtonDown
などはUnityのUpdate
で1フレームのみ反応します。Fusionではゲームプレイのコード(プレイヤーの移動など)をFixedUpdateNetwork
で実行するため、ボタン押下状態を正確に取得するための特別な処理が必要になります。
FixedUpdate
でも発生する問題と同様です。FixedUpdateNetwork
で正確な入力を取得するには、複数のアプローチがあります。
Update
でボタン押下状態を取得、結果をbool
で保存し、ゲームロジックに使用する。その後のFixedUpdateNetwork
の最後に取得結果をクリアする。- 新しいUnityのInput Systemを使用して、
Update Mode
をManual Update
に設定、FixedUpdateNetwork
でInputSystem.Update
を呼び出す。 - Fusionのネットワーク入力で、
NetworkButtons
を使用する。
ジャンプ
ボタン押下を処理する例として、プレイヤーのジャンプを実装してみましょう。今回は、前節のリストのオプション1を使用します。
PlayerMovenet
のコードを、以下のように書き換えてください。
C#
using Fusion;
using UnityEngine;
public class PlayerMovement : NetworkBehaviour
{
private Vector3 _velocity;
private bool _jumpPressed;
private CharacterController _controller;
public float PlayerSpeed = 2f;
public float JumpForce = 5f;
public float GravityValue = -9.81f;
private void Awake()
{
_controller = GetComponent<CharacterController>();
}
void Update()
{
if (Input.GetButtonDown("Jump"))
{
_jumpPressed = true;
}
}
public override void FixedUpdateNetwork()
{
// FixedUpdateNetwork is only executed on the StateAuthority
if (_controller.isGrounded)
{
_velocity = new Vector3(0, -1, 0);
}
Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * Runner.DeltaTime * PlayerSpeed;
_velocity.y += GravityValue * Runner.DeltaTime;
if (_jumpPressed && _controller.isGrounded)
{
_velocity.y += JumpForce;
}
_controller.Move(move + _velocity * Runner.DeltaTime);
if (move != Vector3.zero)
{
gameObject.transform.forward = move;
}
_jumpPressed = false;
}
}
このコードでは、ジャンプ処理と、KCC(キネマティックキャラクターコントローラー)に渡す速度と重力の計算を追加しています。
_jumpPressed
変数はボタン押下状態を保存するために使用されます。ボタン押下状態は、判定ミスが起こらないようにUpdate
でポーリングされ、FixedUpdateNetwork
の最後にリセットされます。
C#
if (_controller.isGrounded)
{
_velocity = new Vector3(0, -1, 0);
}
上記のコードで、小さな斜面上を歩いている時でも地面に着くようにすることで、ジャンプ中のみプレイヤーが地面から離れるようにします。
テストの実行
PlayerMovement
が完成したら、Unityエディターに戻り、PlayerCharacter
プレハブにPlayerMovement
コンポーネントを追加します。
プレイヤーの移動がテストできるようになったので、ビルドして二つのクライアントを実行してみましょう。
File > Build Settings
で現在のシーンをリストに追加して、ウインドウ左下のPlayer Settings
ボタンを押してください。
Player Settings
では、Resolution and Presentation
をFullscreen Mode
に設定して、Run In Background
にチェックを入れてください。
Build Settings
に戻り、Build and Run
を押してビルドを作成します。ビルドが完了したら、Unityエディター上でもゲームを実行すると、二つのクライアントが立ち上がることになります。
両方のクライアントでStart Shared Client
ボタンを押します。プレイヤーが二人表示され、それぞれが各クライアントで操作できます。歩き回ったりジャンプしたりできるか確認してみてください。
カメラ
プレイヤーのセットアップを完成させるため、カメラを追加しましょう。
カメラ設定には何通りかの方法(三人称、一人称など)があり、実装方法も異なります。マルチプレイゲームでは、ローカルプレイヤーオブジェクトに追従するカメラが一つあることが望ましい場合が多いです。一般的な実装は、以下の二つです。
- ローカルプレイヤーオブジェクトがスポーンされたら、カメラのインスタンスを生成する
- あらかじめカメラをシーン上に置いておき、ローカルプレイヤーオブジェクトがスポーンされたら、そのオブジェクトをカメラのターゲットにする
このチュートリアルでは2のアプローチを使用します。
新規スクリプトを作成して、名前をFirstPersonCamera
にし、以下のコードを追加してください。
C#
using UnityEngine;
public class FirstPersonCamera : MonoBehaviour
{
public Transform Target;
public float MouseSensitivity = 10f;
private float verticalRotation;
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");
verticalRotation -= mouseY * MouseSensitivity;
verticalRotation = Mathf.Clamp(verticalRotation, -70f, 70f);
horizontalRotation += mouseX * MouseSensitivity;
transform.rotation = Quaternion.Euler(verticalRotation, horizontalRotation, 0);
}
}
これは、非常にシンプルな一人称カメラの実装です。このコードにはマルチプレイの要素が含まれていないことに注意してください。このカメラは、オブジェクトをターゲットにして動作する他のカメラ(Cinemachineなど)に置き換えることも可能です。
シーンのMainCamera
にFirstPersonCamera
を追加します。ターゲットは実行時にコードから設定されるので、ターゲットオブジェクトは空のままで問題ありません。