Created
October 15, 2017 13:12
-
-
Save urahimono/5c8ffa4c5e1bd819c196e43195acd803 to your computer and use it in GitHub Desktop.
【Unity】NavMeshを学ぶ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//------------------------------------------------------------------------ | |
// | |
// (C) Copyright 2017 Urahimono Project Inc. | |
// | |
//------------------------------------------------------------------------ | |
using UnityEngine; | |
using UnityEngine.AI; | |
using System.Collections; | |
[RequireComponent( typeof( NavMeshAgent ) )] | |
public class ObjectController : MonoBehaviour | |
{ | |
[SerializeField] | |
private Transform[] m_targets = null; | |
[SerializeField] | |
private float m_destinationThreshold = 0.0f; | |
protected NavMeshAgent m_navAgent = null; | |
private int m_targetIndex = 0; | |
private Vector3 CurretTargetPosition | |
{ | |
get | |
{ | |
if( m_targets == null || m_targets.Length <= m_targetIndex ) | |
{ | |
return Vector3.zero; | |
} | |
return m_targets[ m_targetIndex ].position; | |
} | |
} | |
protected virtual void Start() | |
{ | |
m_navAgent = GetComponent<NavMeshAgent>(); | |
m_navAgent.destination = CurretTargetPosition; | |
StartCoroutine( UpdateOffMeshLink() ); | |
} | |
private void Update() | |
{ | |
if( m_navAgent.remainingDistance <= m_destinationThreshold ) | |
{ | |
m_targetIndex = ( m_targetIndex + 1 ) % m_targets.Length; | |
m_navAgent.destination = CurretTargetPosition; | |
} | |
} | |
private IEnumerator UpdateOffMeshLink() | |
{ | |
// オフメッシュリンクの挙動が自動モードの場合は、この処理は行わない。 | |
if( m_navAgent.autoTraverseOffMeshLink ) | |
{ | |
yield break; | |
} | |
while( true ) | |
{ | |
// オフメッシュリンクに乗るまで待機。 | |
while( !m_navAgent.isOnOffMeshLink ) | |
{ | |
yield return null; | |
} | |
// NavMeshの挙動を止めます。 | |
// Stop()はObsoleteになったようなので使わないよ。 | |
m_navAgent.isStopped = true; | |
// オフメッシュリンクと高さに差があるので、ちょっと微調整。 | |
OffMeshLinkData offMeshLinkData = m_navAgent.currentOffMeshLinkData; | |
Vector3 targetPos = offMeshLinkData.endPos; | |
targetPos.y += transform.position.y - offMeshLinkData.startPos.y; | |
yield return OffMeshLinkProcess( targetPos ); | |
// オフメッシュリンクの計算を完了する。 | |
m_navAgent.CompleteOffMeshLink(); | |
// NavMeshの挙動を再開する。 | |
// Resume()はObsoleteになったようなので使わないよ。 | |
m_navAgent.isStopped = false; | |
} | |
} | |
protected virtual IEnumerator OffMeshLinkProcess( Vector3 i_targetPos ) | |
{ | |
yield return null; | |
} | |
} // class ObjectController |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//------------------------------------------------------------------------ | |
// | |
// (C) Copyright 2017 Urahimono Project Inc. | |
// | |
//------------------------------------------------------------------------ | |
using UnityEngine; | |
using UnityEngine.AI; | |
using System.Collections; | |
[RequireComponent( typeof( NavMeshAgent ) )] | |
[RequireComponent( typeof( Rigidbody ) )] | |
public class ObjectJumpController : ObjectController | |
{ | |
[SerializeField] | |
private float m_jumpTime = 0.0f; | |
private Rigidbody m_rigidbody = null; | |
protected override void Start() | |
{ | |
base.Start(); | |
// 放物線の挙動のためにRigidbodyを使う。 | |
// NavMeshAgentを使っているときは使いたくないので、 | |
// isKinematicを有効にしてRigidbodyの無効化する。 | |
m_rigidbody = GetComponent<Rigidbody>(); | |
m_rigidbody.isKinematic = true; | |
} | |
protected override IEnumerator OffMeshLinkProcess( Vector3 i_targetPos ) | |
{ | |
m_rigidbody.isKinematic = false; | |
m_rigidbody.velocity = Vector3.zero; | |
ShootFixedTime( i_targetPos, m_jumpTime ); | |
yield return new WaitForSeconds( m_jumpTime ); | |
transform.position = i_targetPos; | |
m_rigidbody.isKinematic = true; | |
m_rigidbody.velocity = Vector3.zero; | |
} | |
private void ShootFixedTime( Vector3 i_targetPosition, float i_time ) | |
{ | |
float speedVec = ComputeVectorFromTime( i_targetPosition, i_time ); | |
float angle = ComputeAngleFromTime( i_targetPosition, i_time ); | |
if( speedVec <= 0.0f ) | |
{ | |
// その位置に着地させることは不可能のようだ! | |
Debug.LogWarning( "!!" ); | |
return; | |
} | |
Vector3 vec = ConvertVectorToVector3( speedVec, angle, i_targetPosition ); | |
SetRigidbody( vec ); | |
} | |
private Vector3 ConvertVectorToVector3( float i_v0, float i_angle, Vector3 i_targetPosition ) | |
{ | |
Vector3 startPos = transform.position; | |
Vector3 targetPos = i_targetPosition; | |
startPos.y = 0.0f; | |
targetPos.y = 0.0f; | |
Vector3 dir = ( targetPos - startPos ).normalized; | |
Quaternion yawRot = Quaternion.FromToRotation( Vector3.right, dir ); | |
Vector3 vec = i_v0 * Vector3.right; | |
vec = yawRot * Quaternion.AngleAxis( i_angle, Vector3.forward ) * vec; | |
return vec; | |
} | |
private float ComputeVectorFromTime( Vector3 i_targetPosition, float i_time ) | |
{ | |
Vector2 vec = ComputeVectorXYFromTime( i_targetPosition, i_time ); | |
float v_x = vec.x; | |
float v_y = vec.y; | |
float v0Square = v_x * v_x + v_y * v_y; | |
// 負数を平方根計算すると虚数になってしまう。 | |
// 虚数はfloatでは表現できない。 | |
// こういう場合はこれ以上の計算は打ち切ろう。 | |
if( v0Square <= 0.0f ) | |
{ | |
return 0.0f; | |
} | |
float v0 = Mathf.Sqrt( v0Square ); | |
return v0; | |
} | |
private float ComputeAngleFromTime( Vector3 i_targetPosition, float i_time ) | |
{ | |
Vector2 vec = ComputeVectorXYFromTime( i_targetPosition, i_time ); | |
float v_x = vec.x; | |
float v_y = vec.y; | |
float rad = Mathf.Atan2( v_y, v_x ); | |
float angle = rad * Mathf.Rad2Deg; | |
return angle; | |
} | |
private Vector2 ComputeVectorXYFromTime( Vector3 i_targetPosition, float i_time ) | |
{ | |
// 瞬間移動はちょっと……。 | |
if( i_time <= 0.0f ) | |
{ | |
return Vector2.zero; | |
} | |
// xz平面の距離を計算。 | |
Vector2 startPos = new Vector2( transform.position.x, transform.position.z ); | |
Vector2 targetPos = new Vector2( i_targetPosition.x, i_targetPosition.z ); | |
float distance = Vector2.Distance( targetPos, startPos ); | |
float x = distance; | |
// な、なぜ重力を反転せねばならないのだ... | |
float g = -Physics.gravity.y; | |
float y0 = transform.position.y; | |
float y = i_targetPosition.y; | |
float t = i_time; | |
float v_x = x / t; | |
float v_y = ( y - y0 ) / t + ( g * t ) / 2; | |
return new Vector2( v_x, v_y ); | |
} | |
private void SetRigidbody( Vector3 i_shootVector ) | |
{ | |
// 速さベクトルのままAddForce()を渡してはいけないぞ。力(速さ×重さ)に変換するんだ | |
Vector3 force = i_shootVector * m_rigidbody.mass; | |
m_rigidbody.AddForce( force, ForceMode.Impulse ); | |
} | |
} // class ObjectJumpController |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//------------------------------------------------------------------------ | |
// | |
// (C) Copyright 2017 Urahimono Project Inc. | |
// | |
//------------------------------------------------------------------------ | |
using UnityEngine; | |
using UnityEngine.AI; | |
using System.Collections; | |
[RequireComponent( typeof( NavMeshAgent ) )] | |
public class ObjectWarpController : ObjectController | |
{ | |
[SerializeField] | |
private float m_scaleTime = 0.0f; | |
[SerializeField] | |
private float m_waitTime = 0.0f; | |
protected override IEnumerator OffMeshLinkProcess( Vector3 i_targetPos ) | |
{ | |
Vector3 defaultScale = transform.localScale; | |
yield return new WaitForSeconds( m_waitTime ); | |
yield return ScaleProcess( Vector3.zero, m_scaleTime ); | |
yield return new WaitForSeconds( m_waitTime ); | |
transform.position = i_targetPos; | |
yield return ScaleProcess( defaultScale, m_scaleTime ); | |
yield return new WaitForSeconds( m_waitTime ); | |
} | |
private IEnumerator ScaleProcess( Vector3 i_toScale, float i_time ) | |
{ | |
Vector3 fromScale = transform.localScale; | |
float startTime = Time.time; | |
float endTime = startTime + i_time; | |
while( Time.time < endTime ) | |
{ | |
float elapsedTime = Time.time - startTime; | |
float elapsedRate = elapsedTime / i_time; | |
Vector3 scale = Vector3.Lerp( fromScale, i_toScale, elapsedRate ); | |
transform.localScale = scale; | |
yield return null; | |
} | |
transform.localScale = i_toScale; | |
} | |
} // class ObjectWarpController |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment