今回は主人公キャラクターが武器を構えた時に一番近い敵の方向を向くようにします。
今まではユーザーが主人公キャラクターを操作し、敵の方向を向かせ、攻撃をしていました。
しかし、もっと単純に武器を構えたら一番近い敵の方向を向かせて、左右の方向キーを押したら別の近い敵にターゲットを変更します。
市販のゲームで言うと昔のバイオハザードみたいな感じになります。
昔のバイオハザードがどんな感じだったか今となってはあまり覚えていないんですが・・・・(^_^;)
あとはSIRENも近いかも!?
今回の機能を作成すると、
↑のような感じで攻撃をする為に構えた時、ターゲットの方向を向かせる事が出来ます。
左右のキーを押した場合は主人公の検知エリア内にいる敵の中から一番角度が近い敵の方向を向いています。
検知エリア内にいる敵でも主人公との間に壁があった場合はその敵はターゲットには設定出来ないようにします。
敵の方向を向く機能の実現方法を考える
まずは機能を実現する為の方法を考えます。
主人公の子要素に敵をサーチするエリアを作成し、そのエリアに入った敵をゲームオブジェクトのリストに保存します。
格納された敵のゲームオブジェクトの中から主人公と一番近い敵を最初のターゲットに設定します。
次に一番近いターゲットを狙っている時に左右の方向キーを押したら別の敵をターゲットにします。
ユーザーが左の方向キーを押したら左側、右の方向キーを押したら右側にいる敵を調べ、
主人公から見て一番角度が小さい敵を次のターゲットにします。
敵をサーチするエリアから敵が出た場合はゲームオブジェクトのリストからその敵のゲームオブジェクトを削除します。
敵をサーチするエリアの作成
それではまず主人公の子要素に敵をサーチするエリアを作成していきましょう。
主人公キャラクターの子要素に右クリック→Create Emptyで空のゲームオブジェクトを作成し名前をSearchEnemyとします。
SearchEnemyにインスペクタのAdd Component→Physics→Sphere Colliderを追加します。
コライダは衝突させず検知するだけのエリアとして使うのでIs Triggerにチェックを入れておきます。
Sphere ColliderのRadiusはご自分の好みに合わせて変更してください。
ここで注意しなければいけないのはBox Collider等の角ばったコライダを設定してはいけない事です。
例えばBox Colliderをキャラクターに設置した場合、キャラクターが回転している間に敵がサーチエリアを出てしまうからです。
Sphere Colliderならば回転している間も範囲から外れる事がないので大丈夫です。
また敵をサーチするSearchEnemyスクリプトを新しく作り設定します。
上がSphere Colliderの範囲です。
Sphere Colliderは上の画像のように丸いのでキャラクターが回転中も敵が範囲外に出る事はありません。
ターゲットを選択するスクリプトSearchEnemyの作成
それではターゲットを選択するスクリプトSearchEnemyを作成していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | using UnityEngine; using System.Collections; using System.Collections.Generic; public class SearchEnemy : MonoBehaviour { // サーチした敵を入れる [SerializeField] private List<GameObject> enemyList; // 現在標的にしている敵 [SerializeField] private GameObject nowTarget; // 主人公操作スクリプト private RotateEnemyChara rotateEnemyChara; void Start() { enemyList = new List<GameObject>(); nowTarget = null; rotateEnemyChara = GetComponentInParent<RotateEnemyChara>(); } void Update() { // ターゲットがいる場合に左右のキーを押したらターゲットを変える TargetOthers(); } void TargetOthers() { // 一人も敵を登録していなければ何もしない if (enemyList.Count == 0) { nowTarget = null; return; } // 主人公が攻撃の構えをしていない、回転中、左右の方向キーが押されていない時 if (rotateEnemyChara.GetState() != RotateEnemyChara.State.WaitShot || rotateEnemyChara.IsRotate() || Mathf.Approximately(Input.GetAxis("Horizontal"), 0f) ) { return; } float inputHorizontal = Input.GetAxis("Horizontal"); // ターゲットのゲームオブジェクト GameObject nearTarget = null; // 主人公と現在のターゲットとの角度 float nearTargetAngle = 360f; foreach (var enemy in enemyList) { // この敵が現在のターゲットの時、または主人公と敵との間に壁があれば何もしない if (enemy == nowTarget || Physics.Linecast(transform.parent.transform.position + Vector3.up, enemy.transform.position + Vector3.up, LayerMask.GetMask("Field"))) { continue; } // 今調べている敵と主人公との角度を設定 float targetAngle = Vector3.SignedAngle(transform.parent.forward, enemy.transform.position - transform.parent.position, Vector3.up); // 現在ターゲットにしている敵と主人公との角度を設定(設定されていない時はエラーになるので回避) if (nearTarget != null) { nearTargetAngle = Vector3.SignedAngle(transform.parent.forward, nearTarget.transform.position - transform.parent.position, Vector3.up); } // 左を押した時でターゲットが真後ろから左側の角度が返ってきた時、または // 右を押した時でターゲットが真後ろから右側の角度が返ってきた時 if ((inputHorizontal < 0f && -180f <= targetAngle && targetAngle <= 0f) || (inputHorizontal > 0f && 0f <= targetAngle && targetAngle <= 180f) ) { if (nearTarget == null) { nearTarget = enemy; } else if (Mathf.Abs(targetAngle) < Mathf.Abs(nearTargetAngle)) { nearTarget = enemy; } } } // 近くのターゲットがいれば設定 if (nearTarget != null) { nowTarget = nearTarget; } } void OnTriggerStay(Collider col) { Debug.DrawLine(transform.parent.position + Vector3.up, col.gameObject.transform.position + Vector3.up, Color.blue); // 敵を登録する if (col.tag == "Enemy" && !enemyList.Contains(col.gameObject) ) { enemyList.Add(col.gameObject); } } void OnTriggerExit(Collider col) { // 敵がサーチエリアを抜けたらリストから削除 if (col.tag == "Enemy" && enemyList.Contains(col.gameObject) ) { // ターゲットになっていたらターゲットを解除 if (col.gameObject == nowTarget) { nowTarget = null; } enemyList.Remove(col.gameObject); } } // 現在のターゲットを返す public GameObject GetNowTarget() { return nowTarget; } // 敵が死んだ時に呼び出して敵をリストから外す void DeleteEnemyList(GameObject obj) { if (nowTarget == obj) { nowTarget = null; } enemyList.Remove(obj); } // ターゲットを設定 public void SetNowTarget() { // 一番近い敵を標的に設定する foreach (var enemy in enemyList) { // ターゲットがいなくて敵との間に壁がなければターゲットにする if (nowTarget == null) { if (!Physics.Linecast(transform.parent.position + Vector3.up, enemy.transform.position + Vector3.up, LayerMask.GetMask("Field"))) { nowTarget = enemy; } // ターゲットがいる場合で今の敵の方が近ければ今の敵をターゲットにする } else if (Vector3.Distance(transform.parent.position, enemy.transform.position) < Vector3.Distance(transform.parent.position, nowTarget.transform.position) && !Physics.Linecast(transform.parent.position + Vector3.up, enemy.transform.position + Vector3.up, LayerMask.GetMask("Field")) ) { nowTarget = enemy; } } } } |
スクリプトが長いので細かく見ていきます。
フィールド宣言とStartメソッド
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // サーチした敵を入れる [SerializeField] private List<GameObject> enemyLists; // 現在標的にしている敵 [SerializeField] private GameObject nowTarget; // 主人公操作スクリプト private RotateEnemyChara rotateEnemyChara; void Start () { enemyLists = new List<GameObject>(); nowTarget = null; rotateEnemyChara = GetComponentInParent<RotateEnemyChara>(); } |
enemyListsとnowTargetをSerializeFieldアトリビュートを付けて宣言したのはUnityの実行中に値を確認する為です。
enemyListsはリストを使い主人公の検知エリア内にいる敵を登録したり削除したりします。
StartメソッドではListのオブジェクトの作成と現在のターゲットであるnowTargetの初期化、キャラクター操作スクリプトの取得をしています。
UpdateメソッドとTargetOthersメソッド
UpdateメソッドはTargetOthersメソッドを呼び出しているだけです。
TargetOthersメソッドでは主人公が攻撃の為に構えている状態で左右のキーを押した時に検知エリア内にいる別の敵をターゲットに変える処理です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | void Update() { // ターゲットがいる場合に左右のキーを押したらターゲットを変える TargetOthers(); } void TargetOthers() { // 一人も敵を登録していなければ何もしない if (enemyList.Count == 0) { nowTarget = null; return; } // 主人公が攻撃の構えをしていない、回転中、左右の方向キーが押されていない時 if (rotateEnemyChara.GetState() != RotateEnemyChara.State.WaitShot || rotateEnemyChara.IsRotate() || Mathf.Approximately(Input.GetAxis("Horizontal"), 0f) ) { return; } float inputHorizontal = Input.GetAxis("Horizontal"); // ターゲットのゲームオブジェクト GameObject nearTarget = null; // 主人公と現在のターゲットとの角度 float nearTargetAngle = 360f; foreach (var enemy in enemyList) { // この敵が現在のターゲットの時、または主人公と敵との間に壁があれば何もしない if (enemy == nowTarget || Physics.Linecast(transform.parent.transform.position + Vector3.up, enemy.transform.position + Vector3.up, LayerMask.GetMask("Field"))) { continue; } // 今調べている敵と主人公との角度を設定 float targetAngle = Vector3.SignedAngle(transform.parent.forward, enemy.transform.position - transform.parent.position, Vector3.up); // 現在ターゲットにしている敵と主人公との角度を設定(設定されていない時はエラーになるので回避) if (nearTarget != null) { nearTargetAngle = Vector3.SignedAngle(transform.parent.forward, nearTarget.transform.position - transform.parent.position, Vector3.up); } // 左を押した時でターゲットが真後ろから左側の角度が返ってきた時、または // 右を押した時でターゲットが真後ろから右側の角度が返ってきた時 if ((inputHorizontal < 0f && -180f <= targetAngle && targetAngle <= 0f) || (inputHorizontal > 0f && 0f <= targetAngle && targetAngle <= 180f) ) { if (nearTarget == null) { nearTarget = enemy; } else if (Mathf.Abs(targetAngle) < Mathf.Abs(nearTargetAngle)) { nearTarget = enemy; } } } // 近くのターゲットがいれば設定 if (nearTarget != null) { nowTarget = nearTarget; } } |
最初に検知エリア内にいる敵がいなければターゲットを設定する事は出来ない為、returnでそれ以降の処理はしません。
次に主人公が攻撃をする為に構える状態でない、またはターゲットを変更する為回転中、左右のキーを押していない時もreturnでそれ以降の処理はしません。
それらの条件を抜けた場合は敵のリストに登録されている敵を調べます。
調べている敵がすでにターゲットである時、またはその敵にレイを飛ばして間に壁があった場合はcontinueでそれ以降の処理を飛ばし次の敵を調べます。
人型キャラクターの基底値は足元になっているので、Vector3.upを使って1mだけ上に移動した位置からレイを飛ばします。
これはDebug.DrawLineでレイを視覚的に確認出来るのでどこからどこにレイを飛ばしているか確認してください。
Unityの実行中にレイを確認するにはGizmosを有効にすると確認出来ます。
(Gizmosの右の下矢印を押すと視覚化するものを選択出来ます)
主人公の位置にVector3.up(Vector3(0, 1, 0))を足した位置からサーチエリア内にいる敵の位置+Vector3.upの位置にレイが飛んでいます。
主人公の向いている方向と敵の方向から角度を求めます。
1 2 3 4 5 6 7 8 | // 今調べている敵と主人公との角度を設定 float targetAngle = Vector3.SignedAngle(transform.parent.forward, enemy.transform.position - transform.parent.position, Vector3.up); // 現在ターゲットにしている敵と主人公との角度を設定(設定されていない時はエラーになるので回避) if (nearTarget != null) { nearTargetAngle = Vector3.SignedAngle(transform.parent.forward, nearTarget.transform.position - transform.parent.position, Vector3.up); } |
主人公と今調べている敵の角度と、主人公と今のところ一番角度が小さい敵の角度を求めています。
次に左右のどちらのキーを押したかで処理を分岐させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 左を押した時でターゲットが真後ろから左側の角度が返ってきた時、または // 右を押した時でターゲットが真後ろから右側の角度が返ってきた時 if ((inputHorizontal < 0f && -180f <= targetAngle && targetAngle <= 0f) || (inputHorizontal > 0f && 0f <= targetAngle && targetAngle <= 180f) ) { if (nearTarget == null) { nearTarget = enemy; } else if (Mathf.Abs(targetAngle) < Mathf.Abs(nearTargetAngle)) { nearTarget = enemy; } } |
主人公が見ている方向から左側は-180~0、右側は0~180が角度として返ってくるので、その値を使って向いている方向から一番近い敵を探します。
左のキーを押している時でtargetAngleが-180から0の間の場合と、右のキーを押している時でtargetAngleが0から180の間の場合のみターゲットにします。
今見ている敵との角度と今のところ一番角度が近い敵を調べ、今見ている敵の角度の方が近かったらその敵をnearTargetに入れます。
Mathf.Absで絶対値が求められます。
敵検知などのメソッド
後は敵を検知するメソッド等をみていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | void OnTriggerStay(Collider col) { Debug.DrawLine(transform.parent.position + Vector3.up, col.gameObject.transform.position + Vector3.up, Color.blue); // 敵を登録する if (col.tag == "Enemy" && !enemyList.Contains(col.gameObject) ) { enemyList.Add(col.gameObject); } } void OnTriggerExit(Collider col) { // 敵がサーチエリアを抜けたらリストから削除 if (col.tag == "Enemy" && enemyList.Contains(col.gameObject) ) { // ターゲットになっていたらターゲットを解除 if (col.gameObject == nowTarget) { nowTarget = null; } enemyList.Remove(col.gameObject); } } // 現在のターゲットを返す public GameObject GetNowTarget() { return nowTarget; } // 敵が死んだ時に呼び出して敵をリストから外す void DeleteEnemyList(GameObject obj) { if (nowTarget == obj) { nowTarget = null; } enemyList.Remove(obj); } // ターゲットを設定 public void SetNowTarget() { // 一番近い敵を標的に設定する foreach (var enemy in enemyList) { // ターゲットがいなくて敵との間に壁がなければターゲットにする if (nowTarget == null) { if (!Physics.Linecast(transform.parent.position + Vector3.up, enemy.transform.position + Vector3.up, LayerMask.GetMask("Field"))) { nowTarget = enemy; } // ターゲットがいる場合で今の敵の方が近ければ今の敵をターゲットにする } else if (Vector3.Distance(transform.parent.position, enemy.transform.position) < Vector3.Distance(transform.parent.position, nowTarget.transform.position) && !Physics.Linecast(transform.parent.position + Vector3.up, enemy.transform.position + Vector3.up, LayerMask.GetMask("Field")) ) { nowTarget = enemy; } } } |
OnTriggerStayメソッドで検知エリアに入った敵を調べ、enemyListsに登録します。
OnTriggerExitメソッドでは敵が検知エリアから出て行った時にnowTargetに設定されていれば解除し、enemyListsから削除します。
SetNowTargetメソッドはキャラクター操作スクリプトから呼び出し、現在のターゲットを設定します。
これでターゲットを指定するスクリプトが完成しました。
キャラクター操作スクリプトの作成
次はキャラクター操作スクリプトを作成します。
この記事用にRotateEnemyCharaスクリプトを作成しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | using UnityEngine; using System.Collections; public class RotateEnemyChara : MonoBehaviour { public enum State { Normal, WaitShot, } private CharacterController characterController; private Animator animator; private Vector3 velocity = Vector3.zero; [SerializeField] private float walkSpeed = 1.5f; [SerializeField] private State state; // キャラの回転スピード [SerializeField] private float charaRotateSpeed = 45f; // 敵サーチスクリプト private SearchEnemy searchEnemy; // 回転中かどうか [SerializeField] private bool isRotate = false; // 敵の方向を向いたとする角度 [SerializeField] private float unLockAngle = 1f; // Use this for initialization void Start () { characterController = GetComponent <CharacterController> (); animator = GetComponent <Animator> (); searchEnemy = GetComponentInChildren <SearchEnemy> (); state = State.Normal; } // Update is called once per frame void Update () { if (state == State.Normal) { if (characterController.isGrounded) { velocity = Vector3.zero; var input = new Vector3 (Input.GetAxis ("Horizontal"), 0f, Input.GetAxis ("Vertical")); if (input.magnitude > 0f) { animator.SetFloat ("Speed", input.magnitude); transform.LookAt (transform.position + input); velocity = transform.forward * walkSpeed; } else { animator.SetFloat ("Speed", 0f); } if (Input.GetButtonDown ("Fire2")) { searchEnemy.SetNowTarget (); SetState (State.WaitShot); } } } else if (state == State.WaitShot) { // ターゲットを自動で変更する処理 if (searchEnemy.GetNowTarget ()) { isRotate = true; // キャラクターの向きを変える var targetRotation = Quaternion.LookRotation (searchEnemy.GetNowTarget ().transform.position - transform.position); targetRotation = Quaternion.Euler (0f, targetRotation.eulerAngles.y, 0f); transform.rotation = Quaternion.Lerp (transform.rotation, targetRotation, charaRotateSpeed * Time.deltaTime); // ロックを解除する条件 if (Mathf.Abs (transform.eulerAngles.y - Quaternion.LookRotation (searchEnemy.GetNowTarget ().transform.position - transform.position).eulerAngles.y) < unLockAngle) { isRotate = false; animator.SetFloat ("Speed", 0f); } } if (!Input.GetButton ("Fire2")) { SetState (State.Normal); } } velocity.y += Physics.gravity.y * Time.deltaTime; characterController.Move (velocity * Time.deltaTime); } public void SetState(State state) { this.state = state; velocity = Vector3.zero; if (state == State.WaitShot) { animator.SetFloat ("Speed", 0f); } } public State GetState() { return state; } // 回転中かどうかを返す public bool IsRotate() { return isRotate; } } |
長いので一部説明していきます。
キャラクターの状態がノーマル状態の時にFire2ボタン(デフォルトではマウスの右クリック)を押したらSearchEnemyスクリプトのSetNowTargetメソッドを呼び出し、ターゲットの設定をします。
その後、攻撃をする為に構える状態へと変更します。
1 2 3 4 5 6 | if (Input.GetButtonDown ("Fire2")) { searchEnemy.SetNowTarget (); SetState (State.WaitShot); } |
攻撃をする為に構えている状態の時は
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | } else if (state == State.WaitShot) { // ターゲットを自動で変更する処理 if (searchEnemy.GetNowTarget ()) { isRotate = true; // キャラクターの向きを変える var targetRotation = Quaternion.LookRotation (searchEnemy.GetNowTarget ().transform.position - transform.position); targetRotation = Quaternion.Euler (0f, targetRotation.eulerAngles.y, 0f); transform.rotation = Quaternion.Lerp (transform.rotation, targetRotation, charaRotateSpeed * Time.deltaTime); // ロックを解除する条件 if (Mathf.Abs (transform.eulerAngles.y - Quaternion.LookRotation (searchEnemy.GetNowTarget ().transform.position - transform.position).eulerAngles.y) < unLockAngle) { isRotate = false; animator.SetFloat ("Speed", 0f); } } if (!Input.GetButton ("Fire2")) { SetState (State.Normal); } } |
SearchEnemyスクリプトのGetNowTargetでターゲットがいる場合は回転中フラグをオンにし、キャラクターのY軸の角度を変更します。
主人公のY軸の角度とターゲットのY軸の角度がロック解除をする角度以下になったら回転中のフラグをオフにします。
ターゲットにする敵を変更出来るか確認する
これで処理が出来たので確認してみましょう。
上のように設定しました。
上のように左右の方向キーを押すとターゲットにする敵を変更します。
が、これだと人の下に回転盤でもあるかのようにクルッと回転してしまうので、ターゲットに向けて回転している間は
下半身のアニメーションを足踏みのものに変更しましょう。
体の一部のアニメーションを変更して違和感をなくす
体の一部のアニメーションを変更する方法は

を参照してください。
上のようにLower Layerという名前でアニメーターのレイヤーを作成します。
Assetsフォルダで右クリック→Create→Avatar Maskを選択し名前をLower Avatarとし、インスペクタで上のように設定します。
Lower Layerの右の歯車を押して、上の画面を開きLower Avatarを設定します。
Weightは1に設定しておきます。
Lower Layerの状態遷移を上のように作成します。
あ・・・名前を変更するのを忘れてNew Stateのままになっていますが・・・、Idle等のわかりやすい名前を付けてください。
New Stateのアニメーションクリップは何も設定しません。
Rotate Walkのアニメーションクリップは足踏みをするようなアニメーションを選択します(歩くアニメーションでOK)
アニメーションパラメータにRotateWalkをbool型で作成しておき、RotateWalkがtrueになったらRotateWalkに遷移するようにします。
RotateWalkがfalseになった時にNew Stateに遷移させます。
上がNew State→Rotate Walkの遷移のインスペクタです。
最後にキャラクター操作スクリプトでアニメーションパラメータのRotateWalkのOn・Offの処理を追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | } else if (state == State.WaitShot) { // ターゲットを自動で変更する処理 if (searchEnemy.GetNowTarget ()) { animator.SetBool("RotateWalk", true); isRotate = true; // キャラクターの向きを変える var targetRotation = Quaternion.LookRotation (searchEnemy.GetNowTarget ().transform.position - transform.position); targetRotation = Quaternion.Euler (0f, targetRotation.eulerAngles.y, 0f); transform.rotation = Quaternion.Lerp (transform.rotation, targetRotation, charaRotateSpeed * Time.deltaTime); // ロックを解除する条件 if (Mathf.Abs (transform.eulerAngles.y - Quaternion.LookRotation (searchEnemy.GetNowTarget ().transform.position - transform.position).eulerAngles.y) < unLockAngle) { animator.SetBool("RotateWalk", false); isRotate = false; animator.SetFloat ("Speed", 0f); } } if (!Input.GetButton ("Fire2")) { SetState (State.Normal); } } |
↑のようにRotateWalkアニメーションパラメータを操作します。
これで体の一部のアニメーション変更処理が終わったのでUnityの実行ボタンを押して確認してみましょう。
上のように下半身は歩くアニメーションが再生されるようになりました。
もっと細かく作りたい場合は左向きに回転する時、右向きに回転する時のアニメーションを変更するといいかもしれません。
細かいアニメーション設定をしたい方は

を参考にしてください。
これでUnityのアクションゲームで攻撃時に敵の方向をむかせる機能が完成しました。
左右の方向キーを押した時にターゲットを変更する処理が結構大変でした・・・(^_^;)
今回のターゲットの変更の仕方は向いている方向に一番近い敵ですが、方向ではなく一番近い距離にいる敵とする事も出来ます。
その場合は回転でターゲットを選択するのではなく距離で計算する事で実現できますので、やってみてください。