Unity2019.2.2f1
Windows10
□
【UnityC#講座】3D人型モデルを三人称視点で動かす操作を改良
これらの記事の続きです。
今回は自分で操作するユニティちゃんとNavMeshAgentで動くユニティちゃんが互いにパンチし合うようにします。
より具体的に言うとNavMeshAgentの方は殴られると動き出してプレイヤーを追いかけてColliderに接触したら攻撃し、追いかける時間が決められただけ経つとスタート地点に戻るようにしました。
ユニティちゃん同士の殴り合い。
一定時間経つとNavMeshAgentで動く方はスタート地点に戻ります。#unity pic.twitter.com/YQWXL19WVt— イシゲー@UnityとBlender (@ishidahanta) November 20, 2019
■ユニティちゃんをコピーする
Duplicateする
前回作ったユニティちゃんをHierarchyで右クリック、Duplicateでコピーして敵にします。
Tagを2つ替える
その際、気を付けないといけないのはコピーユニティちゃんとそのAttackPointのTagを直すことです。
コピーユニティちゃんのTagをUntaggedにします。
コピーユニティちゃんのAttackPointをEnemyAttackにします。
簡単に階層が下のオブジェクトにアクセスするにはHierarchyの検索欄を使います。
あるいはInspectorからPlayerスクリプトに入っているAttackPointをクリックすると簡単にアクセスできます。
Playerスクリプトを外す
そしてコピーの方のPlayerスクリプトを外します。
右上の歯車マークをクリックし、Remove Componentを選んでください。
それを残しておくとアニメーションイベント絡みのエラーが出ます。
別に機能に問題はないですが鬱陶しいので消しておきましょう。
参考
【Unity】SetBoolでNull???【エラー】
■NavigationウィンドウでBakeする
Navigation Static
次はNavMeshAgentを動かすための土台を作ります。
まずはPlanないしはユニティちゃんが移動する床のオブジェクトをNavigation Staticにしましょう。
Inspectorからの右上にあるStaticをクリックし、Navigation Staticを選択します。
Navigationウィンドウ
次はNavigationウィンドウを出します。
画面上部のメニューバーのWindowから選択します。
Window > AI > Navigation
Bake
次はNavigationウィンドウでBakeします。
Navigation > Bakeタブ > Bakeボタン
するとSceneビューのNavigation Staticにしたオブジェクトに青い面ができますが、それがNavMeshAgentが移動できる範囲です。
そのオブジェクトを移動したり、形を変えたりするとBakeし直さなければなりません。
スポンサーリンク
■スクリプトを設定する
最後はスクリプトを設定して終わりです。
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
//NavMeshAgent使うとき必要 | |
using UnityEngine.AI; | |
[RequireComponent(typeof(CapsuleCollider))] | |
[RequireComponent(typeof(Rigidbody))] | |
//オブジェクトにNavMeshAgentコンポーネントを設置 | |
[RequireComponent(typeof(NavMeshAgent))] | |
public class Opponent : MonoBehaviour | |
{ | |
private NavMeshAgent agent; | |
private Vector3 startPoint; | |
Rigidbody rb; | |
CapsuleCollider caps; | |
private Animator animator; | |
GameObject player; | |
//追跡モードになってからの時間 | |
[SerializeField] float time; | |
//追跡モードを続ける時間 | |
[SerializeField] float chaseTime = 5.0f; | |
//攻撃にかける時間 | |
[SerializeField] float attackTime = 0.5f; | |
//追跡のスピード | |
[SerializeField] float chaseSpeed = 3.5f; | |
//スタート地点に戻るスピード | |
[SerializeField] float returnSpeed = 1.0f; | |
enum Action | |
{ | |
Wait, | |
Attack, | |
Chase, | |
Damage, | |
Return | |
} | |
[SerializeField] Action action = Action.Wait; | |
//攻撃判定のオブジェクトを入れる | |
public GameObject attackJudgment; | |
void Start() | |
{ | |
//Animatorコンポーネントを取得 | |
animator = GetComponent<Animator>(); | |
//Rigidbodyコンポーネントを取得 | |
rb = GetComponent<Rigidbody>(); | |
//RigidbodyのConstraintsを3つともチェック入れて | |
//勝手に回転しないようにする | |
rb.constraints = RigidbodyConstraints.FreezeRotation; | |
//CapsuleColliderコンポーネントを取得 | |
caps = GetComponent<CapsuleCollider>(); | |
//CapsuleColliderの中心の位置を決める | |
caps.center = new Vector3(0, 0.8f, 0); | |
//CapsuleColliderの半径を決める | |
caps.radius = 0.23f; | |
//CapsuleColliderの高さを決める | |
caps.height = 1.6f; | |
//NavMeshAgentコンポーネントを取得 | |
agent = GetComponent<NavMeshAgent>(); | |
// autoBraking を無効にすると、目標地点の間を継続的に移動します | |
//(つまり、エージェントは目標地点に近づいても | |
// 速度をおとしません) | |
agent.autoBraking = false; | |
//スタート地点を取得 | |
startPoint = transform.position; | |
//Playerタグのオブジェクトを取得 | |
player = GameObject.FindGameObjectWithTag("Player"); | |
//攻撃判定のオブジェクトを隠す | |
attackJudgment.SetActive(false); | |
} | |
void Update() | |
{ | |
//殴られていない時は動かす待機モーション出す | |
if (action == Action.Wait) | |
{ | |
//Agentを止める | |
agent.isStopped = true; | |
//スピードによりモーションが変わる | |
animator.SetFloat("Y", agent.velocity.sqrMagnitude); | |
} | |
//殴られるとPlayerを追跡し出す | |
else if (action == Action.Chase) | |
{ | |
//NavMeshAgentが動き出す | |
agent.isStopped = false; | |
//目的地をPlayerにする | |
agent.destination = player.transform.position; | |
agent.speed = chaseSpeed; | |
animator.SetFloat("Y", agent.velocity.sqrMagnitude); | |
time += Time.deltaTime; | |
//chaseTimeの時間が過ぎるとReturnモードになる | |
if (time > chaseTime) | |
{ | |
action = Action.Return; | |
time = 0; | |
} | |
} | |
//攻撃モード | |
else if (action == Action.Attack) | |
{ | |
animator.SetBool("Attack", true); | |
agent.speed = 0; | |
attackJudgment.SetActive(true); | |
} | |
//ダメージモード | |
else if (action == Action.Damage) | |
{ | |
animator.SetBool("Damage", true); | |
agent.speed = 0; | |
} | |
//スタート地点に帰る | |
else if (action == Action.Return) | |
{ | |
animator.SetFloat("Y", agent.velocity.sqrMagnitude); | |
agent.speed = returnSpeed; | |
//目的地をスタート地点に | |
agent.destination = startPoint; | |
//経路探索の準備ができておらず、 | |
//目標地点との距離から0.1m未満になったら起動 | |
if (!agent.pathPending && agent.remainingDistance < 0.1f) | |
{ | |
//待機モードに戻る | |
action = Action.Wait; | |
} | |
} | |
} | |
//攻撃受けた時の処理 | |
//IsTriggerにチェックしたオブジェクトが | |
//別オブジェクトに触れると起動 | |
private void OnTriggerEnter(Collider other) | |
{ | |
//PlayerAttackタグに触れると、ダメージモードなら何も起きない | |
//それ以外のモードならダメージモードになる | |
if (other.gameObject.tag == "PlayerAttack") | |
{ | |
if (action == Action.Damage) | |
{ | |
return; | |
} | |
else | |
{ | |
action = Action.Damage; | |
} | |
} | |
} | |
//攻撃する条件 | |
//本体のColliderが別オブジェクトに触れたら起動 | |
private void OnCollisionEnter(UnityEngine.Collision collision) | |
{ | |
//相手がPlayerタグでこちらが追跡モードの時に起動 | |
//攻撃モードになる | |
if (collision.gameObject.tag == "Player" && action == Action.Chase) | |
{ | |
action = Action.Attack; | |
} | |
} | |
//DAMAGED00のアニメーションイベントで呼ばれる | |
//Action.Moveに戻す | |
//ダメージアニメーションから移動アニメーションへ | |
void DamageEnd() | |
{ | |
animator.SetBool("Damage", false); | |
action = Action.Chase; | |
} | |
//POSE30のアニメーションイベントで呼ばれる | |
//Invokeで指定した秒数の後にAttackEndAnimが呼ばれる | |
void AttackEnd() | |
{ | |
//attackTime秒後にAttackEndAnimを呼ぶ | |
Invoke("AttackEndAnim", attackTime); | |
} | |
//追跡モードに戻す | |
//パンチアニメーションから移動アニメーションへ | |
//攻撃判定のオブジェクトをしまう | |
void AttackEndAnim() | |
{ | |
animator.SetBool("Attack", false); | |
attackJudgment.SetActive(false); | |
action = Action.Chase; | |
} | |
} |
列挙型(Enum)のWateが待機モード。
プレイヤーのAttackPointオブジェクトに触れるとChaseになりプレイヤーを追跡します。
そしてプレイヤーのColliderに触れると攻撃し、決められた時間が経つとReturnになりスタート地点に戻ります。
コピーしたユニティちゃんにスクリプトをアタッチしたら、InspectorからAttackPointを入れてください。
これで終わりですがちゃんと動いたでしょうか?
■関連記事
【UnityC#講座】ユニティちゃんにキソラちゃんがついてくるようにする【NavMeshAgent、Blend Tree】
【UnityC#講座】ユニティちゃんたちをドラクエっぽく一列に移動や順番変更させる【List、for文、NavMeshAgent】
【UnityC#講座】近づいたら追いかけてくる巡回ユニティちゃん【NavMeshAgent】
【UnityC#講座】見つけたら追いかけてくる監視ユニティちゃん【NavMeshAgent】
【UnityC#講座】ユニティちゃんをモブキャラのごとくランダム移動させる【NavMeshAgent】
この作品はユニティちゃんライセンス条項の元に提供されています
スポンサーリンク