「Unity/3d/アニメーション/追跡」の版間の差分
提供: 初心者エンジニアの簡易メモ
(→ターゲットポイントをindex順に) |
|||
(同じ利用者による、間の17版が非表示) | |||
行2: | 行2: | ||
#敵オブジェクトにAddComponentsでRigidbodyとCapsuleColliderを追加 | #敵オブジェクトにAddComponentsでRigidbodyとCapsuleColliderを追加 | ||
#床オブジェクトの(名前の横にある)staticにチェックをつける | #床オブジェクトの(名前の横にある)staticにチェックをつける | ||
− | #Window/AI/Navigationから床オブジェクトを選択し、Bakeタブを選択しBakeボタンを押す。 | + | #Unityメインメニュー/Window/AI/Navigationから床オブジェクトを選択し、Bakeタブを選択しBakeボタンを押す。 |
#敵オブジェクトのAddComponentsからNavMeshAgentを追加 | #敵オブジェクトのAddComponentsからNavMeshAgentを追加 | ||
#敵オブジェクトに以下csのようにNavMeshAgentを追加 | #敵オブジェクトに以下csのようにNavMeshAgentを追加 | ||
− | # | + | #障害物オブジェクトを設置してstaticにチェックを入れる。 |
#障害物オブジェクトにもBakeを設定する。 | #障害物オブジェクトにもBakeを設定する。 | ||
<pre> | <pre> | ||
行11: | 行11: | ||
public class EnemyController : MonoBehaviour | public class EnemyController : MonoBehaviour | ||
{ | { | ||
− | |||
NavMeshAgent agent; | NavMeshAgent agent; | ||
+ | GameObject playerObj; | ||
void Start() | void Start() | ||
{ | { | ||
− | + | playerObj = GameObject.Find("Player"); | |
+ | NavStart(); | ||
+ | } | ||
+ | // 追跡ロジック開始 | ||
+ | void NavStart() | ||
+ | { | ||
if (GetComponent<NavMeshAgent>() != null) | if (GetComponent<NavMeshAgent>() != null) | ||
{ | { | ||
行25: | 行30: | ||
void Update() | void Update() | ||
{ | { | ||
− | + | NavUpdate(); | |
− | if ( | + | } |
+ | // 追跡ロジック | ||
+ | void NavUpdate() | ||
+ | { | ||
+ | if (playerObj != null && agent != null) | ||
{ | { | ||
− | agent.SetDestination( | + | agent.SetDestination(playerObj.transform.position); |
} | } | ||
} | } | ||
行40: | 行49: | ||
==正面を向いて追跡== | ==正面を向いて追跡== | ||
<pre> | <pre> | ||
− | + | GameObject playerObj; | |
− | + | float speed = 0.1f; | |
void Start () { | void Start () { | ||
− | + | playerObj = GameObject.Find("Player"); | |
} | } | ||
void Update() { | void Update() { | ||
− | + | transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(playerObj.transform.position - transform.position), 0.3f); | |
− | + | transform.position += transform.forward * speed; | |
} | } | ||
</pre> | </pre> | ||
行53: | 行62: | ||
接触判定させる場合で、追いついて回転して、接触判定しないときはRigidbodyが足りないのかも・・ | 接触判定させる場合で、追いついて回転して、接触判定しないときはRigidbodyが足りないのかも・・ | ||
+ | |||
+ | ==NavMeshAgent同士の接触== | ||
+ | NavMeshAgent同士の接触半径を狭める場合は、InspectorのNavMeshAgentのRadiusを0.5から小さくする | ||
+ | |||
+ | ==逃げるロジック== | ||
+ | ターゲットをいくつか用意して、そこに向かっていくように。 | ||
+ | <pre> | ||
+ | using UnityEngine.AI; | ||
+ | public class PlayerController : MonoBehaviour | ||
+ | { | ||
+ | NavMeshAgent agent; | ||
+ | float speed = 6f; | ||
+ | GameObject enemyObj; | ||
+ | GameObject targetPointGroupObj; | ||
+ | void Start() | ||
+ | { | ||
+ | enemyObj = GameObject.Find("Enemy"); | ||
+ | targetPointGroupObj = GameObject.Find("TargetPointGroup"); | ||
+ | NavStart(); | ||
+ | } | ||
+ | // 追跡ロジック開始 | ||
+ | void NavStart() | ||
+ | { | ||
+ | if (GetComponent<NavMeshAgent>() != null) | ||
+ | { | ||
+ | agent = GetComponent<NavMeshAgent>(); | ||
+ | agent.updateRotation = false; | ||
+ | agent.updatePosition = true; | ||
+ | } | ||
+ | } | ||
+ | void Update() | ||
+ | { | ||
+ | UpdateNav(); | ||
+ | UpdateLookAt(); | ||
+ | } | ||
+ | void UpdateLookAt() | ||
+ | { | ||
+ | transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(enemyObj.transform.position - transform.position), 0.3f); | ||
+ | } | ||
+ | // 追跡ロジック | ||
+ | void UpdateNav() | ||
+ | { | ||
+ | if (agent != null) | ||
+ | { | ||
+ | if (agent.pathStatus != NavMeshPathStatus.PathInvalid) | ||
+ | { | ||
+ | // agent.SetDestination(gameObject.transform.Find("Back").transform.position); | ||
+ | agent.SetDestination(GetFarTargetPointPosition()); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | // 敵から一番遠いターゲットポイントのPositionを返す | ||
+ | Vector3 GetFarTargetPointPosition() | ||
+ | { | ||
+ | float maxDistance = 0; | ||
+ | Vector3 maxDistancePosition = Vector3.zero; | ||
+ | foreach (Transform transform in targetPointGroupObj.GetComponentInChildren<Transform>()) | ||
+ | { | ||
+ | var distance = Vector3.Distance(enemyObj.transform.position, transform.position); | ||
+ | if (maxDistance < distance && transform.gameObject.activeSelf) | ||
+ | { | ||
+ | maxDistance = distance; | ||
+ | maxDistancePosition = transform.position; | ||
+ | } | ||
+ | } | ||
+ | return maxDistancePosition; | ||
+ | } | ||
+ | } | ||
+ | </pre> | ||
+ | 参考:https://yubeshicat.hatenablog.com/entry/2018/09/07/150259 | ||
+ | |||
+ | ===ターゲットポイントをindex順に=== | ||
+ | <pre> | ||
+ | GameObject targetPointGroupObj; | ||
+ | GameObject targetPointObj; | ||
+ | void Start() | ||
+ | { | ||
+ | targetPointGroupObj = GameObject.Find("TargetPointGroup"); | ||
+ | } | ||
+ | // ターゲットポイントをグループからindex順にPositionを返す | ||
+ | Vector3 GetNextTargetPointPosition() | ||
+ | { | ||
+ | if (targetPointObj != null) | ||
+ | { | ||
+ | var distance = Vector3.Distance(targetPointObj.transform.position, transform.position); | ||
+ | // ターゲットに近づいたらきり変える | ||
+ | if (distance < 10) | ||
+ | { | ||
+ | List<Transform> transforms = new List<Transform>(); | ||
+ | int index = 0; | ||
+ | foreach (Transform tmpTransform in targetPointGroupObj.GetComponentInChildren<Transform>()) | ||
+ | { | ||
+ | transforms.Add(tmpTransform); | ||
+ | if (tmpTransform.Equals(targetPointObj.transform)) | ||
+ | { | ||
+ | index = tmpTransform.GetSiblingIndex(); | ||
+ | } | ||
+ | } | ||
+ | if (index >= transforms.Count - 1) | ||
+ | { | ||
+ | targetPointObj = transforms[0].gameObject; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | targetPointObj = transforms[index + 1].gameObject; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | foreach (Transform transform in targetPointGroupObj.GetComponentInChildren<Transform>()) | ||
+ | { | ||
+ | targetPointObj = transform.gameObject; // 0番目 | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | return targetPointObj.transform.position; | ||
+ | } | ||
+ | </pre> | ||
==参考== | ==参考== |
2023年5月31日 (水) 02:48時点における最新版
追跡アクション追加
- 敵オブジェクトにAddComponentsでRigidbodyとCapsuleColliderを追加
- 床オブジェクトの(名前の横にある)staticにチェックをつける
- Unityメインメニュー/Window/AI/Navigationから床オブジェクトを選択し、Bakeタブを選択しBakeボタンを押す。
- 敵オブジェクトのAddComponentsからNavMeshAgentを追加
- 敵オブジェクトに以下csのようにNavMeshAgentを追加
- 障害物オブジェクトを設置してstaticにチェックを入れる。
- 障害物オブジェクトにもBakeを設定する。
using UnityEngine.AI; public class EnemyController : MonoBehaviour { NavMeshAgent agent; GameObject playerObj; void Start() { playerObj = GameObject.Find("Player"); NavStart(); } // 追跡ロジック開始 void NavStart() { if (GetComponent<NavMeshAgent>() != null) { agent = GetComponent<NavMeshAgent>(); agent.updateRotation = false; agent.updatePosition = true; } } void Update() { NavUpdate(); } // 追跡ロジック void NavUpdate() { if (playerObj != null && agent != null) { agent.SetDestination(playerObj.transform.position); } } }
追跡されない時
- 対象オブジェクトのscaleを変えてみる。
- bakeを再度やってみる
正面を向いて追跡
GameObject playerObj; float speed = 0.1f; void Start () { playerObj = GameObject.Find("Player"); } void Update() { transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(playerObj.transform.position - transform.position), 0.3f); transform.position += transform.forward * speed; }
参考:https://qiita.com/ganbaru/items/d4fe649370ce4451db80
接触判定させる場合で、追いついて回転して、接触判定しないときはRigidbodyが足りないのかも・・
NavMeshAgent同士の接触半径を狭める場合は、InspectorのNavMeshAgentのRadiusを0.5から小さくする
逃げるロジック
ターゲットをいくつか用意して、そこに向かっていくように。
using UnityEngine.AI; public class PlayerController : MonoBehaviour { NavMeshAgent agent; float speed = 6f; GameObject enemyObj; GameObject targetPointGroupObj; void Start() { enemyObj = GameObject.Find("Enemy"); targetPointGroupObj = GameObject.Find("TargetPointGroup"); NavStart(); } // 追跡ロジック開始 void NavStart() { if (GetComponent<NavMeshAgent>() != null) { agent = GetComponent<NavMeshAgent>(); agent.updateRotation = false; agent.updatePosition = true; } } void Update() { UpdateNav(); UpdateLookAt(); } void UpdateLookAt() { transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(enemyObj.transform.position - transform.position), 0.3f); } // 追跡ロジック void UpdateNav() { if (agent != null) { if (agent.pathStatus != NavMeshPathStatus.PathInvalid) { // agent.SetDestination(gameObject.transform.Find("Back").transform.position); agent.SetDestination(GetFarTargetPointPosition()); } } } // 敵から一番遠いターゲットポイントのPositionを返す Vector3 GetFarTargetPointPosition() { float maxDistance = 0; Vector3 maxDistancePosition = Vector3.zero; foreach (Transform transform in targetPointGroupObj.GetComponentInChildren<Transform>()) { var distance = Vector3.Distance(enemyObj.transform.position, transform.position); if (maxDistance < distance && transform.gameObject.activeSelf) { maxDistance = distance; maxDistancePosition = transform.position; } } return maxDistancePosition; } }
参考:https://yubeshicat.hatenablog.com/entry/2018/09/07/150259
ターゲットポイントをindex順に
GameObject targetPointGroupObj; GameObject targetPointObj; void Start() { targetPointGroupObj = GameObject.Find("TargetPointGroup"); } // ターゲットポイントをグループからindex順にPositionを返す Vector3 GetNextTargetPointPosition() { if (targetPointObj != null) { var distance = Vector3.Distance(targetPointObj.transform.position, transform.position); // ターゲットに近づいたらきり変える if (distance < 10) { List<Transform> transforms = new List<Transform>(); int index = 0; foreach (Transform tmpTransform in targetPointGroupObj.GetComponentInChildren<Transform>()) { transforms.Add(tmpTransform); if (tmpTransform.Equals(targetPointObj.transform)) { index = tmpTransform.GetSiblingIndex(); } } if (index >= transforms.Count - 1) { targetPointObj = transforms[0].gameObject; } else { targetPointObj = transforms[index + 1].gameObject; } } } else { foreach (Transform transform in targetPointGroupObj.GetComponentInChildren<Transform>()) { targetPointObj = transform.gameObject; // 0番目 break; } } return targetPointObj.transform.position; }