プロフィール

はーさん

Author:はーさん
1人創作チームDeadMan'sSunのボスです。
Twitter→@Ha_Shok_ko

TERA HITO:Revolutionを作りました。よろしく頼むぜ、兄弟!
・ふりーむ!のTERAのページ(exe形式公開場所)へ
・UnityRoomのTERAのページ(WebGL版公開場所)へ

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
カウンター
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム
QRコード
QR

私のアイランド


--/--/-- --:-- はーさん

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
2015/10/28 01:05 はーさん

【Unity】RTSみたいなゲームオブジェクトの選択方法

お久しぶりです。
はーさんです。
二か月ぶりのUnityの記事です。
最近学校の方とかで忙しいこともあって、記事を書けませんでした。
夏休み時間あっただろ!


今日はUnityでRTSみたいな、マウスをクリックしてからドラッグしてできた四角形の中に納まったゲームオブジェクトを選択する方法がそれっぽくできたので紹介します。

やりたいことはこういうのですな。

ブログ

ウォークラフトとか、スタークラフトとかエイジオブエンパイアとかにありそうな感じの。
いわゆるRTSの複数ユニット選択のやり方ですね。
マウスクリックとドラッグで良い感じの四角形ができて、こうピーって。
これ作ろうと思ったら、こういう問題があるんですよね。

ブログ1

マウスがクリックしたところはスクリーンの座標として扱われます。
で、ゲームオブジェクトたちの座標というのはワールド座標として扱われます。
まあ当然といえば当然なんですけど、ワールド座標とスクリーン座標は別物なんですよね。
マウスがクリックしたところをワールド座標として扱うには、変換してあげないといけないわけですね。

で、次にマウスがクリックとドラッグで作った四角形の範囲内にいるobjectをどうやって判定するか、という話になるんですよね。
四角形のオブジェクトを作って、大きさを反映させてやって作る、というのも一つの手ですが僕は失敗しました。
要するにこういうことだったんですよね。

ブログ4

オブジェクトの座標がマウスのクリックとドラッグで作った四角形の始点と終点内に収まっているかどうか、で選択されたかを判定します。

つまり、

始点のx座標<=オブジェクトのx座標<=終点のx座標
始点のy座標<=オブジェクトのx座標<=終点のx座標

これで作った四角形内にいる、と判定するわけです。

以下その判定用のデモコードです。
そのままコピペで使えます。
なかなかマッチョでヤングなコードですけど。

/////////////////////////////////////////////////////

using UnityEngine;
using System.Collections;

public class SelectObjectSystem : MonoBehaviour {

public Vector3 startPos;
public Vector3 endPos;
public float s_x;//始点x座標
public float s_y;//始点y座標
public float e_x;//終点x座標
public float e_y;//終点y座標

public GameObject[] gameobject;//デモ用のオブジェクト格納

// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update () {
click ();
}

void click(){

       //左クリックしたときと離した時とで疑似的なドラッグ操作にしてます。
//左クリックしたとき
if (Input.GetMouseButtonDown (0)) {
startPos=Input.mousePosition;//クリックした位置
startPos.z=10f;//マウス座標の奥行の設定
startPos=Camera.main.ScreenToWorldPoint(startPos);//スクリーン座標をワールド座標に
//↓左を離した時
} else if (Input.GetMouseButtonUp (0)) {
endPos=Input.mousePosition;
endPos.z=10f;
endPos=Camera.main.ScreenToWorldPoint(endPos);
unitpositionculiculate();//オブジェクトの位置を判定するメソッド
}

}

void unitpositionculiculate(){

s_x = startPos.x;
s_y = startPos.y;
e_x = endPos.x;
e_y = endPos.y;
//初期の始点と終点のX座標で、始点が終点よりも大きかったら終点の座標と入れ替え
if(startPos.x>endPos.x){
s_x=endPos.x;
e_x=startPos.x;
}
//初期の始点と終点のY座標で、始点が終点よりも大きかったら終点の座標と入れ替え
if(startPos.y>endPos.y){
s_y=endPos.y;
e_y=startPos.y;
}
//for文で判定を行う
for (int i=0; i<3; i++) {
Vector3 posi = gameobject [i].transform.position;
//条件式
if (s_x<=posi.x&&e_x>=posi.x&&s_y<=posi.y&&e_y>=posi.y) {
Debug.Log("範囲内にいます"+gameobject[i].name);
}
}

}
}

/////////////////////////////////////////////////////
補足

~~~~~~わちゃわちゃ色々

startPos.z=10f;//マウス座標の奥行の設定
startPos=Camera.main.ScreenToWorldPoint(startPos);//スクリーン座標をワールド座標に

~~~~~~わちゃわちゃ色々

この部分はマウスのスクリーン座標をワールド座標に変換しています。
このときZの値を設定しているのはスクリーン座標にZ軸は存在しない(つまりVectior2型、XとY座標のみ)ので、Vector3型に収めるとZが0になって、ものすごく小さな範囲でしか値をとれないというか、どこの値なのか与り知らぬ謎の値をとります。認知して、と言われてもUnityは僕の子じゃないので無理です。


・unitpositionculiculate()について
ラクダキャスティングしてないのですごい平坦な名前で見づらいですね。
ここでは始点と終点の座標の判定の祭に、始点のXとY座標が終点よりも大きいかった場合に条件式を実行できないので、値を入れ替える、ということをしています。

インスペクターの設定と、実行時の結果はどうなるかは以下の画像のとおりです。

ブログ2

ブログ3

これでウォークラフトが作れますね!わーい!


結構力押しだったので、まぁ当然ですけど問題点もあります。

◎このやり方の問題点

・カメラに点ぐらいにしか映っていないユニットでも範囲内にいたら選んでしまう。(Z軸は関係ないので)
・範囲外のユニットも判定の対象になっている。
・膨大な数のユニットを用意した場合、毎回その数だけ判定することになる。


こんなところでしょうか。
でも四角形作ってその範囲のユニットを全選択!はやりたかったことなので、超うれしいですね。
あとカッコいいし。
ピーッシュッキャキーンって。


改善点とかあれば、教えてもらえるとうれしいです。

スポンサーサイト
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。