今回は、アニメーションを追加していきます。
ダークソウルのように、武器による攻撃とローリングが行えるようにしました。
アセットストアで無料アセットを探してみたのですが、片手剣と盾を持って移動、攻撃、ローリングを行えるものが見つかりませんでした。両手剣ならあったので、それを使うことにします。同じアニメーションのアセット内に装備ナシもあったので、後日、装備を付けたり外したりできりるようにしたいと思います。
両手剣と書きながら、大槌に変わっています。
アセットの準備
アセットのインポート
アセットストアから以下のアセットをダウンロードして、インポートします。常に上位にあり、大人気のアセットのようです。
インポートの際は、次の画像でチェックが入っているもののほかに、あとから Materials, Models, Texures も入れました。最初はアニメーションだけ入れていたのですが、アバターがないって警告が出ていたので追加しました。
インポートしたらいつものように Asset Packs フォルダに移動しておきます。
武器のプレハブ化
武器は、背負っている大槌 Maul を使うことにしました。
まず Knight プレハブを開きます。続いて、chest に Empty のオブジェクト 2階層作成し、BackWeaponPosition と BackWeaponMaul という名称に変更します。さらにその下に Maul をぶら下げます。
BackWeaponPosition は背中の武器を取り付ける位置として使用します。BackWeaponMaul は位置と回転を気にせずに BackWeaponPosition に Maul を取り付けることができるようにするために使用します。実際に使用するのは後日になります。
出来上がったら、以下の画像のように BackWeaponMaul を Project の PlayerCharacter 内にドラッグアンドドロップしてプレハブ化しておきます。
一度プレハブ化した BackWeaponMaul の プレハブを Unpack します。Maul を手に取り付けるためです。
今度は、右手の R_Wrist の下に 2段分の Empty Object を作成し、それぞれ名前を R_HandWeapon, WeaponMaul とします。R_HandWeapon が武器の取り付け位置、WeaponMaul が Maul の 位置と回転を保存するための Object です。WeaponMaul の下に Maul を取り付けます。
BackWeaponMaul は不要なので削除しておきます。
以下の画像のようにして、WeaponMaul もプレハブ化しておきます。
武器の位置調整
まず、実行をして、Scene 画面に移動します。そして、中央のボタンで一時停止させます。あとは気合で位置と角度の調整を行います。慣れないと10分以上かかる場合があります。この時、必ず hierarchy で Maul を選択して作業をしてください。WeaponMaul ではないので注意してください。
このアニメーションでは左右の手の位置が合わないので、以下の画像のように右手に合わせました。左手は、気が向いたときににでも、 IK を使った位置合わせに挑戦することにします。
まだ、実行状態を止めないでください。止めたらやり直しです。この状態で、Maul の Transform で Copy Component します。
Copy Component を行ったら、実行を止めます。そして、Maul を選択した状態で、Transform で右クリックして Paste Component Values を実行します。
これで、実行した時に、先ほど位置合わせを行った場所に Maul が表示されます。忘れずに、Kight を Override しておきます。
今回は、実行しない状態でScene で見たときに右手にピッタリ合いました。ここでずれていても実行時に正しい位置に表示されれば問題ありません。
実行したら、左手はこのようにずれています。とりあえず放置します。
Animator にアニメーションを追加
Animator に アニメーションを追加していきます。
最初の攻撃中にもう1度ボタンを押すことで、2段目のコンボが出るようにしました。それとローリングを追加します。
事前準備
このキャラクターは、Animator の Apply Root Motion にチェックが入っていないので、チェックを入れておきます。基本的に、アニメーションについているRoot Motion を使えるようにして進めます。後で、移動のアニメーションだけは、Root Motion を切るかもしれません。
Root Motion については、ここが分かりやすかったです。
Parameters の設定
Parameters を以下のようにします。不足があれば追加してください。Speed と SpeedVertical が Float型 で、残りは Bool 型です。
新しい Blend Tree の作成
Animator 内に新しい Blend Tree を作ります。Motion と Threshold は以下の画像の通りにしてみました。足が滑るのでもう少し調整が必要だと思います。Run-Forward は再生速度を変えて2つ入れました。
デフォルトの Entry のステートを以下のようにして変更します。 Locomotion Blend Tree が新しく作った Blend Tree です。
アニメーションの追加
下の図のようにアニメーションを追加します、
左下にある BlendTree は以前使っていたもので、とりあえず残してあります。
各パラメータは以下の通り。
まず、Locomotion から Roll Foward。
- Has Exit TIme を外す
- タイミングを一番左にずらす。こうすることで、すぐにローリングに移るようになります。
- Conditions に IsRolling true を追加する
つづいて、Roll Foward から Locomotion への戻り。
Has Exit Time にチェックを入れることでアニメーションが終わってから Locomotion に戻るようになります。他も変更するところはありません。
Locomotion から Attack 1 は次の通り。Roll Foward と同様のことを行います。Conditions を IsAttackR1 にします。
戻りも、Roll Foward の戻りと同様です。Has Exit Time にチェックを入れておくことで、アニメーションが終わってから Locomotion に戻ります。
Attack 1 から Attack 4 は以下の通りです。Has Exit Time のチェックを外していますが、タイミングの設定が以下のようになっているため、Attack1 のアニメーションが終了してから Attack 4 に移ります。
Attack 4 から Locomotion への戻りは、他と同様、Has Exit Time にチェックを入れておくことで、アニメーションが終了したら戻るようにしておきます。(画像省略)
アニメーションの加工
そのままアニメーションを使うと、後ろに余白があり、キビキビした動きにならないため、アニメーションの長さを調整します。
Attack1 では、Length を少し削って実際のアニメーションより早く次の動作に移るようにします。
長さを調整したら、Events を設定します。Attack 1 には初めから Hit というイベントが設定されています。あとで使うと思うので、このまま残しておきます。
Hit より後ろの以下の位置あたりに新しいイベント追加して、Function を CallAnimationEnd と設定します。これは、このタイミングで、CallAnimationEnd() という関数を呼び出してくれます。先ほどの Hit も同様です。
忘れずに Apply を押してください。
Rolling は長さの調整が必要ありませんでした。以下のように イベントを設定します。
Attack 4 は無駄な動きが多いので長さを調整しました。あとは Attack 1 と同様にイベント追加して Function を設定します。
以上で Animator と アニメーションの設定は終わりです。
スクリプトの修正
今回加えたスクリプトへの修正について説明します。HUD 用のファイル HudController.cs と、PlayerStatus.cs については変更はありません。
PlayerAnimation.cs
今回使ったアニメーションに設定されていたイベントから呼び出される関数を追加しました。エラーが出ないようにすることが目的だったため、特に中身は作っていません。Hit() は攻撃アニメーションについていたもの。FootL(), FootR()は移動系のアニメーションについていたものです。こちらは足音を付けるためのものだと思います。
//
// Animation のイベントから呼び出す関数
//
void Hit()
{
}
void FootL()
{
}
void FootR()
{
}
PlayerCtrl.cs
ボタンの入力処理を追加しました。今回は、手抜きで、四角ボタンでローリング、×ボタンで走る、丸ボタンでジャンプとしました。×ボタンを短く押してローリングする方法は後日紹介します。
// 四角ボタンでローリング
if (Input.GetButtonUp("Fire_0"))
{
if (state != State.Rolling)
{
nextState = State.Rolling;
}
}
// 丸ボタンでジャンプ
if (Input.GetButtonUp("Fire_2"))
{
if (state != State.Jump)
{
nextState = State.Jump;
}
}
if (Input.GetButtonUp("Fire_R1"))
{
if (state == State.AttackR1)
{
nextState = State.AttackR1_2;
}
else if (state != State.AttackR1 && state != State.AttackR1_2)
{
// AttackR1, AttackR1_2 のときは、次の入力をまだ受け付けない
nextState = State.AttackR1;
}
}
攻撃中やローリング、ジャンプ中に移動や方向転換を制限する処理を追加しています。ローリングのアニメーションはその場でローリングするため、一定速度で移動するような処理を追加しています。攻撃中やジャンプ中も同様で、一定速度で移動するようにしました。
public bool canMove = true;
public bool canRotate = true;
public float fixedMoveSpeed = 0;
private void StartRolling(State prevState)
{
StateStartCommon();
status.isRolling = true;
nextState = State.Walking;
fixedMoveSpeed = 8f;
}
private void StartJump(State prevState)
{
StateStartCommon();
status.isJumping = true;
nextState = State.Walking;
// ダッシュジャンプの速度
fixedMoveSpeed = playerMove.walkSpeed * playerMove.runSpeedUpRatio;
playerMove.AddJumpPower();
}
private void StateStartCommon()
{
//Debug.Log("StateStartCommon()");
status.resetStatus();
status.isAnimationEnd = false;
nextState = State.Walking;
canMove = false;
canRotate = false;
fixedMoveSpeed = 0;
}
PlayerMove.cs
「// カメラの向きに、スティックの向きを掛け合わせ、キャラクターをスティックの方向に向かせる」処理をcanRotate が true の場合だけにしました。攻撃中、ローリング中、ジャンプ中に方向転換をできなくするための処理です。
// カメラの向きに、スティックの向きを掛け合わせ、キャラクターをスティックの方向に向かせる
Vector3 cameraDirection = lookTarget.position - mainCamera.transform.position;
cameraDirection.y = 0;
cameraDirection = Vector3.Normalize(cameraDirection);
if (playerCtrl.canRotate)
{
Quaternion characterTargetRotation = Quaternion.LookRotation(cameraDirection) * Quaternion.LookRotation(playerDirection);
transform.rotation = Quaternion.RotateTowards(transform.rotation, characterTargetRotation, rotationSpeed * Time.deltaTime);
}
canMove が false の場合、固定値で移動する処理を追加しました
// スティックの傾きによる速さの変化
speedByStick = playerCtrl.GetMagunitudeStickL();
moveSpeed = speedByStick * walkSpeed * runSpeedUp * sprintSpeedUp;
if (!playerCtrl.canMove)
{
// 動けない場合に固定値を使用する
moveSpeed = playerCtrl.fixedMoveSpeed;
}
velocity = transform.forward.normalized * moveSpeed;
ついでに歩行速度が速いので、少し遅くしました。
// 移動速度
internal float walkSpeed = 1f;
internal float runSpeedUpRatio = 2.0f;
internal float sprintSpeedUpRatio = 2.0f;
ファイル
おわりに
以上で、攻撃、ローリング、ジャンプができるようになりました。
現時点では、ボタン操作は簡略化して、四角ボタンでローリング、×ボタンで走る、丸ボタンでジャンプとしました。また、ジャンプはダークソウルのようなジャンプとは異なり、2Dのアクションゲームのような大ジャンプになっています。
このあたりは、後日実装します。