アニメーション
概要
Fusion Animationsサンプルでは、Fusionを使ったアニメーションネットワーキングを扱う6つの異なるアプローチを紹介しています。
例 1 から例 5 は render accurate approach を使用し、例 6 は tick accurate approach を表しています。各例では、脚と腕のヒットボックスをおよそ1秒間隔で描画することで、サーバーキャラクターとプロキシキャラクターの間の精度を実証しています。アニメーションの精度は、ゲームが 遅延補償 を使用しているときに特に重要です。
ダウンロード
バージョン | リリース日 | ダウンロード | |
---|---|---|---|
1.1.6 | Jul 11, 2023 | Fusion Animations 1.1.6 Build 211 |
フォルダー構造
プロジェクトは、6つの小さな独立した例のセットとして構成されています。
/01_AnimatorSimple | 例1 - アニメーターとネットワーク状態 |
/02_AnimatorInterpolated | 例2 - アニメーターと補間されたネットワーク状態 |
/03_AnimatorStateSync | 例3 - アニメーターとの状態同期 |
/04_NetworkMecanimAnimator | 例4 - ネットワークMecanimアニメーター |
/05_AnimancerFSM | 例5 - AnimancerとネットワークFSM |
/06_FusionAnimationController | 例 6 - Fusion アニメーションコントローラー |
/Common | すべての作例に共通するプレハブ、スクリプト、素材 |
/ThirdParty | サードパーティーアセット(モデル、アニメーション、Animancer Lite) |
ハウツー
ゲームを開始する
各サンプルには独自のシーンファイルがあり、それを開いてプレイすることができます。または、すべてのサンプルは、Startシーン(/Common/Start)から起動することができます。
デモの目的には、ホストと2クライアントのマルチピアモードをお勧めします(Start Host + 2 Clients ボタン)。これにより、State Authority、Input Authority、Proxyの結果をエディタで確認・比較することができます。
コントロール
すべての例では、3つのアニメーションの状態のみを使用しています。デフォルトでは待機アニメーションが再生され、上矢印キーを押すとキャラクターランアニメーションが始まり、スペースキーを押すとジャンプアニメーションが始まります。
複数のピアでプレイするときは、Num 0、1、2*、*3**キーを使って、ピアを切り替えることができます。また、ランナー可視化コントロールウィンドウ(トップメニューのFusion > Windows > Runner Visibility Controls)からも切り替えが可能です。
アニメーションの精度を理解する
ピア間の正確なアニメーション同期は、正確な遅延補正など、特定のゲームアプリケーションにとって非常に重要です。アニメーションが完全に同期していると、あるクライアントで認識されたヒットがサーバーでも認識されることが保証され、結果として良いプレイ体験を提供することができます。もちろん、これはキャラクターのヒットボックスがアニメーションの影響を受けている場合のみ適用されます。FusionマニュアルのAnimationページで、重要なコンセプトが詳しく説明されていますので、ご確認ください。
全ての例は、ローカルプレイヤーから見た足と腕のヒットボックスの予想位置(プロキシ*キャラクターのヒットボックスは青色で表示)と、サーバーに表示される位置(緑色で表示)を示しています。アニメーションの精度が高いほど、ボックスの位置がより近くなります。
Hitbox drawing is performed by HitboxDraw
script placed on the Player prefabs. To better compare the difference, hitboxes are drawn in 50 ticks intervals (roughly a second).
プロキシオブジェクト = 入力権限(ローカルプレイヤーによって制御されていない)および状態権限(そのネットワーク状態に対する権限を持たないインスタンス、通常はサーバー上のインスタンス)を持たないネットワークオブジェクトインスタンスです。クライアントとしてプレイする場合、プロキシキャラクターはプレイヤーに見える他のプレイヤーのことです。
ネットワーク状態のシミュレーション
アニメーションの精度を上げるためのいくつかの変更(補間されたデータの使用など)は、悪いネットワーク条件で観察するのがよいでしょう。そのような状態を素早くシミュレートするために、Clumsyのようなツールを使用することができます。詳しくは Simulating Network Conditions のセクションをご覧ください。
例1 - アニメーターとネットワーク状態
レンダリング精度の高いアプローチ
この例では、最新のネットワーク状態を使用してアニメータのパラメータを制御す る、最もシンプルなソリューションを示します。
通常、既存のネットワーク状態(例:_controller.Speed
)を使用してアニメーショ ンを制御することができます。レンダリング精度の高いアニメーションは、Render
メソッドやOnChanged
コールバックでネットワーク上のデータに基づいて設定されます。
C#
private CharacterController _controller;
private Animator _animator;
public override void Render()
{
if (_lastVisibleJump < _controller.JumpCount)
{
_animator.SetTrigger("Jump");
}
_lastVisibleJump = _controller.JumpCount;
_animator.SetFloat("Speed", _controller.Speed);
}
例2 - アニメーターと補間されたネットワーク状態
レンダリング精度の高いアプローチ
この例では、最新のネットワークデータだけでなく、補間されたネットワークデータを使用することで、前の例から一歩前進しています。補間されたデータを使用することで、アニメーションがより正確になり、ネットワークの状態が理想的でない場合でもこの正確さが保たれます(ネットワーク状態のシミュレーションセクションを参照)。
C#
private CharacterController _controller;
private Animator _animator;
public override void Render()
{
int jumpCount = _useInterpolation == true ? _controller.InterpolatedJumpCount : _controller.JumpCount;
if (_lastVisibleJump < jumpCount)
{
_animator.SetTrigger("Jump");
}
_lastVisibleJump = jumpCount;
float speed = _useInterpolation == true ? _controller.InterpolatedSpeed : _controller.Speed;
_animator.SetFloat("Speed", speed);
}
補間されたデータと最新のデータの使用状況を比較するために、シンプルなチェックボックスがプレイヤーコンポーネントに存在します。Player_AnimatorInterpolated プレハブを探し、Use Interpolation をオフにしてください。2つのクライアントを追加してゲームを開始し、質の悪いネットワーク(Clumsy - Lag 100 ms, Drop 20%)をシミュレートし、その違いを比較します。
例3 - アニメーターとの状態同期
レンダリング精度の高いアプローチ
この例では、特別なコンポーネント AnimatorStateSync
を追加し、現在のプレイヤーアニメーターの状態とその時間を定期的に同期させます。状態の同期は、プレイヤーがゲームに参加した後や、プロキシオブジェクトが関心領域 に入ったときでも、プロキシのアニメーションが同期していることを保証します。
状態同期は、長時間のアニメーション(ロコモーションなど)や、レンダーアキュレートアプローチで起こりうるミスを修正するために特に重要です。
例:ローカルプレイヤーがゲームに参加したとき、リモートプレイヤーはすでに10秒間のランニングアニメーションを実行しています。しかし、アニメーションの時間が同期されていない場合、ローカルプレイヤーのマシンのプロキシキャラクターが最初からランニングアニメーションを開始するため、アニメーションのタイミングが異なってしまいます。このタイミングは、次のアニメーション動作(例:ジャンプ)で自動的に修正されますが、それまではアニメーションが同期していないことになります。
例4 - ネットワークMecanimアニメーター
レンダリング精度の高いアプローチ
Fusion SDKに同梱されているNetworkMecanimAnimator
(NMA)コンポーネントを使用してアニメーションを同期させる簡単な方法です。
Network Mecanim Animatorは、補間されたネットワークデータを使用しないため、例3のソリューションよりもアニメーションの精度は低くなります。NMAは、既存のネットワークデータを使用せず、現在のアニメーターパラメーターを独自のネットワークデータ構造にコピーするため、特に同期されたパラメーターが大きく変化する場合、より多くの帯域幅を消費することに注意してください。
Network Mecanim Animator についての詳細は Animation のドキュメントを参照してください。
C#
private CharacterController _controller;
private NetworkMecanimAnimator _networkAnimator;
public override void FixedUpdateNetwork()
{
if (IsProxy == true)
return;
if (Runner.IsForward == false)
return;
if (_controller.HasJumped == true)
{
_networkAnimator.SetTrigger("Jump", true);
}
_networkAnimator.Animator.SetFloat("Speed", _controller.Speed);
}
例5 - AnimancerとネットワークFSM
レンダリング精度の高いアプローチ
この例では、人気のあるサードパーティのアニメーションアセット Animancer と、このサンプルでプレビュー中の Network FSM アドオンを使用しています。Animancer は、最初の例と同様に、FSM なしでも使用できることに留意してください。
ネットワーク FSM は、ゲームオブジェクトに StateMachineController
コンポーネントを配置し、ステートマシンを保持し IStateMachineOwner
インターフェイスを実装したユーザスクリプト(Player など)を必要とします。その後、StateMachineController
が自動的に必要なデータを全てのピアに同期し、登録されたマシンを更新します。
C#
public class Player : NetworkBehaviour, IStateMachineOwner
{
private PlayerBehaviourMachine _fullBodyMachine;
void IStateMachineOwner.CollectStateMachines(List<IStateMachine> stateMachines)
{
var states = GetComponentsInChildren<PlayerStateBehaviour>();
var animancer = GetComponentInChildren<AnimancerComponent>();
_fullBodyMachine = new PlayerBehaviourMachine("Full Body", _controller, animancer, states);
stateMachines.Add(_fullBodyMachine);
}
}
アニメーションは状態の変化に基づいてプレイされます。状態は、プレイヤー階層のオブジェクトに StateBehaviour
スクリプトを付加したもの (例: Jump State, Locomotion State) か、State
スクリプトを継承したクラス (この例では紹介していません) である、単一のプレイヤー挙動を表します。
C#
public override void FixedUpdateNetwork()
{
if (IsProxy == true)
return;
if (_controller.HasJumped == true)
{
_fullBodyMachine.TryActivateState<PlayerJumpState>();
}
}
C#
public class PlayerJumpState : PlayerStateBehaviour
{
[SerializeField]
private ClipTransition _jumpClip;
protected override void OnEnterStateRender()
{
Animancer.Play(_jumpClip);
}
protected override void OnFixedUpdate()
{
if (Machine.StateTime >= _jumpClip.Length * _jumpClip.Speed)
{
// Jump animation should be finished, let's leave this state
Machine.TryDeactivateState(StateId);
}
}
}
親状態から制御されるサブ状態マシン(子マシン)を作成し、HFSM(階層型有限状態マシン)を効果的に作成することが可能です。たとえば、子マシンは、Jump、Fall、Land などの状態を持つ Airborne マシンで、親状態である Airborne から制御することができます。このような分離は、多くのステートを持つ複雑なアニメーションのセットアップを制御するときに便利で す。
Network FSM はデフォルトで補間されたデータに基づいてプロキシの状態を切り替え、Render 呼び出しからチェックする際に補間された現在の状態時間 (Machine.StateTime
) も提供することです。これにより、労力をかけずに細かいアニメーションの精度を確保することができます。
C#
public class PlayerLocomotionState : PlayerStateBehaviour
{
[SerializeField]
private LinearMixerTransition _moveMixer;
protected override void OnEnterStateRender()
{
Animancer.Play(_moveMixer);
// Update the animation time based on the state time
_moveMixer.State.Time = Machine.StateTime;
}
protected override void OnRender()
{
_moveMixer.State.Parameter = Controller.InterpolatedSpeed;
}
}
例 6 - Fusion アニメーションコントローラー
ティック精度の高いアプローチ
Fusion Animation Controllerは、Unityの低レベルなPlayables APIの上に直接構築されたtick accurateアニメーションソリューションです。
Mecanim と同様に、Animation Controller は Animation Layers で操作します。各レイヤーは、1つ以上のアニメーション状態を含みます。レイヤーと状態は、オブジェクト階層にあるオブジェクトで表現されます(Player_FusionAnimationController
プレハブを参照)。アニメーションは、コードから AnimationController
コンポーネントを介して制御されます。
C#
private CharacterController _controller;
private PlayerLocomotionState _locomotionState;
private PlayerJumpState _jumpState;
public override void FixedUpdateNetwork()
{
if (IsProxy == true)
return;
if (_controller.HasJumped == true)
{
_jumpState.Activate(0.15f);
}
else if (_jumpState.IsPlaying() == false || _jumpState.IsFinished(-0.15f, false) == true)
{
_locomotionState.Activate(0.15f);
}
}
Fusion Animation Controllerは、BR200で使用されたアニメーションコントローラを改良したものです。より精巧なアニメーション例については、BR200をご確認ください。
Back to top