numalog

ぬまおうの活動日誌

Archive for the ‘プログラミング’ Category

Unity tips #3 OnTrigger、OnCollision関数について

without comments

同様に過去記事からサルベージ。

実は、 OnTrigger、OnCollision関数が適応されるかどうかは条件があります。
これを知らないでやると、なぜか接触を感知しなかったり、かとおもえば突然動いたりなど不具合が出まくるので注意。

Collision detection occurs and messages are sent upon collision
Static Collider Rigidbody Collider Kinematic
Rigidbody Collider
Static
Trigger Collider
Rigidbody
Trigger Collider
Kinematic Rigidbody
Trigger Collider
Static Collider Y
Rigidbody Collider Y Y Y
Kinematic Rigidbody Collider Y
Static Trigger Collider
Rigidbody Trigger Collider
Kinematic Rigidbody Trigger Collider
Trigger messages are sent upon collision
Static Collider Rigidbody Collider Kinematic
Rigidbody Collider
Static
Trigger Collider
Rigidbody
Trigger Collider
Kinematic Rigidbody
Trigger Collider
Static Collider Y Y
Rigidbody Collider Y Y Y
Kinematic Rigidbody Collider Y Y Y
Static Trigger Collider Y Y Y Y
Rigidbody Trigger Collider Y Y Y Y Y Y
Kinematic Rigidbody Trigger Collider Y Y Y Y Y Y

この表でYとついているところが判定が行われる組み合わせで、それ以外のところでは正しく行われません。
当たり判定を行わせるオブジェクト同士が空白の部分の組み合わせになっていると、不可解な挙動をします。
両方Kinematic&Rigidbodyを与えると上手くいきます。


Written by numa

5月 3rd, 2013 at 4:38 am

Posted in プログラミング

Tagged with

Unity tips #2 カメラスクリプトの書き方

without comments

前回に引き続いて、過去の記事から、需要がありそうなのをサルベージして張ります。

追尾型 カメラスクリプトの書き方

基本的なところをざっと。 括弧の中は仮の変数名。

  • Player位置からカメラへ向うベクトル(vectorToCamera)を求める。

this.transform.position-Player.transform.position と計算

注意点で、カメラとプレイヤーのx,z座標が同じとき、 vectorToCamera が零ベクトルになってしまうので正常に動かない可能性があります。
すこしでもx,z座標がずれてれば正しく動くはずなので、カメラとプレイヤーの初期x,z座標はずらす必要があります。
もしくは、プレイヤーとカメラのx,z座標が同じときは、適当な数字にずらすようにスクリプトで書いてあげればよいでしょう。

  • 目標カメラXZ位置(wantedPosition)として、Player.transform.position + xzVectorToCamera*distanceと計算

distanceはどれぐらいの距離を保ちPlayerの後を追尾するか。
カメラのY位置は個別に指定したほうがよい。よってvectorToCameraのy成分を0にしてNormalizeしたものをxzVectorToCameraとする。

  • 目標カメラY位置(wantedPosition.y)は個別に、Player.transform.position.y + yHeightとする。

yHeightで カメラの高さを設定。

  • wantedPositionをそのままtransform.positionにいれるとカメラの動きが俊敏すぎてガクガクしてしまう。

これを防ぐために Vector3.LerpやMathf.Lerpを使い、現在のtransform.positionと補間をおこなうと滑らかな動きになる。

例)
transform.position = Vector3.Lerp(transform.position,wantedPosition,damping*Time.deltaTime)
変数dampingで追従移動の滑らかさを指定する

位置の決定はこれでよいものの、これではカメラは追従するだけでプレイヤーの方を向かないので、そこについての処理を書く。

  • プレイヤーの方を見るようなカメラの回転を計算する(targetRotation)。

Quaternion.LookRotation(-vectorToPlayer)とやれば簡単

  • 例によって、これをtransform.rotationにいれるだけだとガクガクなので、

transform.rotation = Quaternion.Slerp(transform.rotation,targetRotation,rotationDamping*Time.deltaTime)

と補間をして滑らかに回転させる。

これが自分が使っているカメラの基本挙動。
これに加えてy成分を地形に沿わせて上下させたり、
Playerの移動をカメラと相対的な動きにさせると、結構時のオカリナっぽい挙動になります。


Written by numa

5月 3rd, 2013 at 4:32 am

Posted in プログラミング

Tagged with

Unity tips #1 ObjectをInstantiate、カメラスクリプト、HPゲージバー、配列の仕様について

without comments

前ブログで書いていた、unity関連の記事で、検索エンジンなどの結果から需要がありそうなものを抜粋。

大量のObjectをInstantiateすると遅い

for loopなどで、Instantiateでオブジェクトを出す方法は簡単ではあるのですが、大量に生成するとかなりパフォーマンスが落ちます。
対策としては、それが静的なオブジェクトであれば、メッシュ頂点を編集して、1つのオブジェクトとしてまとめて生成する方法が早いです。

参考サイト

(英語)http://blog.nobel-joergensen.com/2010/12/25/procedural-generated-mesh-in-unity/

http://wise9.jp/archives/1479

サードパーソンカメラスクリプト

プレイヤーを追尾するカメラスクリプトのサンプルです。
unity4.x系で未確認。
また、今見るともうちょっとやりようあったなぁ というところが結構あるので、参考程度で。

なぜか変なpタグが入ってしまうので、お手数ですが使う際は取り除いてください。

using UnityEngine;
using System.Collections;
public class CameraMovement : MonoBehaviour {
    public GameObject targetObject;//追跡するゲームオブジェクト
    private Vector3 targetPosition;
    private Quaternion targetRotation;
    private Vector3 viewPoint;
    public Vector3 distanceVector;//カメラと追跡物の距離
    public Vector3 relativeViewPoint;//追跡物とカメラ視点の距離
    // Use this for initialization
    void Start () {
        Initialize();
    }</p>

<pre><code>// Update is called once per frame
void LateUpdate () {

    CaluculateViewPoint();
    CalculateCameraMovement();
    ApplyCameraMovement();

}

void Initialize(){
    targetPosition = new Vector3();
    targetRotation = new Quaternion();
    viewPoint = new Vector3();
}

void CalculateCameraMovement(){

    targetPosition = targetObject.transform.position + distanceVector;
    targetRotation = Quaternion.LookRotation( viewPoint – this.transform.position);

}

void CaluculateViewPoint(){
    viewPoint = targetObject.transform.position + relativeViewPoint;
}

void ApplyCameraMovement(){

    this.transform.position = targetPosition;
    this.transform.rotation = targetRotation;
}
</code></pre>

<p>}

WindowsServer2008でUnityを起動する

マイコンピューターを右クリック->プロパティ->システムの詳細設定->詳細設定タブ->パフォーマンスの”設定” ->データ実行防止タブ->次に選択するものを除く~->追加で”Unity.exe”を追加

ほかにも起動しないソフト、OSがあったら、この設定を試してみると動くようになるかも。

HPゲージバーの実装

サンプル

GUI.DrawTexture  (Rect (0,0, size.x, size.y),HudEmpty);</p>

<p>GUI.BeginGroup (Rect (0, 0,HPratio*size.x, size.y));
GUI.DrawTexture (Rect (0,0, size.x, size.y),HPMAX);
GUI.EndGroup ();

sizeはHPゲージの画像サイズx,yをVector2(x,y)として表現したもの HPratioは現在のHP/最大HPをFloat型で計算したもの 。 HudEmptyはゲージが空のときのテクスチャ、HPMAXはHPゲージが満タンのときのテクスチャ。

結局何をしているかというと、 GUI.BeginGroupのRectを、HPの比率(HPratio)により変形させることにより、 HPゲージのテクスチャの可視部分を変化させてゲージを表現しています。

UnityRPGでは、いまのところはこの方法をちょっと変形させたものを使っています。

ほかに考えられる方法としては、Groupじゃなくて単純にテクスチャのRectを引き伸ばしたりとかでしょうか。 ただテクスチャの変形だと、装飾が入っているゲージのときに、引き伸ばしにより表示が崩れてしまうので、 個人的にはBeginGroupによる方法が一番汎用的でいい気もします。

オブジェクト配列の初期化/Unityの配列の仕様

というか、オブジェクト指向言語について。 今昔の記事を見ると、分かってなさすぎてちょっと恥ずかしかったりするのですが、

var inventory:ItemIndex;
inventory = new ItemIndex[Size];
inventory[2].hogehoge();
の3行目は出来ませんよ。という話。
なぜかというと、newで宣言しているところではただ参照を格納する変数(ポインタ)を確保しているだけで、その先のobjectを生成していないから。
土地は確保したけれど、建物がマダですよ という感じ。
単一の new Hoge(foo)とちがって、コンストラクターを呼んでいないので、実態はありません

inventory = new ItemIndex[Size];
for (i = 0; i < Size; i++) {
  inventory[i] = new ItemIndex();
}
こうして、各要素の先にobjectを作ってあげる必要があります。

また、Javascript(C#も というか大抵のオブジェクト指向言語)には、

  • プリミティブな配列

var hoge = new int[50];みたいな形で宣言。
アクセスはhoge[3]とする。hoge[3].push()などのメソッドは基本的に一切持たない   割と高速

  • ArrayListクラス

var arr = new Array(); (javascript)
ArrayList arr = new ArrayList(); (C#)
みたいな形で宣言。 アクセスはarr[50]など、jsとC#ではプリミティブ配列と同じ形で可能。arr.push()、arr.pop()など、メソッドを持つ

という、2種類の配列があります。

一番の違いは、かなりざっくり言うと下のArrayListはクラスの一つ、だからメソッドがあり、余計な操作してくれるので動的な要領確保メソッドがある。
上は組み込み型(int、floatみたいなの)。だからメソッドがない。余計な操作がないので動的に要領確保できない。
厳密に言えば正確ではないのですが、大体このような認識をしておけばいいと思います。
もしどの配列を使えばいいか迷ったら、基本的には下のArrayListを使いましょう。
上はどうしても速度が出ないなど、理由がない限りは使わないでいいかと思います。
たとえばCからはじめたので、ArrayListに慣れていない という場合でもなるべく使用して使い方を覚えたほうがいいと思います。 慣れるとプリミティブよりはるかに読みやすくコードを記述できたり、配列をクラスオブジェクトとして扱うのは、他の言語でもよく使われる手法なので、かなり役立ちます。


Written by numa

5月 3rd, 2013 at 4:15 am

Posted in プログラミング

Tagged with