5回目・NavMeshPathとは何ぞや?
目次
- 分かったこと1・「NavMeshPath」は「NavMeshAgent」の中にある
- 分かったこと2・「NavMeshPath.corner」の扱いとVector3の使い方
- 分かったこと3・「NavMeshAgent.destination」を設定してもすぐには「NavMeshPath.corner」は作られない
- 分かったこと4・「NavMeshPath.corner」は自動更新されない
Unityの公式サイトのここを読んでみると、
http://docs.unity3d.com/ja/current/ScriptReference/NavMeshPath.html
移動方向の矢印を作るにはNavMeshPathのcornersを使うことになりそうなことまでは把握した。
ただ、その他のことは全く書いてないので手探りで理解することに。
分かったこと1・「NavMeshPath」は「NavMeshAgent」の中にある
public NavMeshAgent agent;
agent = GetComponent<NavMeshAgent>();
NavMeshPath path = agent.path;
これと
NavMeshPath path;
これは全く一緒らしい。
agentをpublicしたってとこは違うけどほぼ一緒のことをやってるらしい。
分かったこと2・「NavMeshPath.corner」の扱いとVector3の使い方
public Vector3 corners;
とUnityのサイトのNavMeshPath.cornerには書いてあるけど、
これは「corners」はVector3で書かれているってことを示しているらしい。
Vector3[]は、
Vector3[n] = (x, y, z)みたいな感じで作られていて、
Unityのサイトの感じでpath.corners [0]のxだけを参照したい時は、
path.corners [0].xとすればいいっぽい。
分かったこと3・「NavMeshAgent.destination」を設定してもすぐには「NavMeshPath.corner」は作られない
「NavMeshAgent.destination」設定後すぐに「NavMeshPath.corner」を参照しようとすると、そんなもんないと言われます。
「NavMeshAgent.hasPath」を確認することでこれが回避できます。
分かったこと4・「NavMeshPath.corner」は自動更新されない
「NavMeshAgent.destination」を設定してPlayerが移動中の場合、「NavMeshPath.corner」はどうなっているかというと、
全く更新されません。
始点と終点は直線上にあるときだと、corner[0]に始点の座標、corner[1]に終点の座標が書いてあるだけです。
「NavMeshAgent.destination」を新しく設定すれば更新されます。
4回目・プレイヤーの変数を別のオブジェクトが参照する
別のオブジェクト側のスクリプト名を「Cursor」とし、
「Player」側で下記のプログラムを書いて、
direction = (GameObject)Resources.Load ("Prefabs/Cursor");
GameObject cursor = (GameObject)Instantiate (direction);
cursor.transform.parent = transform;
「Cursor」をプレハブから生成した後、
「Cursor」のparentを「Player」にすることで、
「Player」の取得をGetComponentではなく、GetComponentInParentで取得できるようにしてます。
「Player」側のスクリプトの変数
public NavMeshAgent agent;
public RaycastHit hit;
public bool once = false;
public bool targetF = false;
「Cursor」側のスクリプトの一部
private Player _parent;
void Start() {
_parent = GetComponentInParent<Player>();
transform.parent = null;
}
void Update() {
if (_parent.once) {
Object.Destroy (gameObject);
} else {
NavMeshPath path = _parent.agent.path;
Vector3 _parentPO = _parent.transform.position;
こうすることで「Cursor」が「Player」の値を参照できるようになりました。
「transform.position」は元々PublicでUnity側が作ってくれているので書かなくても参照できる。
3回目・視野内に入ったプレイヤーを感知して突進する敵AI
private NavMeshAgent agent;
void Start ()
{
player = GameObject.Find("Player");
agent = GetComponent<NavMeshAgent>();
}
void Update ()
{
Vector3 forward = transform.TransformDirection(Vector3.forward);
Vector3 targetDirection = player.transform.position - transform.position;
float distance = targetDirection.magnitude;
float angle = Vector3.Angle(forward, targetDirection);
if (distance < 4 && angle < 90)
agent.SetDestination(player.transform.position);
}
void OnTriggerEnter(Collider other)
{
if(other.tag == "Player")
{
Debug.Log ("hit");
}
}
これだけで探査型AIの出来上がり〜
2回目・クリックした位置にプレイヤーを移動させる
private NavMeshPath path;
public NavMeshAgent agent;
public RaycastHit hit;
public bool once = false;
public bool targetF = false;
if (Input.GetMouseButtonDown (0)) {
if (Physics.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out hit, 100)) {
if (hit.collider.isTrigger) {//only player&enemy have isTrigger.
agent.destination = new Vector3(hit.transform.position.x, 0, hit.transform.position.z);
targetF = true;
} else {
agent.destination = hit.point;
targetF = false;
}
once = true;
}
どういうことをやっているかというと、
敵キャラにクリックした場合は、敵の位置に向かって移動する。
地面をクリックした場合は、クリックした場所に向かって移動する。
ということをしている。
地面はcollider.isTriggerをOFFにし、敵やプレイヤーはONにすることで区別しています。
もしもこの条件分岐がなく、「agent.destination = hit.point;」だけにした場合は、
敵にクリックした時、そのクリックした位置(側面)のy座標を0にしたポイントがdestinationに設定されるため、
敵に向かって移動、ということにはなりません。
試しに「agent.destination = hit.point;」だけにしてプレイヤーをクリックすると、停止するのではなく移動してしまうのがわかるかと思います。
そういうわけでこんな感じのコードになりました。
1回目・Navigationのポジションのズレを直す
ナビゲーションをSphere + Planeで普通に作っていくと
こんな感じになるのだけど、
これをBakeして実行すると下の画像みたいにY座標がズレてしまう
補正のせいかY=0.666...という面倒なことになった。
色々と試行錯誤していった結果、
Navigation -> Bake ->「Agent Radius」の値を小さくしていけばズレが小さくなっていくが、値を0にできないためこの方法ではズレを解消することができなかった。
適当にぽちぽち押していった結果、
Navigation -> Bake -> Advanced ->「Height Mesh」をONにするといいらしい
これだけで補正がなくなってスッキリ
「Agent Radius」がどんな値でもtransformのポジションYが変わらなくなりました
0回目・はじめに:このブログが目指すところ & 目次
Unity & C#初心者の私が、
ゲームを完成させてApp StoreにiPhoneアプリ公開するまでの努力を見せるだけのブログです。
どんなRTS(リアルタイムストラテジー)を作りたいかというと、
-
決戦2のようなゲーム
いやー高校生くらいの時に親父が500円でワゴンから買ってきたこのゲームにメチャハマりましたなー懐かしい。
何人がお分りいただけただろうか?
ゲーマーでも1%の人しか知らないような超マイナーゲーなのでどんなシステムかと言うと、
- 複数の軍隊を指揮して敵チームに勝利する
- 自分の軍隊の移動はこちらが完全に指示できる
- 攻撃は軍隊同士がぶつかれば自動で行う
- 移動、攻撃もリアルタイムで進行
ファイアーエムブレム や ファミコンウォーズのようなターン制だったり、
無双シリーズのような個人を動かすゲームではなく、
決戦初代 とか 三国志大戦、戦国大戦のようなリアルタイムで軍隊を指揮するゲームを目指します。
それに必要なものは、
- 地形を察知して目的地まで移動する
- クリックした位置にプレイヤーを移動させる
- 視野内に入ったプレイヤーを感知して突進する敵AI
- 移動経路を矢印で表示する←今ここ
- 視野をグラフィックで表示する
- 選択したプレイヤーに移動を指示する
- 視野内に入った敵のグラフィック表示させるようにする
- 敵捜索AIを敵に付ける
ゲーム作りが進んでいって必要なものが増えたら付け足します。
少ないように見えて結構難解なプログラムを書かされるかも?なのでとりあえず完走目指して頑張ります。