ラベル Unity の投稿を表示しています。 すべての投稿を表示
ラベル Unity の投稿を表示しています。 すべての投稿を表示

2013年5月9日木曜日

Unityのエディタ拡張 -基礎

なんかUnityではエディタが拡張できることも売りの一つらしい.
そんなこと言われたら手を出すしかないじゃない+(・ω・0)*

Unityのエディタ拡張 -基礎

まずは拡張ウィンドウ作成から

1. 準備

ほとんどいらない. Assetsの下に「Editor」ディレクトリを作るくらい. ちなみに他のところでも, 「Editor」ディレクトリにあれば動くらしい. まぁわかりやすくまとめておくのが吉. 

2. コーディング

他の普通のコードと同じようにC#で書ける. 
using UnityEngine;
using UnityEditor;
using System.Collections;

public class ExpansionPrac : EditorWindow {

 [MenuItem("Window/My Window %i")]
 static void Init(){
  ExpansionPrac window = 
   (ExpansionPrac)EditorWindow.GetWindow(typeof(ExpansionPrac));
 }
}
こんな感じ. なにも表示されないウィンドウを出すだけ.
とりあえず EditorWindowクラスを継承. その際には UnityEditorクラスのインポートを忘れずに.

問題は 7行目. 他ではあまり見ない [ ] を使った宣言. MenuItem()により, メニューに追加する.
引数はその際の配置. この場合はメニューの Window → My Windowをクリックで表示されるようになる. 最後の %i はなんとショートカットキー. この場合は 「ctrl + i」. 他と被ってないか注意.


こうなります.

クリック後, Init()の中でウィンドウを用意する.  EditorWindow.GetWindow()でウィンドウを呼び出してる(らしい). 型はこのクラスの型. このクラス名がウィンドウのタブに出てくるので注意.

3. 実際に呼び出せるようにする

しかしゲームに関係ないのにいつコンパイルするんだろう…とか思ってたら
シーンを再生/停止したとき
スクリプトを編集したとき
にやってくれているらしい. 道理でスクリプト編集から戻ってくるなり「エラーあるぞゴルァ!щ(゚Д゚#щ)」とか怒ってくれるわけだ…
なのであと必要な手順は「Editor」ディレクトリの下に配置しているかということ. ちなみに自分は
Assets/Scripts/Editor/ExpansionPrac.cs
と配置して起動を確認. ただ他でEditorを作成→Scriptsディレクトリ以下に移動 した直後はコンパイルが通っていないのか起動しません(・ω・`) 一度 再生→停止 するなどしてコンパイルしてもらうといいかも.

4. 中身を作ってみる

呼び出してはみたものの…
さみしい(・ω・`)
なので中身を適当に入れてみる.
bool isEditable;
bool childToggleBool = true;
float childSliderFloat = 2.22f;
 
void OnGUI(){
 GUILayout.Label("DispTest", EditorStyles.boldLabel);
 int sw = Screen.width;
 int sh = Screen.height;
 isEditable = EditorGUILayout.BeginToggleGroup("ToggleGroupTest", isEditable);
 childToggleBool = EditorGUILayout.Toggle("childToggle", childToggleBool);
 childSliderFloat = EditorGUILayout.Slider("childSlider", childSliderFloat, -10, 10);
 EditorGUILayout.EndToggleGroup();
}
まさかの OnGUI();
シーン中で使ったようにGUILayout()が使用可能. EditorStylesなんていうフォントなどの仕様のクラスも.
また 7, 8行目のように, カスタムウィンドウの幅/高さを取得することも可能.

9行目からがちょっと独特. EditorGUILayoutなるクラスを使える. 通常よく見る Inspectorなんかで使われている表示はここから取り出せるっぽい. Unityリファレンスマニュアルにある通り, とりあえず Toggleグループを追加してみる. グループの中身になるものを 10, 11行目に宣言し, 12行目の EndToggleGroup()でグループの宣言を閉じる. 閉じなくても今回は問題なく動くのだが, 当然閉じないといつまでもグループの中身を足し続けることに…

10行目は子にもトグルボタンをつけてみる. 特に何もなし.
11行目はスライダ. 3,4つ目の引数がスライダの下限/上限. ちなみに, ここの引数を 7行目で取得した swを使って, -sw/swと入れて, ウィンドウサイズを変えてみるとちょっと面白いことにヘ(゚∀゚ヘ)

ちなみにフィールドにあるのがトグルやスライダの初期値になります.
これを 2. で作ったコードに追加してコンパイルしてもらうと…
出てきた!+(゚∀゚0)*



ちなみにコード全景.
using UnityEngine;
using UnityEditor;
using System.Collections;

public class ExpansionPrac : EditorWindow {

 [MenuItem("Window/My Window %i")]
 static void Init(){
  ExpansionPrac window = 
   (ExpansionPrac)EditorWindow.GetWindow(typeof(ExpansionPrac));
 }
 
 bool isEditable;
 bool childToggleBool = true;
 float childSliderFloat = 2.22f;
 
 void OnGUI(){
  GUILayout.Label("DispTest", EditorStyles.boldLabel);
  int sw = Screen.width;
  int sh = Screen.height;
  isEditable = EditorGUILayout.BeginToggleGroup("ToggleGroupTest", isEditable);
  childToggleBool = EditorGUILayout.Toggle("childToggle", childToggleBool);
  childSliderFloat = EditorGUILayout.Slider("childSlider", childSliderFloat, -10, 10);
  EditorGUILayout.EndToggleGroup();
 }
 
}




今回はここまで.
次はGUI操作でちゃんと編集できるようにしたいなー+(・ω・0)*



参考 : Unityリファレンスマニュアル
         MK Games
         EditorGUILayout

2013年4月8日月曜日

Unityゲームを終了する

UnityでAndroidにビルドしていると思うこと
「ホームボタンでしか戻れないうえにバックグラウンドで生きてんの…?」

当然バッテリーはマッハなため非常によろしくない. が, デフォルトではそんな処理はしてくれない.
なのでスクリプトでつける必要があったのでメモメモφ(・ω・ )


Unityゲームを終了する


1. メソッド

Application.Quit();
これだけ.
このメソッドを呼ぶことでアプリケーションは閉じてくれる.

2. 実際に使ってみる

空の GameObjectを作り, GameManagerとでもしておく. 
void Update(){
    if (Application.platform == RuntimePlatform.Android && Input.GetKey(KeyCode.Escape)){
        Application.Quit();
    }
}
こんな内容のスクリプトを作り, GameManagerに持たせてやると, ゲーム中「戻る」キーを押すことでゲームが終了できる.
プラットフォームが Androidであることを確認してるけど, 「戻る」キーとか iPhoneには無いよなぁ….
毎フレーム呼び出すのが気持ち悪いなら何かしらボタンを作って, そこから反応してやると誤爆も少なくなっていいかも.

3(おまけ). ダイアログっぽい何か作ってみた

いいと思ったのでやってみようとした. ただ…ダイアログってどう作るんだ…?3Dには強いが2Dにはいまいち余計な手間がかかってしまうイメージ.

   3-1. 構想

      ヨクワカラナイのでとりあえず構想.
      ダイアログを開くボタンを押す → ダイアログからYesを選ぶ → ゲームが終わる!
      こうしたいなー(・з・)的な簡単な構想. 
      何やらいろいろやり方はアルっぽいけどよくわかんない('A`)
      AssetStoreにありそうだなー…
      ダイアログっぽいものを書く OnGUIを持ったスクリプトを動的に追加することで「ダイアログを開」き, このスクリプトを削除して「ダイアログを閉じ」たい. 
   

   3-2. ダイアログを開くボタン

      とりあえずボタン. これはシンプル.
using UnityEngine;
using System.Collections;

public class ButtonTest : MonoBehaviour {

 public bool isOpened = false;
 
 void OnGUI(){
  float sw = Screen.width;
  float sh = Screen.height;
  
  if (GUI.Button(new Rect(0,0,sw * 3/12,sh/12), "menu") && !isOpened) {
   Debug.Log("push!");
   isOpened = true;
  }
  
 }
}
sw, shはそれぞれ現在のスクリーンの幅/高さを取得. 割合でボタンの座標を決定してやると端末変わった時とかに順応しやすいかと.

ボタンを表示させているのが 7行目, GUI.Button(). なお GUIクラスは OnGUI()メソッド以外から呼ぼうとすると怒られる…(・ω・`)
このメソッドはボタンを作りつつ, 押されたときに trueを返すできる子. 一粒で二度おいしい.
最初の引数で表示位置を, 次の引数でボタンに表示するラベルを宣言. なお Rectについてはこんなのもございます(宣伝)

isOpenedはなんてことはない bool. これで制限をかけて, ボタン連打でダイアログ地獄, なんてのを避ける(予定).
これを空の GameObjectでも作って載せてやり, 実行するとボタンが左上に出るはず.

こんな感じ. なおこの状態で押しても, isOpenedをなんとかする方法がないので, ログは一個しか出てこないハズ.


      3-3. 「ダイアログ」を用意する

ここが一番困った. AndroidのDialogクラスみたいなのは見当たらないし, 仕方ないので別のクラスを自作し, そこでOnGUI()でもしてそれっぽく見せてみる.
using UnityEngine;
using System.Collections;

public class TestDialog : MonoBehaviour {
 
 public ButtonTest test;
 
 void Start(){
  test = this.gameObject.GetComponent<buttontest>() as ButtonTest;
 }
 
 void OnGUI () {
  float sw = Screen.width;
  float sh = Screen.height;
  GUI.Box(new Rect(sw / 3, sh / 3, sw / 3, sh / 3),"TestDialog");
  
  if (GUI.Button(new Rect(sw * 2 / 5, sh * 2/ 5, sw / 5, sh / 10), "yes")) {
                        Debug.Log("quite");
                        test.isOpened = false;
                        Destroy (this);
                        Application.Quit();
  }
  if (GUI.Button(new Rect(sw * 2 / 5, sh * 11 / 20, sw / 5, sh / 10), "no")){
                        Debug.Log("cancel");                        
                        test.isOpened = false;
                        Destroy (this);
  }
 }
}
こんなクラス. このスクリプトを 3-2. で作ったスクリプトを載せた空のオブジェクトに動的にくっつけることで表示させよう, という魂胆. menuボタンのイベントで動的にくっつければ, あたかもボタンでダイアログを開いたように見えるという寸法.

Start()はとりあえず 3-2のスクリプトの取得. isOpenedを書き換えて, 「開きっぱなしの状態」をキャンセルする.
15行目, GUI.Boxで, ただの四角い領域を描画. ついでに"TestDialog"とタイトルっぽく入れてみる.
中にはボタン2つ. yesと noボタン. この yesボタンの if()の中で Application.Quit()でも呼んでやれば目的は達成できるはず. でも実機じゃないと確認できない(・ω・`)
そしてDestroy(this)で このスクリプト を破棄することで, ダイアログ(?)を破棄する. アプリ終了する前に Destroy()しておくべきなのだろうか…

後は3-2の方, ボタンのイベントの中を
if (GUI.Button(new Rect(0,0,sw * 3/12,sh/12), "menu") && !isOpened) {
   Debug.Log("push!");
   this.gameObject.AddComponent<TestDialog>();
   isOpened = true;
  }
と, AddComponent()してやることで, ここで作ったスクリプトを動的に足す.
これで, menuボタンを押すと,
みょん. それっぽいものが出てきてくれました.
Inspectorの方を確認して, 動的にスクリプトが追加されているのも確認しておくといいかも.
ちなみに3-2の方, ボタンの if()文を,
if (!isOpened && GUI.Button(new Rect(0,0,sw * 3/12,sh/12), "menu")) {
   Debug.Log("push!");
   this.gameObject.AddComponent<TestDialog>();
   isOpened = true;
  }
としてみると, ダイアログっぽいものを開く際変化する isOpenedのほうの条件に引っかかるのか, そのあとの条件となっている menuボタン描画メソッドが呼ばれなくなり,

menuボタンが消える. これはこれで使いようがありそうだったのでメモメモφ(・ω・ ).





おまけのが充実してる気がするけど仕様です. ( ´∀`)ノシ キニシナイ

2013年4月3日水曜日

他のGameObjectの持つスクリプトのフィールドを参照する

たとえばライフポイント.
ディスプレイするために表示用クラスで見たいけど, 体力管理としてプレイヤーでも参照したい, でも2か所に持つとかキモすぎる!щ(゚Д゚#щ) 絶対バグる!<(゚Д゚#<)
なんて状態.
なお今回からC#で書いてみます. ほとんど変わらないから問題ないかと.


他のスクリプトのフィールドを参照する


1. 状況

たとえば Playerのタグを持った PlayerObjectがいたとする. 
こいつはこんな LifeManagerという名のスクリプトを持っている. 
public int life = 10;
void Update(){
…
たとえば残りライフを描画する GUIのクラス, LifeMonitorがあったとする.
LifeMonitorは残りライフを表示するために PlayerObjectの残りライフが知りたい.
でもまさかダメージが入るたびに SendMessageメソッドで報告を受けるのもなんかヤダ('A`).
まさか LifeMonitorの方でも同じようにライフを減らすなんてありえない.

たとえばこんなシチュエーション.

2. 対策

LifeMonitorのほうのスクリプトに
GameObject player = GameObject.FindWithTag("Player").gameObject;
LifeManager script = player.getComponent(typeof(LifeManager)) as LifeManager;
int currentLife = script.life;
これで参照できる.
1行目は単純に PlayerのGameObjectを取得しているだけ. やり方は他にもいろいろ.

問題はその下.
1行目で取得した Playerから, コンポーネント名を指定して取得する.
ここが最初の問題.

必要なパーツは2つ. 「型宣言」と「キャスト」. 上記2行目なら,  typeof(クラス名)が型の宣言. as LifeManager がキャスト. 他のやり方もあり,
LifeManager script = (LifeManager)player.getComponent<LifeManager>();
とするパターンも. <LifeManager> で型宣言し, (LifeManager)でキャストするやり方の組み合わせ.
2つのパーツがそろっていればやり方は自由なのだが, 実はUnityScriptなら,
var script: LifeManager = player.getComponent(LifeManager);
とか書けちゃったりする.

あとは3行目のように, 取得したコンポーネントからフィールドの lifeをいただけば一丁上がり.
他のフィールドも同様に参照してやればおk. 意外とイメージはしやすいはず.
まぁディスプレイする側から体力操作し始めるようなことはないだろうけど.

3. 応用?

実は同様に, メソッドの呼び出しも可能. LifeManagerに以下のメソッドを追加してみる.
public void addLife(int inc){
    life += inc;
}
今更だけどたとえが悪かったなぁ…('A`) lifeに引数に指定した incだけ足すだけの簡単なメソッド.
LifeMonitorの方では,
script.addLife(1);
とでもしてやればOK. この後 lifeを読むと, ちゃんと 1加算されている.
戻り値も取り出せるし, 当然複数の引数も渡せる.
また直接,
script.life = 11;
とかぶち込むことも. やりたい放題である.

これらの注意点は,  必ず publicであること. パッケージ分けとかがあるわけではないので, アクセス修飾子に注意. 特に C#のデフォルトは privateな点など, 言語的なところにも注意. protectedも当然NG.

フィールドを参照したい, (基本ないだろうけど)フィールドの値を書き換えたい, 何度も同じスクリプトのメソッドを呼び出したい,戻り値が欲しい, 引数は複数持たせたい!なんて時はこの手法がよろしいのかな?

逆にゲームオーバーのように1回だけ呼べばいいものは, sendMessage()を使えばよろしいかと.





なんか変な文章(・ω・`)

2013年3月21日木曜日

Unity基本メソッド覚書

Unityでいろいろ作っている時に,
「あれってどう実装するんだっけ…」「これ動かすときどこの値をいじるんだっけ…」
なんてことが最近多かったのでメモメモφ(・ω・ )

Unityでスクリプトを書くとき覚えておきたいメソッド-移動と回転-


0. 基本

移動にしても回転にしても, 座標を用いてパラメータをいじるのは基本
var myTransform : Transform = this.gameObject.transform;
ここ.
Hierarchyウィンドウから適当なオブジェクトを選択して, Inspectorを眺めると必ずあるのがこの transform.
位置, 回転, スケールを管理するここはスクリプトからもよくアクセスされる.
スクリプト中で何度もアクセスするようなら, 上記のように変数として持ってしまうのも, 処理の高速化として有効らしい.
ちなみにC#で書くなら, 
Transform myTransform = this.gameObject.transform;
ほぼ変わらない.

1. 移動

ゲーム作成において必須項目. なので「プレイヤーを歩かせる」「足場を動かす」「弾を打ち出す」など, いろいろなところで使う. ちなみにC#でもUnityScriptでもほとんどコードは変わらず. おかげでC#のお勉強にならない…(・ω・`)

・ positionをいじる

myTransform.position = new Vector3( x, y, z);
Vector3型で指定した x, y, zの座標に「ワープ」する.
なので「歩く」モーションなどには向かない.
ヨ○テレ○ートみたいなワープ移動や, ロック○ンの"消える足場"みたいなものなら使えるかもしれないが, 基本移動を表現するには不向き.

・ Translate

myTransform.Translate(Vector3 vec);
Vector3型で指定したベクトル方向に「動かす」メソッド. プレイヤーを歩かせるならこれか.
コード中で使うなら,
var speed: float;
myTransform.Translate(Vector3 vec * speed * Time.deltaTime)
となるかと. Vector3で方向を, speedで移動速度を設定. Time.deltaTimeで環境ごとのフレームレートの差を補完させる. 処理がマシンによってばらばらになるのが嫌なら, つけておくと安心できるかと.
参考

・addForce

これだけちょっと毛色が違う. こちらは
this.gameObject.rigidbody.addForce(Vector3 vec);
Vector3型で宣言した方向に力を加えるメソッド. まずアクセスするのが Transformではなく Rigidbody. これは「Unityが面倒な物理演算を自分でやってくれる」ための重要なコンポーネント. ここにアクセスして, 「力を加えて」動かす.
要するに「物を殴って動かす」ようなもの. このメソッドを呼んだ一瞬は力がかかるけど, 以降は慣性で移動する.
おもに弾丸の発射やピンボールのバンパーなんかに用いると幸せになれるかも.
当然対象に rigidBodyがないとだめ. addしておきましょう.

2. 回転

同じく必須項目. たとえ横スクロールアクションであろうと左右の向きくらいは変えるはず. 「向きを変える」「ターゲットの方向を向く」「軸を合わせる」なんかでいろいろ使う.

・LookAt

var targetTransform: Transform;
myTransform.LookAt(targetTransform);
Transformから直接呼び出すメソッド. シンプルに
「targetTransformに指定したものの方を見る」
というもの.
一見便利なのだが, 問題は myTransformと targetTransformが接近したとき.
「近づく」まではぎりぎり行けるかいけないかはわかれるが, 接触してしまうとかなり猛烈な荒ぶり方をしてしまう.
またこの「見る」は, 全身の正面を targetTransformに向けるので, 両者のサイズ差が大きいと, 見上げる or 見下ろす ような体制になりやすいのが難点.

逆に接近することがないようなもの, 侵入者を照らすサーチライトの光源なんかはこれで十分かと.

・rotation- 1

myTransform.rotation = Quaternion.Euler( x, y, z);
transformのrotationに, オイラー角で指定して角度を入れる. この Quaternionクラスが角度の操作をする時に便利.特に,
myTransform.rotation = Quaternion.AngleAxis( float angle, Vector3( x, y, z));
と, AngleAxisメソッドを使うと便利. これは第一引数に角度を, 第二引数に回転軸を設定して回転させる, というもの. Update()メソッドの中で徐々に角度の部分を増やしてやれば, ゆっくり回転する物体の出来上がり. 変に角度いじるよりわかりやすいかと.
またこれは掛け合わせることで, 複数の軸へのそれぞれの回転量を表すこともできる.
たとえば, 「x軸を軸に45度, y軸を軸に120度回転させた状態」にしたいなら,
myTransform.rotation = Quaternion.AngleAxis( 45, Vector3( 1, 0, 0))
                       * Quaternion.AngleAxis( 120, Vector3( 0, 1, 0));
と, それぞれの条件を書いた式をかけてやるだけでいい. これはわかりやすい.
ただし順序があり, 最後にかけた回転から順に行われるらしく, この場合は
「 y軸を軸に120度回転させてから, x軸を軸に45度回転させる」という順序で回転が行われる. 結果が同じならいいけれども….
たとえば

こんな棒があった時,

上記の y軸 → x軸回転時
その逆 x軸 → y軸回転時
とここまで変わるので注意が必要.

主に回転し続ける足場やカメラなど, 常に角度が変化するものに強い?

・rotation - 2

myTransform.rotation = Quaternion.LookRotation(myTransform.position - targetTransform.position);

いじる場所は一個前と同じ myTransform, 使うクラスも Quaternionとこれまた同じ.
やることは二個前と同じ, 「自分を targetTransformの方に向かせる」 というもの.
では何が違うのかというと, 引数に Vector3クラスが使える という点だろう.
LookAtの際問題になるのが, 両者が接近したとき, と紹介したが, これを回避できるのがコイツ.
やり方は
var vec: Vector3 = myTransform.position - targettransform.position;
vec.y = 0;
myTransform.rotation = Quaternion.LookRotation(vec);
としてやる. 要は両者の y軸(高さ)の差を0としてやれば, 変に上下に傾くことがなくなる.
応用してやれば, myTransformの y = 0の場所から見た方向を向く, などもいじりやすいのが利点. 
2D視点など軸が一ついらないゲームなんかではこっちの方が変な動きをしなくて安心かと. 

・Rotate

myTransform.Rotate( x, y, z);
//or
myTransform.Rotate(Vector3 vec);
こちらは x, y, z の角度をそれぞれ指定して回すメソッド. 角度が完璧に決まっているならこちらのが早い. がやはり徐々に変化させるタイプには向かない.
スポーン時に最初の向きを決めてやったり, マ○オのような2Dスクロールで進行方向を変える時などはこっち?.

最近の○リオはちゃんと振り向きモーションあるけどね(・ω・`).


・おまけ

myTransform.rotation = Quaternion.identity;
回転なしの状態にする = すべての角度を 0 にする.
角度の初期化などに便利?





-移動と回転-とか書いたけどこれは他にもまとめる時がくるフラグなんだろうか…(・ω・`)

2013年3月11日月曜日

見回りをする敵の作成

よくある雑魚敵.
見回りの兵士しかり, ただ歩く雑魚しかり, よくある敵の動きとして決められたポイントを動く敵の動きを組んでみた.
作った段階順にメモメモφ(・ω・ )

見回り兵の動きの作成

1. ターゲットの方を「向く」

今回考えたのが, ターゲットの方を向く → 前進! でシンプルにいけるんじゃね?ということ.
なのでまずは「ターゲット」としたものの方を向くことから
var speed : int;
function walkToTarget(t:Transform){
 var targetVec : Vector3 = t.position;
 targetVec.y = this.gameObject.transform.position.y;
 gameObject.transform.LookAt(targetVec);
 this.transform.Translate(0,0,1 * speed * Time.deltaTime);
}
6行目はまだ見ないで('A`). 引数の tは目標の transform. speedはお好みで. ここに出しておくと Unityの Inspectorですぐいじれるから便利.
3行目で目標の positionを取得. これをtransform.LookAt()に放り込むだけで, 引数に入れた positionの方を向いてくれるから便利. ただしこのままだと, 目標が自分より高い位置にいる場合, 最悪仰向けになるという間抜けさ.
なので 4行目, 見る positionの高さ yを自分の高さにしてやれば, 不自然に仰向けうつ伏せになることはなくなる.
これをUpdate()のなかで呼んで, とりあえず目標の方に「向く」ことができた.

2. 「前進」する. 

わりと大事だと思ってる. 適当な区間を歩かせようとしたとき, 「ここから x歩いたら y度修正して 半径 rの弧のうえを歩くように…」なんて考えたくない('A`) できる限り楽したいのです.
this.transform.Translate(0,0,1 * speed * Time.deltaTime);
さっき見えちゃったけど. transform.Transrate()の引数に Vector3で動く量を指定してやるだけ.
今回はただ前進したいので zだけ増やして残りは 0. speedは1. の通りお好み. Time.deltaTimeはフレームレートの違いを吸収して, 単位時間当たりの変化量を一定にしてくれるらしい. 端末の違いなどで変化が出ないようにするのに非常に役立つ.

ここまでで, あとは適当なところで目標を指定してやれば, そいつを追い続ける動きができる. がそれだと巡回ができない.
なので「巡回のポイントごとにマーカーを置き, そこに到達したら次の目標を指示する」ようにしてやる.

3. マーカーの作成

イメージはカラーコーンか. こいつを作る前に, 1. 2. を載せる敵に Enemyのタグをつける. これで「巡回中の敵がマーカーにたどり着いた」を識別する.
まずはマーカーの GameObjectの作成. これは何でもいいけど, 必ず敵が「到達」できるようにすること. はるか上空にあるマーカーを眺めて荒ぶる兵士とかかわいそうすぎる(;ω;`)
適当に cube当たりをチョイス. 名前を checkPoint1とでもしたら Inspectorを見る.
見えているマーカーを回るならともかく, 基本は何もないだろうし, Mesh Filterの Meshを Noneに. 
Colliderは Is Triggerをチェックしておく. 
こうすることで「トリガー」となり, 物理的な当たり判定が消え, 物が素通りするようになる. 
ただし「衝突した」ことはとれるので, センサーなど目に見えない範囲を作るときに重宝する. 
今回もその恩恵にあやかる. 
準備ができたらスクリプト.
var nextTarget : GameObject;

function OnTriggerEnter(object:Collider){
 if (object.gameObject.tag == "Enemy"){
  object.gameObject.SendMessage("changeTarget",nextTarget);
 }
}
OnTriggerEnter()は引数の「なにか」がトリガーに引っかかったぞ, というメソッド. 何がトリガーの範囲に入ってきても呼ばれる. なのでふるい分けをしてやる.
4行目は, 入ってきた「なにか」のタグを取得し, if文でふるい分ける. 今回は敵が巡回してきたら反応したいので, タグは Enemy.
Enemyが来たらそいつに対し, 5行目の処理. 内容はぶつかってきた objectに対して, 「changeTargetというメソッドを, nextTargetという引数を与えて呼び出せ」ということ. これまた便利.
あとは nextTargetに次に目指してほしいマーカーを入れてやるといい.

4. 目標切り替えの処理

これは単純
var target : GameObject;
function changeTarget(newTarget:GameObject){
 target = newTarget; 
}
これだけ. これを敵の方のスクリプトに持たせる. マーカーではない. このメソッドを持ってマーカーに突っ込むと, 次の目標の支持が飛んでくる寸法.
最後に Inspectorから, 「一番最初に向かう目標のマーカー」を敵の scriptの targetのところに指定してやればいい.

ちなみにこの指定の際,  targetをフィールドに宣言していると, Hierarchyに並んでいるマーカーを, Inspectorの scriptの中に表示されている targetにドラッグ&ドロップしてやるだけでいい.
どこを指定したかがわかりやすいかと.

5. マーカーをばらまく

マーカーをコピーしてばらまくだけ. もちろん「次の目標」はそれぞれに設定しないといけないけど.

これで「適当なポイントを巡回する兵士」みたいな動きができる.
ただこのままだと怪しいやつが目の前を通っても無視するおバカ兵士になってしまう.
のでその辺を足すとより敵っぽくなるかと.




ながなが書いたけどコードにするとめっさ短いのがUnityのいいところ. ∩( ・ω・)∩




2013年3月4日月曜日

RECTの勘違い

ずっと勘違いしたまま何とかやってこれてしまったので
ここらで矯正

Rect()の範囲指定

特にGUIいじるときなんかに登場する, 四角形の範囲を宣言するクラス(?). 
Rect(x,y,width,height)
中の4つの引数で範囲を宣言するのだが, 何と混ざったか4つの引数を

左上(x0,y0)と右下(x1,y1)ととった四角形の2点

Rect(x0,y0,x1,y1)

でとるものとか勘違い.
正解は

Rect(x0,y0,x1-x0,y1-y0)

と左上の1点と幅高さで宣言するものとのこと.




どうしてこうなった…(・ω・`)



2013年1月24日木曜日

Unity使ってみた

PlayもそこそこにUnityもいじってみた.
…意外とコード書かないなぁこれ(感想)


はじめてのUnity


ここを参考にまずはイロイロいじってみた. ただまだ第1回しかなく第2回は近日公開…
近日っていつですか(・ω・`)

そんな中でまずは基礎的なところをメモメモφ(・ω・ )

1. プロジェクトとシーン

プロジェクトはゲーム本体, シーンはそのステージ, といった関係. なので1プロジェクトの中にたくさんのシーンを持つことができます. もちろんシーンから別シーンの遷移も可能. ただし編集していられるのはシーン1つずつのみ. 別シーンを開くときはセーブを忘れずに.
共同開発時のネック. シーンの衝突だけは避けましょう. 泣けます. なにいじっても衝突するので素直に声掛け合って編集するのは一人だけにする, のが一番かと.

チラッと見た話では一つのシーンを分割して作り, 後で合成して一つのシーンにするなんてやり方も…

2. ホイールボタン

3D系ツール(Blender等)をつかってて感じたホイールボタンの重要性. Unityのシーンビュー内ではホイールボタンを転がしてズーム, 右ドラッグで回転ですが, ホイールボタンドラッグで画面を平行移動ができます. ホイールボタンドラッグとかこのマウス買ってから初めて使った( ´_ゝ`)

3. asset

光, 空, 地形や水など, 普通に作ったらそれだけで製作期間が楽しいことになりそうなものは, Unityが標準で用意しているものからユーザーが作ったものまでイロイロ用意されています.
どこかの記事では「既にあるものは最大限利用しましょう」なんて書かれているほど. 特に車なんかはめんどくさいそうなので慣れるまではこちらを流用しましょう, らしい.
標準のものは
[Asset] → [Import Package] → からいろいろ選べます.
ただし中には素敵に重いものもあるので, スマホ向けを考えているなら容量に注意, いろいろ眺めて必要なものだけ入れましょう.

4. ライセンス

もっと先にメモすべきことだったorz 無料版でも十分に作れるUnity. ただしAndroid, iPhone向けにビルドしたい, 欲張って箱○やらPS3やらでやりたい!なんて考えると, それぞれにビルドするために, それぞれ別々のライセンスが必要です. なのでAndroidだけやりたいならAndroid用ライセンスが別途必要ですお客様. 無料版でできるのはhtml版の書き出しだけ. 往年のFlashゲーム時代を彷彿とさせます.

5. オブジェクトの配置(床と壁)

3. の通り地形用assetもあるけれど, まずは基本.

Hierarchyビューの左上の [Create] か
[GameObject] → [CreateOther]

からCubeを選択. これをシーンから選択してやるとInspectorビューにそのオブジェクトの情報がいろいろ出てきます.
まずはそのオブジェクトの位置や回転などを表すTransformの項目をいじって原点付近にあわせましょう. Scaleをいじれば大きさも変更可能. 基本はこれで平べったくして床を生成する. 部屋の床など平らなところは基本これでOK.
同様に縦に伸ばしてやれば柱や壁の完成. 色についてはまた別のところで.
これをPositionをいじって並べてやればフィールドの完成.

6. プレハブ化

かなーり大事なところ1号. 要するに作ったオブジェクトを登録しておき, 複製などをしやすくするための機能.

 一番シンプルなやり方は, Hierarchyビューにある, プレハブ化したいオブジェクトを, ProjectビューのASSETディレクトリの中にドラッグ&ドロップ. これでASSETの中にHierarchyの中にあったオブジェクトがASSETの中にコピーされるはず.
このASSETの中のオブジェクトを今度はSceneビューにドラッグ&ドロップ. これでOK, シーンにオブジェクトが追加されたはず. 5. の壁などや大砲の弾など, シーン中で同じものをたくさん使うなら是非こちらを.
名前はそれっぽいのを付けておきましょう. Cubeが立ち並ぶASSETとか泣けます.
ちなみにスクリプトから動的に作成するときなどは, プレハブ化しておかないと動的に作成とかできないので, 弾丸みたいなものは設定がすんだらプレハブ化しておきましょう.

7. 親子

かなり大事なところ2号. 例えば5. で作った床と壁, 今はバラバラにしか動かせないので, いざ床の位置を変えたくなったら全部変えないといけません. そこで親子化.
これまた設定は楽で, Hierarchyビューの子にしたいオブジェクトを親にしたいオブジェクトにドラッグ&ドロップ. これだけ. これでHierarchyビューではディレクトリの階層構造のようになっているはず.

このとき 親 のほうをSceneビューから動かすと, 子にあたるオブジェクト全ての位置が変更されます. 子だけを選択してInspectorを見ると, なにやら表示が太線に. これは
親のオブジェクトの基準点
から見た相対的な座標が表示されています.
これにより親のTransformの変更に紐付けた子のTransformも同時に変更されます.
もちろん子だけを選択した状態なら選択中のオブジェクトの位置を変更できる.
部屋の全景の作成や, 複数のオブジェクトがまとまってできる一つのオブジェクト, なんてものを作るのに便利.

ちなみに
[GameObject] → [Create Empty]
で空のオブジェクトが作れます.
ここに床, 壁とそれぞれ放り込んでやるとフィールドの管理とかしやすいとか, そういった使い方.
カメラもこれで管理すると楽…かも?



ほんとにただのメモ書きだぁ・・・('A`)


AWS CDKで立てたEC2インスタンスのTimeZoneとかいじりたかった話

EC2を立てることはできたけど、立てたインスタンスは UTCのままだし設定ファイルとかいちいちscpしてくるのはダルい。 当初UserDataでなんとかしようとしたものの、「書く量がヤバいしメンテしにくい」と悩んでいたところ見かけたのが  AWS::CloudFormation:...