Skip to content

Instantly share code, notes, and snippets.

@onionmk2
Created July 19, 2017 21:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save onionmk2/82094e3c6cc2fc2e13af05368ca49810 to your computer and use it in GitHub Desktop.
Save onionmk2/82094e3c6cc2fc2e13af05368ca49810 to your computer and use it in GitHub Desktop.
public override TaskStatus OnUpdate()
{
var playerTransform = GetComponent<EnemyStore>().playerTransform;
var distanceFromPlayer = Vector3.Distance(playerTransform.position, transform.position);
// slow down until speed becomes zero.
if (distanceFromPlayer <= GlobalConst.maxRangeOfPlayerNear)
{
GetComponent<Animator>().applyRootMotion = false;
//減速を始めた場合、以降プレイヤーが移動したとしても、agentの目的地を更新しない(パス検索は重いので1回で済ませたいため。)。
if (!slowDownSetupFinished)
{
// 初速
var initialSpeed = navMeshAgent.velocity.magnitude;
// 終末速度
var endSpeed = 0f;
// 変位(減速を開始する地点から静止する地点の間の距離)
var deltaOfDistance = GlobalConst.maxRangeOfPlayerNear - GlobalConst.maxRangeOfPlayerAround;
acceleration = (Mathf.Pow(endSpeed, 2) - Mathf.Pow(initialSpeed, 2)) / (2 * deltaOfDistance);
slowDownStartTime = Time.time;
slowDownStartSpeed = initialSpeed;
SetDestinationAtPlayerAround();
slowDownSetupFinished = true;
}
// 等加速度運動の公式を用いて、「初速, 終末速, 変位」の3つから加速度を求める。
// 「初速、求めた加速度、経過時刻」から、現在の速さを求める。
var currentTime = Time.time - slowDownStartTime;
navMeshAgent.speed = slowDownStartSpeed + acceleration * currentTime;
if (navMeshAgent.speed < Mathf.Epsilon)
{
navMeshAgent.isStopped = true;
}
return TaskStatus.Running;
}
// Run
else
{
GetComponent<Animator>().applyRootMotion = false;
slowDownSetupFinished = false;
navMeshAgent.speed = GlobalConst.maxEnemyRunVelocity;
navMeshAgent.SetDestination(playerTransform.position);
navMeshAgent.isStopped = false;
return TaskStatus.Running;
}
}
///<summary>以下の条件を満たす点に<see cref="NavMeshAgent.SetDestination"/>する。
/// 1. NavMeshPath上にある。
/// 2. <see cref="GlobalConst.maxRangeOfPlayerAround"/>地点に最も近い。
/// </summary>
/// <remarks>
/// 「Destinationはプレイヤー位置にして、距離が<see cref="GlobalConst.maxRangeOfPlayerAround"/>
/// 以下の場合<see cref="NavMeshAgent.isStopped"/>で止める」 という実装では、滑りが発生する。
/// </remarks>
private void SetDestinationAtPlayerAround()
{
var playerPosition = GetComponent<EnemyStore>().playerTransform.position;
NavMeshPath path = new NavMeshPath();
var hasPath = navMeshAgent.CalculatePath(playerPosition, path);
if(!hasPath) Debug.Log("敵も自機もnavMesh上にしか居れないので、ここにはこないはず");
var distancesBetweenCornerPointAndAroundPoint = path.corners
.Select((corner) => Vector3.Distance(corner, playerPosition))
.Select(distance => Mathf.Abs(distance - GlobalConst.maxRangeOfPlayerAround))
.ToArray();
var minDistIndex = Array.IndexOf(distancesBetweenCornerPointAndAroundPoint, distancesBetweenCornerPointAndAroundPoint.Min());
var closestCornerFromAroundPoint = path.corners[minDistIndex];
navMeshAgent.SetDestination(closestCornerFromAroundPoint);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment