AIプログラムとかUnityゲーム開発について

探索や学習などを活用したAI系ゲームを作りたいと思います。

手足にコライダーを付けて、キックやパンチ攻撃を実現

f:id:yasu9780:20161119051439p:plain

 手足にコライダーをつけてキックやパンチの判定に使います。剣にコライダーをつけて斬撃を判定するのと仕組みは同じです。
 UI的に手動でコライダーをつけることもできますが、それだとキャラを追加するごとに作業が要ります。
 プログラムでコライダーを装着すれば、キャラ追加時もなにも作業が要りませんので効率的です。
 
 具体的には、球型のIsTriggerなコライダーをprefabとして準備しておきます。
 骨の位置を取得して子要素として登録します。
 球コライダーはmeshを非表示にしておけば、コライダーのみ有効になります。
 足の攻撃として、足首よりもつま先にコライダーが欲しいので、forward*0.1fだけ足して、つま先方向に動かしました。

        anim = GetComponent<Animator>();

        //右手のコライダー
        Transform Rhand = anim.GetBoneTransform(HumanBodyBones.RightHand);
        GameObject RhandSph = Instantiate((GameObject)Resources.Load("Sphere"), Vector3.zero, Quaternion.identity) as GameObject;
        RhandSph.transform.position = Rhand.position;// +Rhand.right*0.1f;
        RhandSph.transform.SetParent(Rhand);
        //左手のコライダー
        Transform Lhand = anim.GetBoneTransform(HumanBodyBones.LeftHand);
        GameObject LhandSph = Instantiate((GameObject)Resources.Load("Sphere"), Vector3.zero, Quaternion.identity) as GameObject;
        LhandSph.transform.SetParent(Lhand);
        LhandSph.transform.position = Lhand.position;// + Rhand.right * 0.1f;

        //右足のコライダー
        Transform Rfoot = anim.GetBoneTransform(HumanBodyBones.RightFoot);
        GameObject RfootSph = Instantiate((GameObject)Resources.Load("Sphere"), Vector3.zero, Quaternion.identity) as GameObject;
        RfootSph.transform.SetParent(Rfoot);
        RfootSph.transform.position = Rfoot.position + Rfoot.forward*0.1f -Rfoot.up*0.1f;
        //左足のコライダー
        Transform Lfoot = anim.GetBoneTransform(HumanBodyBones.LeftFoot);
        GameObject LfootSph = Instantiate((GameObject)Resources.Load("Sphere"), Vector3.zero, Quaternion.identity) as GameObject;
        LfootSph.transform.SetParent(Lfoot);
        LfootSph.transform.position = Lfoot.position + Lfoot.forward * 0.1f -Lfoot.up*0.1f;

 衝突判定の部分は次のような感じになります。足や手の衝突はSphereとして取れます。
 普通の状態で接触しても攻撃にならないように、Sphereの持ち主が攻撃モーション実行中かどうかを調べます。
 自分が味方側で、相手が敵側の場合に、5ダメージを、ApplyDamage関数に渡します。Sphereの持ち主を表す番号noと、打突位置も渡します。
 (持ち主にexpなどの加点を行い、打突位置にエフェクトを表示します)

    void OnTriggerEnter(Collider other)
    {
        if (other.name == "Sphere")
        {
            AnimatorStateInfo stateInfo = _parent.GetComponent<Animator>().GetCurrentAnimatorStateInfo(0);
            if (stateInfo.IsName("Zattack") && stateInfo.normalizedTime <= 1f)
                if (!isMonster(name) && isMonster(_parent.name))
                    ApplyDamage(5, _parent.GetComponent<character>().no, other.transform);
        }


 ほぼ同じロジックですが、剣の衝突の場合は、以下のような感じ。
 相手が剣をふるモーションを実行しているか確認します。また、ハンマー斬撃など動きが大きい場合、振り下ろしと振り上げで二回Enterが発生したりするので、
 振り下ろしモーション時の衝突のみ有効にカウントするために、「stateInfo.normalizedTime < 0.6f」と判定します。
 これは、アニメーションの再生時間位置の正規化された値で、0→1で変化します。
 0.6だと60%ぐらいなので、振り下ろしのみ有効という感じです。実行時の様子などを見てアバウトに決めています。

        if (other.name == "Sword")
        {
            AnimatorStateInfo stateInfo = _parent.GetComponent<Animator>().GetCurrentAnimatorStateInfo(0);
            if (stateInfo.IsName("Sword") && stateInfo.normalizedTime < 0.6f)
            { 
                if (isMonster(name) && !isMonster(_parent.name))
                    ApplyDamage(20, _parent.GetComponent<character>().no, other.transform);
                if (!isMonster(name) && isMonster(_parent.name))
                    ApplyDamage(20, _parent.GetComponent<character>().no, other.transform);
            }
        }