Unityのラグドールを使って敵が制御を失って倒れる様子を作成する

記事内に広告が含まれています。

今回はUnityのラグドールを使って敵が倒れる時の制御を失ってバタッと倒れる状態を作成していきたいと思います。

文章だけでは分かり辛いと思いますが、ダークソウルで敵を倒した後に制御を失って吹っ飛び、主人公に引きずられるようになる状態です。

今回の機能を作成すると、

上のような感じで敵のHPが0以下になった時に敵がフニャフニャになって飛ばされます。

倒れるアニメーションを作成しているわけではなくラグドールで設定したRigidbody、Joint、コライダによって動きが作られています。

上のサンプルは遠距離武器ですが、近接武器の実行例も途中で紹介したいと思います。

スポンサーリンク

今回の機能を作る流れ

今回の機能は二つのやり方で作ってみます。

ひとつめの機能作成の流れとしては、

  • ヒエラルキー上に設置した敵のモデルにラグドールを設定しプレハブにします。
  • 新たに敵のモデルをヒエラルキー上に配置し、通常の敵のスクリプト等を取り付ける。
  • メインカメラに攻撃スクリプトを取り付け、敵のHPが0以下になったら通常の敵を削除し、ラグドールを設定した敵のプレハブをインスタンス化する。
  • となります。

    もうひとつは

  • ヒエラルキー上に設置した敵のモデルにラグドールを設定し、ボーンのRigidbodyのIsKinematicをtrueにします。
  • 敵には移動で使うCharacterControllerやAnimatorコンポーネント等を持たせておきます。
  • メインカメラに攻撃スクリプトを取り付け、敵のHPが0以下になったらCharacterController、Animatorを無効化し、ボーンのRigidbodyのIsKinematicをfalseにしてラグドールが動作するようにします。
  • という流れになります。

    二つ目の方法は一つ目のラグドールを施した敵をインスタンス化するのではなく、通常の敵にラグドールの設定をしておいて、死ぬまでラグドールの動作をさせないというだけです。

    なので二つ目の説明はだいぶ省いております。

    通常の敵とラグドールを施した敵を分ける方法

    まずは通常の敵が倒れた時にラグドールを施した敵をインスタンス化する方法でやってみます。

    敵にラグドールを設定しプレハブを作成する

    まずは敵にラグドールを設定していきます。

    アセットストアで検索窓にZombiと入力し、PricingでFree Assetsにチェックを入れ、PXLTIGERさんが作ったゾンビのモデルをインポートします。

    Assets→Zombie→ModelFBX→Zombieを選択し、インスペクタのRigでAnimation TypeをHumanoidにします。

    Zombieをヒエラルキー上にドラッグ&ドロップして配置します。

    ヒエラルキー上で右クリック→3D Object→Ragdoll…を選択します(敵のモデルは選択しなくて大丈夫です)。

    ラグドールの作成

    Create Ragdollウインドウが開きます。

    ラグドールのウインドウ

    Create Ragdollウインドウの設定に、ヒエラルキー上のZombieのボーンをドラッグ&ドロップして設定します。

    Zombiのボーンをラグドールウインドウで設定

    その他のTotal Mass(全体の質量)、Strength(強さ)、Flip Forward(向きの反転)等は適宜変更してください。

    今回は変更しません。

    Createボタンを押すと敵の設定したボーンにRigidbodyやJoint、コライダが設定されるのがわかります。

    敵モデルにラグドールが設定された

    ZombieゲームオブジェクトのインスペクタのAdd ComponentからCharacterControllerを取り付けコライダのサイズを調整します。

    Animatorコンポーネントの歯車をクリックしRemove Componentを選択しAnimatorコンポーネントを削除します(Animatorが作用しているとラグドールが作用しない為)。

    また名前をZombieからZombiePrefabと変更しておきます。

    これでラグドールを設定した敵が出来たのでAssetsフォルダ内にドラッグ&ドロップしてプレハブにし、ヒエラルキー上の敵は削除します。

    通常の敵キャラクターの作成

    次は通常の歩いたり攻撃をしてきたりする敵キャラクターの作成をします。

    今回はただ攻撃を受ける敵キャラクターにし、移動や攻撃の機能は取り付けません。

    Assets→Zombie→ModelFBX→Zombieをヒエラルキー上にドラッグ&ドロップをします。

    ZombieのインスペクタのLayerにEnemyを設定します(Enemyレイヤーがない場合は作成してください)。

    Enemyレイヤーに変更する時にウインドウが出るので、No, this object onlyボタンを押し子要素のレイヤーは変更しないようにします。

    インスペクタのAdd ComponentからCharacterControllerを取り付け、コライダのサイズをゾンビのモデルの大きさと合うように調整します。

    新しくEnemyスクリプトを作成し取り付けます。

    enemyPrefabにはインスペクタで先ほど作ったラグドールを設定した敵のプレハブを設定します。

    damageDirectionはダメージを受けた時の方向を入れます。

    powerToMoveは敵のラグドールを飛ばす方向に加える力を指定します。

    timeToDeleteEnemyはラグドールの敵をインスタンス化してから削除するまでの時間を設定します。

    TakeDamageメソッドでは受けたダメージと方向を引数として受け取ります。

    自身が保持するhpを減らしてhpが0以下になったらダメージを受けた方向を保持し、自身のゲームオブジェクトを削除します。

    インスタンス化したラグドールの敵のCharacterControllerのMoveメソッドを使って攻撃を受けた方向に力を加えて動かします。

    その後一定時間が経過したらラグドールの敵も削除します。

    TakeDamageメソッドはメインカメラに取り付けるスクリプトから呼び出すことにします。

    メインカメラに敵攻撃スクリプトを取り付ける

    Main Cameraに新しくAttackスクリプトを取り付けます。

    rayDistanceはレイの距離を指定します。

    Input.GetMouseButtonDown(0)でマウスの左ボタンが押されたかどうかを判定します。

    Camera.main.ScreenPointToRay(Input.mousePosition)でメインカメラからマウスの位置にレイを飛ばしその情報をrayに保持します。

    Physics.Raycastでrayの情報を元にEnemyレイヤーが設定されたゲームオブジェクトと接触したかどうかを調べ、接触した情報をhitに保持します。

    接触した相手のEnemyスクリプトを取得し、GetHpメソッドでhpが0よりあるかどうかを調べて、hpがある場合はEnemyスクリプトのTakeDamageメソッドを呼び出し敵にダメージを与えます。

    ダメージ量に1を渡し、ダメージ方向にray.directionでカメラから敵に飛ばしたレイの方向の正規化された値を渡しています。

    渡す引数の前にdamage:やdirection:という記述がありますが、これはEnemyスクリプトのTakeDamageの引数で割り当てられている名前を指定して、TakeDamageメソッドを呼び出す時にどんな引数を渡しているのかを分かりやすくしているだけです。

    行っていることは以下と同じです。

    これで機能が完成しました!

    近接武器に対応する

    ここまでで機能は出来ましたが、レイを使っての銃器を想定した遠距離武器での対応でした。

    しかし近接武器でも同じような感じで対応出来ます。

    以前作成した剣を持たせて敵を攻撃する記事で剣に敵との接触判定をするスクリプトを作りました。

    Unityで主人公キャラが敵を攻撃出来るようにする機能
    Unityで主人公キャラが剣を振って敵キャラを攻撃出来るようにする機能を作成します

    そこで剣に取り付けたスクリプトでEnemyレイヤーが設定されている敵と剣が接触した時に敵のEnemyスクリプトのTakeDamageメソッドを呼び出します。

    ダメージの方向はtransform.root.forwardで主人公の一番階層が上のZombieのゲームオブジェクトの前方を渡していますが、剣が接触した時の剣先の方向を与えるとそちらの方に敵を飛ばす事も出来ます。

    近接攻撃を試すと

    上のようになりました。

    敵のPowerToMoveの値を0.01に設定して試しました。

    敵のラグドール機能をオン・オフする方法

    敵が倒れた時にラグドールの機能をオンにするやり方をみていきます。

    敵をインスタンス化するかしないかの違いなので、説明はだいぶ省いています。

    通常の敵にラグドールを設定する

    今回の場合は敵が倒れた時にラグドールを設定した敵をインスタンス化するのではなく、移動や攻撃等をする敵にラグドールを設定しておき、HPが0以下になったらその機能をオンにするというやり方です。

    なのでヒエラルキー上に敵を配置したらラグドールの設定をしてください。

    ラグドールの設定をしたらボーン全てのLayerをEnemyRagdollに変更します。

    今回のゾンビではBip 01の子要素全てのLayerをEnemyRagdollにします。

    ラグドールを施したボーンの階層

    ラグドールを施したボーンをEnemyRagdollレイヤーにする

    敵の移動等を行うスクリプトをEnemy3という名前で作成し敵に取り付けます。

    スクリプトの名前はわたくしの都合でそうなっているだけなので別の名前にしてください。

    ragdollRigidbodyArrayはRigidbodyを持つTransformを入れます。

    GetComponentsInChildrenを使ってRigidbodyを持つゲームオブジェクトを取得します。

    SetKinematicメソッドはRigidbodyのIsKinematicのオン・オフをするメソッドで、ragdollRigidbodyArrayの全てのRigidbodyのIsKinematicを切り替えられるようにしています。

    RigidbodyのIsKinematicがfalseの場合は外部から力を受けますが、trueの場合は外部からの力を受けません。

    Startメソッドで引数にtrueを渡してSetKinematicメソッドを呼び出し、最初はラグドール機能が働かないようにします。

    TakeDamageメソッドは敵がダメージを受けた時に外部から呼び出し、HPが0以下になったらSetKinematicを引数にfalseを渡して呼び出しラグドール機能をオンにします。

    またCharacterControllerコンポーネントのコライダがラグドールに使用しているコライダと衝突してしまう為、無効化しています。

    Layer Matrixを使ってCharacterControllerを設定しているゲームオブジェクトのレイヤーと、ラグドールに使用しているコライダのゲームオブジェクトのレイヤーの衝突をしないようにしておいても出来ます。

    Animatorコンポーネントが有効だとラグドール機能が働かないのでこちらも無効化します。

    これで敵の設定は終わりです。

    遠距離攻撃の作成

    遠距離攻撃を確認する為のスクリプトを作成します。

    マウスの左ボタンを押した時にレイを飛ばし、EnemyRagdollレイヤーのコライダと接触したらそのコライダのゲームオブジェクトのEnemy3スクリプトを取得し、TakeDamageメソッドを呼び出します。

    第2引数ではヒットしたコライダのTransformを渡してそのTransformのゲームオブジェクトのRigidbodyに力を加えます。

    近距離用の設定

    近距離の場合は剣が複数のコライダと接触した時に連続で複数のコライダに力を加えてしまうので、一振りではひとつのコライダにだけ力を加えるようにします。

    剣にAttackSword3スクリプトを作成し取り付けます。

    ダメージを与えた時にdoDamageにtrueを入れます。

    一度ダメージを与えたらその攻撃が終わるまで他のコライダと接触してもダメージを与えないようにしています。

    本来であればアニメーションイベントで剣を振り終わった時にAttackSword3スクリプトのSetDoDamageメソッドを使ってdoDamageをfalseにしたいところですが、今回はAnimatorControllerのビヘイビアを使ってSetDoDamageメソッドを呼びdoDamageをfalseにします。

    ビヘイビアに関しては以下の記事を参照してください。

    UnityのアニメーターコントローラーのStateMachineBehaviourでアニメを制御する
    Unityのアニメーターコントローラーを通常のスクリプトで制御するのではなくBehaviourを使って制御するようにします

    AnimatorControllerのAttack状態を選択し、新しくFlagTestビヘイビアを作り取り付けます。

    名前が変ですが適した名前を付けてください。

    OnStateExitはアニメーションの状態が終わった時に呼ばれるので、そこでanimatorからAttackSword3スクリプトを取得しSetDoDamageメソッドを呼び出します。

    これで機能が出来ました。

    終わりに

    ラグドールを使用するとリアルな敵が倒れる様子を作成する事が出来ますね。

    手動でRigidbody、Joint、コライダをキャラクターのボーンに取り付ける事でも同じような機能を作成できますが、ラグドールを使用すると該当する場所にボーンを設定するだけで勝手にそれらを作成してくれるので便利ですね。

    敵が倒れる時にラグドールの機能を使って倒し、その後再び起き上がってくる機能も移動キャラとラグドールを一緒にしておけば実現が可能かもしれません。

    ただやろうと思っても結構難しいです。(^_^;)

    タイトルとURLをコピーしました