2011/03/17

Unityで敵が画面内におさまっているか調べる

先日から、ベジエ曲線を使ったビームを作っていますが、ターゲット(敵)をロックオンして
複数のターゲットに対してビームをうてるようになりました。

ただ、一旦ロックオンしてしまうと、ターゲット画面に表示されなくなった後もそのまま
ロックオンしたままなので、今日はターゲット(敵)が画面から見えなくなったら、その敵の
ロックオンは解除しよう。。ということに。

そこで、メインカメラ用のスクリプトに以下のようなメソッドを追加して、
逐次(Updateが呼ばれるたびに)呼び出すようにしました。

def IsInSight(target as GameObject):
    if not target:
        return false

    targetPos as Vector3 = camera.WorldToViewportPoint(target.collider.bounds.center)

    if targetPos.x < 0.0 or targetPos.x > 1.0:
        return false
    if targetPos.y < 0.0 or targetPos.y > 1.0:
        return false
    return true

いやはや、いろいろと考えることがありますね。。
ぼちぼちがんばります。

2011/03/16

ベジエ曲線のレーザー、ちょっと修正。

ベジエ曲線を使ったレーザービーム、自分の機体の向きによってビームの出る位置、射出方向が
まちまちになってしまったので、またまた苦手な計算とにらめっこ。。

今まではZ軸に回転させない状態のベジエ曲線の制御点をVector3で定義しておいて、
レーザー描画時に-90度, -45度, 45度, 90度回転させた制御点を計算していましたが、
その計算方法にミスがありました。

修正前: 制御点の回転角度だけしか考えてませんでした。
  rot = Quaternion.AngleAxis(angle, transform.forward)

修正後:制御点の回転角度、機体自体の回転状態を考慮するようにしました。
  rot = Quaternion.AngleAxis(angle, transform.forward) * transform.rotation


それ以外の処理は変更なしで、上記で求めたQuaternionに、制御点のVector3を積算して
Z軸まわりに制御点を回転させました。

いやはや、ようやく思い通りの結果になって、とてもスッキリしました。(笑

2011/03/14

ベジエ曲線のレーザー、4本にしてみました。

ベジエ曲線を使ったレーザー、4本に増やしてみました。
基本的には、1本の時と同じなのですが、それぞれのレーザーを生成する際、
ベジエ曲線の制御点の座標を自機の正面に対して任意の角度で回転させています。
任意の角度に回転させる方法として、今回は

rot = Quaternion.AngleAxis(angle, transform.forward)

で自機の正面に対するクォータニオンを求め、それをベジエ曲線の制御点(2番目、3番目)に
積算しています。



だた、自機の向きによっては、4本のレーザーが思ったように射出されないので、
計算方法は改良したほうがよさそうです。。(笑

まあ、ドラフトとしてはこんなものだということで。
これから少しづつブラシアップしていきます。

面白いんですが、頭のなかが沸騰しそうになります。。

2011/03/13

ベジエ曲線を使ってレーザービーム

いやはや。。ようやくベジエ曲線を使ってレーザービームらしきものを飛ばすことができるようになりました。
とはいっても、まだまだ手直ししないといけない部分が満載なのですが。。


赤色の線は、制御点を結んだもので黄緑色の線が3次ベジエ曲線。。のはず。(笑
でもなんか違っているような気もします。


それはさておき、とりあえずソースコードを貼付けてみました。
JavaScriptではなくBooで記述したのであまり参考にはならないかも(笑
(SyntaxHighlighterはBooのシンタックスカラーリングをしてくれないみたいなので、Pythonとして表示してみました。)

下記のBezierBeam1は、Weaponというクラスから派生したもので、BezierBeam1のメソッド_UpdatePositionは、その親クラスのメソッドUpdateから呼び出されます。つまり更新のタイミングでかならず呼び出されます。

やっていることはかなり単純で、メソッド_Blendで求めたベジエ曲線上の点の座標をtransform.positionのx, y, zそれぞれに設定しているだけです。

メソッド_Blendでは、ベジエ曲線の公式で単純に計算しているだけなので、高速化とかそのあたりについては全く考慮されていません。


import UnityEngine

class BezierBeam1 (Weapon):
    # PUBLICS
    public offsetQ1 as Vector3 = Vector3(0.0, 1.0, 1.0)
    public offsetQ2 as Vector3 = Vector3(0.0, 0.5, 1.5)
    # PRIVATES
    _goalPosition as Vector3 = Vector3.zero
    _lastT = 0.0
 
    virtual def _UpdatePosition(initialPos as Vector3):
        posQ0 = initialPos
        posQ1 = posQ0 + offsetQ1
        posQ2 = posQ0 + offsetQ2
        posQ3 = _goalPosition
 
        Debug.DrawLine(posQ0, posQ1, Color.red)
        Debug.DrawLine(posQ1, posQ2, Color.red)
        Debug.DrawLine(posQ2, posQ3, Color.red)

        _lastT += Time.deltaTime
        if _lastT > 1.0:
            _lastT = 0.0

        pos as Vector3
        pos.x = _Blend(_lastT, posQ0.x, posQ1.x, posQ2.x, posQ3.x)
        pos.y = _Blend(_lastT, posQ0.y, posQ1.y, posQ2.y, posQ3.y)
        pos.z = _Blend(_lastT, posQ0.z, posQ1.z, posQ2.z, posQ3.z)
        transform.position = pos
  
    def _Blend(t as single, q0 as single, q1 as single, q2 as single, q3 as single):
        wt as single = 1.0 - t
        val as single = (q0 * wt * wt * wt) + (3 * q1 * wt * wt * t) + (3 * q2 * wt * t * t) + (q3 * t * t * t)
        # Debug.Log("Blend = ${t} ${q0}, ${q1}, ${q2}, ${q3}, ${val}")
        return val

    def SetGoalPosition(goal as Vector3):
        _goalPosition = goal


さて、現状だと1本のビームだけで寂しいので、もう少し本数を増やしてみようかと思っています。

2011/03/11

iOS 4.3に更新完了

なんだかんだで、iOS 4.3への更新は20〜30分くらいかかりました。
けっこう時間がかかるもんですねぇ。

で、Safariがとっても早くなったかな。。と使ってみたところ、たしかに
以前使っていたときよりもキビキビと画面が更新されているような気がしますが、
びっくりするほどはかわっていない気がします。

最近Safariはあまり使っていなくて、もっぱらSleipnirのお世話にばかりなっていました。
しばらくは、Safariを使ってみようかなと思っています。

テサリングは国内のユーザーには関係なさそうです。
そういうサービス事態がないし。。

さて、今日もUnityとBlenderで遊んでみようと思います。
今日はベジエ曲線のお勉強でもしてみる予定です。

iOS 4.3に更新中

iOS 4.3に更新中です。

Safariの動作が早くなるようなので、楽しみです。
あと、別途契約が必要ですが、テサリングができるとかできないとか。

使用感などは、後日。

シューティングゲームの策敵とか

シューティングゲームで索敵する処理って、いろいろあるんでしょうね。。
理系でない私としては、そういう処理をサクサク書ける人たひがうらやましい限りです。(笑

手始めに、どこにでもありそうなシューティングを作って遊んでるんですが、
敵に自分を攻撃させる時ってどうやるのが一般的なのか、ちょっと悩み中です。

今のところ作ってみたのはPhysics.Raycastを使う方法です。
たとえば、ある範囲を1度づつずらしながらRaycastして、Colliderにヒットしたら
その方向に攻撃するといった具合です。

ただ、その方法だと、画面上に沢山敵がいる時に、処理が重くなってしまうのかも。。
とか心配になってきてます。ドキュメントだったか、Unityのフォーラムだったか忘れましたが
Raycast()を頻繁に使っても、それほどコストは高くないといった内容の文章もあったように思いますが、処理速度以外にも問題が。

特に角度をずらしながら扇形に索敵すると、敵からの距離が離れるにしたがって
Rayの密度が粗くなってしまうので、なかなか自機(Playerの機体)を発見してもらえないことがあります。

ということで、以下のように処理を変更する予定です。

(1) 敵は常に自機(Playerの機体)の場所を知っている。
(2) 敵は自機(Playerの機体)との距離と、方角をもとに攻撃対象にするかどうかを判定。
(3) 攻撃対象として認識したら、自機(Playerの機体)の位置にRaycast()。衝突判定結果が自機(Playerの機体)だったら、その方向を向いて攻撃。



といった感じで。
(3) を行うことで、敵と自分の間に障害物があったら攻撃しない賢い敵になるかな。。と
妄想中。

なかなか進まないですが、あれこれ考えている間が楽しいもんです。(笑

2011/03/09

Unity 3D始めました。

少し前からUnity 3Dで遊び始めました。
(もちろんBlender2.56も使ってます!)

Blender2.56でモデルを作って、FBX形式で出力したものを
Unitiyで表示させて。。。などなど。

理系でない頭脳の持ち主である私にとっては、
ベクトルの計算はもはや拷問以外のなにものでもありませんが(笑
いろいろと楽しんでいます。

Blenderで出力したFBXデータをUnityで読み込むと、
モデルの向きが思った通りにならないことがあるので、
どうしたものか。。
とりあえず、Unityのマニュアルには、Emptyを追加して、
FBXで読み込んだメッシュデータをその子供にすれば。。とか
書いてありましたが、あまりかっこ良い方法ではないような。。

さて、今日のメモ。

GameObjectを特定の位置(pos)の方向に向けたい場合には

transform.LookAt(pos)

で!
transformは向きを変えたいGameObjectのtransformです。

ちなみに、私はJavaScriptではなくBooでスクリプトを
書いていますが、なかなか快適です。
Pythonを知っている人であれば、すんなりとに使えるのではないでしょうか。