ソラマメブログ

2008年10月25日

Babbage Linden さんが来ました

LSL Conのイベントで、SLのMonoエンジンを担当しているBabbage Lindenさんが来てました。
BabbageLindenさん

いろいろ話してましたけど、さぶろーが気になったのは以下のような話


Mono版のSilverLightである、MoonLightのサンドボックス実行をまねて、SLに安全なC#用のサンドボックスを作りたいと言う話。

C#がなんでも出来すぎるから、サンドボックス内で実行させてSimサーバーの安全性を確保するということでいいのかな?


Previewグリッドで動いてる「プリムをHttpサーバにする機能」で、一時的なURLを使っているのを、DDNSみたいな仕組みを作って、静的URLでアクセス可能にするという話

リンデンは時々こういうスケールのでかい話をする。面白い発想だと思いました。
***追記*** これは勘違いでした。そういう仕組みを自分で作って対処してくださいということでした。


Http通信を使えば、スクリプトのライブラリ化が出来るよという話

このあたりは英語よく分からなかったから間違えてるかも
***追記*** これも勘違いでした(勘違い率50%突破)。なにかライブラリ化を促進するための仕組みが用意されるようです。どんな形式なのかはいまいち分かりませんでしたが、Import文とかで別のLSLを参照したりとか出来るといいですね。


Fakeさんが、Http Server in Primの返す、Content-Type Headerを、text/plain以外に設定できるようにお願い → Babbageさんは、Kellyさんに言ってみますとのこと

Content-Typeが自由に設定できるようになれば、text/htmlを設定してブラウザでプリムからもらったHTMLを閲覧できるなどが出来るようになる! これも面白い発想でした。プリムの周りで起こったことをRSSで配信とかも出来るようになるかなと妄想。


さぶろーは英語あんまり得意じゃないので間違いもあるかも。おかしな点があればコメントで指摘してください^^  
タグ :LSLLSL Con

Posted by sabro at 01:17Comments(0)TrackBack(0)LSL

2008年10月19日

LSLCon2008 開幕

いやー始まりましたね。

http://lsl-con.org/2008/
LSLConロゴ

初日のイベントは、アイテムデモやスクリプター会など、どれも濃い内容でした。さらに常時閲覧可能な展示物や、スクリプトを学びながら遊べるクエストなど、イベント以外にも盛りだくさんの内容となっています。

さぶろーが、SLを始めて最初に体験した大きなイベントが去年のLSLConで、このイベントは特別な思い入れがあります。前回は見てるだけでしたが、今回は半年かけて制作してきたアバターを展示しています。

昨日は制作が間に合わなくて、展示ブースは同人誌を落としたコミケブースみたいになってましたけど、今日やっと動く状態になったので、コソッと設置してきました。

今はまだバグも多く、テスト段階なので、大規模な告知はなしです。興味のある方は直接会場で試してみてください^^

LSLCon2008会場
http://slurl.com/secondlife/New%20Script/230/183/30  

Posted by sabro at 04:20Comments(0)TrackBack(0)LSL

2008年10月16日

VimでLSLを書く環境を整える

SabroがLSLを書く時は、今まで、LSL-Editorを使ってきたのですが、これは日本語を入力するとフォントが崩れてしまいますし、さらに最近フォントを弄ったら英語の入力でもフォントがおかしくなるようになってしまったので(Sabroの環境だけ?)、エディタをVimに変更してみることにしました。

Vimはシンタックスカラーのハイライトが出来るほか、Vim7からはlslEditorほど親切でないにしてもキーワードの自動補完が出来るようになっているので、、そこそこ楽にコーディングできます。


以下環境の作り方 (Windows用Kaoriya版向け)


シンタックスハイライト

  1. Shillというページに、lsl.vimファイルがあるのでダウンロード

  2. lsl.vimにはバグがあるので、I sort my thought... LSL用Vim Syntaxファイルを参考にして修正。

  3. lsl.vimを、Vimのruntime/syntaxフォルダへほりこむ ノ ̄∇ ̄)ノ

  4. runtime/filetype.vimの、「augroup filetypedetect、augroup END」の間に以下を追記
    au BufNewFile,BufRead *.lsl			setf lsl



自動補完

  1. シンタックスハイライトと同じくShillから、lsl.dictファイルをダウンロード

  2. vim.dictファイルを適当なフォルダに設置。Sabroはそのへんの作法とかよく知らないんですが、runtime/dictというフォルダを作ってそこへ入れときました。

  3. vimrcに以下を追記(dictのあるフォルダは環境によって変えてください)
    autocmd FileType lsl set dictionary+=$VIMRUNTIME/dict/lsl.dict


ふぅ、まあこんなことしてる場合じゃないんですけどね。明後日LSL Conだというのに・・・ orz
正直間に合うかどうか微妙なところ。(_ _ ||

追記: 
あっ。自動補完にはautocomplpopが便利ですよ。というかこれがないと個人的には使い物になりません。  
タグ :vimLSL

Posted by sabro at 19:29Comments(2)TrackBack(0)LSL

2008年08月21日

LSLにおけるGPLの効力ってどれくらいの範囲?

久方ぶりです。

最近は更新頻度が低くて何もしてないように見えますが、実はしっかりアバター制作を進めてます。まあ、アバター制作にすでに5ヶ月かけてる時点でアレですが・・・。

で、アバターはアニメ調にしようと考えてるので、デフォルトのアニメーションではフィットしないなあと思い、AO(アニメーションオーバーライド)することにしたのです。

AOのスクリプトを1から作るのは結構大変そうだと思い、Tinyアバターのボディークラッシャーに入っているスクリプトを使わせてもらおうかとソースを見てみたのですが、これってGPLだったんですね Σ( ̄□  ̄ ) てっきり、修正BSDかMITあたりかと思っていました。

以下、スクリプトのコメントを一部抜粋。

//
// Don't ask me for tech support. I won't give it.
// Copyright (C) 2004 Francis Chung
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 U



実は、セキュリティの関係でスクリプトの1つを閲覧不可にしたかったのですが、GPLの効力がどれくらい効くのか、よく分からなくて困っています。

まず、AOスクリプトと、ListenやLinkMessageで通信を行う場合は、それらのソースは公開する必要があると思います(多分)。では、通信が発生しなければどうなんでしょうか? 同じプリム内にあるスクリプトは公開しなければいけない気もしますけどねぇ。

たとえば、AOのスクリプトに対して、別のスクリプトの取り得る格納位置として以下のような場合があると思います。

  1. 同じプリム内

  2. 同じオブジェクトの別のプリム内

  3. 別のオブジェクトに入っているが、1つの商品として扱われる場合(オブジェクトと操作用HUDとか)

  4. まったく関係ない別のオブジェクトに入っている場合


これらのうち、ソース公開の必要があるのはどこまででしょうか?4は公開の必要はないと思いますが・・・。ちなみにSabroが絶賛制作中のアバターでは、上記3のスクリプトを非公開にしたいです。

Windowsアプリとかで、GPLのDBをアプリケーションに付属して配布する場合でも、ソース公開の義務があった気がするので、やっぱりダメだろうなぁ (_ _ |||

やはり車輪の再発明が必要か (つ д`)

それにしても、こうしてみると上記のようなパターンに柔軟に対応できるLSL用のライセンス体系とかほしくなりますね(^^)  

Posted by sabro at 00:19Comments(3)TrackBack(0)LSL

2008年01月29日

LSLスクリプトからアバターを回転させるには

LSLからアバターを動かすのは、わりと簡単。
だいたい次のような方法があります。
  • アタッチメントからllMoveToTarget、llSetForce、llApplyImpulse等を使う
  • llPushObjectを使う
  • オブジェクトや乗り物に座らせて、そちらを動かす

でも、LSLからアバターを回転させるのは難しいです。
回転の関数として、llLookAt、llRotLookAt、llSetTorqueなどがありますが、これらはアタッチメントから使っても、オブジェクトが回転する、もしくは何も起こらないだけでアバターには作用しません。また、自分は今までllPushObjectの第3引数に値を設定すれば、出来るんじゃないかと思ってたのですが、これも駄目でした。第2引数での移動は出来るのに・・・ (-_- )

llPushObject(key id, vector impulse, vector ang_impulse, integer local)

JIRAにも要望があったので多分関数一発では出来ないんでしょう。
New Feature -> LSL -> Agent -> Rotation Control

なので、どうしても回転させたい場合は、オブジェクトに座らせて、そのオブジェクトを回転させることになります。できればSpirittanでは、移動制御時にオブジェクトに座らせたくないのですが、ダッシュ中の方向転換とかを、きれいに出来るようにするには、座り方式でいくしかないみたいです。う~ん困った。  
タグ :LSL物理

Posted by sabro at 01:28Comments(2)TrackBack(0)LSL

2007年12月28日

LSL-Editorでユーザ定義変数も補完する

LSLの開発には、LSL-Editorを使用しています。このエディターはコード自動補完が優秀なのですが、デフォルトの設定ではユーザ定義変数の補完機能がOFFになっています(もしかしたら、最近のバージョンをインストールするとONになってたりするかもしれません)

オプション画面

メニューから、「Tools → options → Text Editor → Code Completion」と進んで、真ん中のチェックをONにするだけで補完が効くようになります。お手軽なので、使ってる人はぜひONにしておきましょう。

ちなみに、なぜ今頃こんなエントリを書いたかというと、自分は今日気づいたからです。お、遅い・・・orz  
タグ :LSLLSL-Editor

Posted by sabro at 22:44Comments(0)TrackBack(0)LSL

2007年12月01日

ホーミング弾の作り方

以前ちらっと書いたとおり、Spirittanにはホーミング弾が存在します。その作り方がなかなか難しかったので、ちょっと公開してみます。

ホーミングというとまず思い浮かぶのは、llSensorとllMoveToTargetの組み合わせによる追尾型のアタッチメントですが、llMoveToTargetをホーミング弾に使用すると、どうしてもカクカクした動きになり見栄えがよくありません。

そこで、SpirittanではllSetForce関数で弾に力を加えることで、徐々に曲がっていく感じの弾を作ってみました。

以下は、弾に埋め込んであるスクリプトのホーミング関連部分のみ抜き出したものです。
// ホーミング対象(敵)のKey
key enemyKey = "xxxx-xxxx-xxxx-xxxx";

// 弾が発射された地点
vector firstPos;

// 敵の現在地へ弾を移動させるために必要な力を計算する
vector getForce(vector enemyPos)
{
    vector myPos = llGetPos();
    vector vel = llGetVel();
    vector acc = llGetAccel();

	// 弾と敵の距離
	vector distance = enemyPos - myPos;

	// 弾発射地点から見て、敵より弾の方が遠い位置にあれば力は加えない
	vector firstPosDistance1 = enemyPos - firstPos;
	vector firstPosDistance2 = llGetPos() - firstPos;
	if(llVecMag(firstPosDistance2) > llVecMag(firstPosDistance1))
	{
		return ZERO_VECTOR;
	}

	// 弾を敵の現在地へホーミングさせるために必要な、現在の速度と直角方向の加速度
	float theta = llRot2Angle(llRotBetween(distance, vel));
    float velMag = llVecMag(distance) * llCos(theta);
    float time = velMag / llVecMag(vel);
    vector newacc = (2 * (enemyPos - (myPos + time * vel)) / 
    	llPow(time, 2)) - acc;

	// 加速度が大きすぎる場合は補正
	if(llVecMag(newacc) > 10)
	{
		newacc = newacc * 10 / llVecMag(newacc);
	}

	// 力 = 質量 × 加速度    
    return llGetMass() * newacc;
}


default
{
	on_rez(integer start_param)
	{
		// 弾を浮かせる設定
		vector v = llGetPos();
		llSetHoverHeight(v.z - llGround(<0.0,0.0,0.0>), FALSE, 1.0);

		// 1秒ごとに敵をサーチ
		llSensorRepeat("", enemyKey, AGENT, 100, PI, 1.0);

		// Rezされた位置を記録しておく
		firstPos = llGetPos();
	}

	sensor(integer total_number)
	{
		vector pos = llDetectedPos(0);

		// 敵が見つかった場合、弾をホーミングさせるために力を加える
		llSetForce(getForce(pos), FALSE);
	}
}

このスクリプトには、次の要素があります。
グローバル変数
  • enemyKey (ホーミング対象(敵)のKey、実際は発射直後に取得)
  • firstPos (弾が発射された地点)

グローバル関数
  • getForce (ホーミングさせるために弾に加える力を計算)

defaultステートのイベント
  • on_rez (弾が生成された直後の処理)
  • sensor (敵を発見した際の処理)


大まかに説明すると、on_rez時にllSensorRepeatで毎秒サーチを行うよう設定し、敵が見つかったらsensorイベントで弾に力を加えます。加える力の大きさは、getForce関数で計算しています。

このスクリプトの肝は、弾に加える力を計算するgetForce関数です。他の部分は特に難しいことはしていないので、この関数に絞って解説します。


最初に弾の位置、速度、加速度を取得した後、敵⇔弾間の距離を取得します。
	// 弾と敵の距離
	vector distance = enemyPos - myPos;
図1


次に、発射地点から敵までの距離と、弾までの距離をチェックして、弾の方が遠い場合は加える力をZERO_VECTORにしています。こうしておかないと、弾をよけても後ろからホーミングしてしまいます。llVecMag関数でベクトルの大きさを取得して距離を比較しています。
	// 弾発射地点から見て、敵より弾の方が遠い位置にあれば力は加えない
	vector firstPosDistance1 = enemyPos - firstPos;
	vector firstPosDistance2 = llGetPos() - firstPos;
	if(llVecMag(firstPosDistance2) > llVecMag(firstPosDistance1))
	{
		return ZERO_VECTOR;
	}
図2
後ろからホーミング



チェックが終わった後は、弾に加えるべき加速度を計算しています。これは、以下のような手順で行います。
  1. 弾⇔敵を結ぶ直線と、弾の進行方向の間の角θを求める
  2. llCos関数を使って、図のような弾進行方向の進むべき距離velMagを計算する
  3. 先ほど求めたvelMagを進むのに、今のスピードでどれだけの時間が掛かるか求める
  4. 物理の公式を使って、距離、時間から赤い矢印方向へ必要な加速度を求める
	// 弾を敵の現在地へホーミングさせるために必要な、現在の速度と直角方向の加速度
	float theta = llRot2Angle(llRotBetween(distance, vel));
    float velMag = llVecMag(distance) * llCos(theta);
    float time = velMag / llVecMag(vel);
    vector newacc = (2 * (enemyPos - (myPos + time * vel)) / 
    	llPow(time, 2)) - acc;
図3
4で使う公式は、等加速度直線運動の公式です。あったねこんなの。
数式
距離 = 初速 × 時間 + 1/2 × 加速度 × 時間^2

図の赤い矢印の方向への初速は0なので右辺の第1項は0になります。時間tは手順3で取得済みです。距離Sは「enemyPos - (myPos + time * vel)」で求めています。あとは、加速度が左辺にくるように整理してから、現在の加速度accを引くことで加えるべき加速度newaccが求められます。


求まった加速度が大きすぎる場合は、補正をかけます。今回の例では加速度ベクトルの大きさが10より大きかった場合は、大きさが10になるように調整しています。これをしておかないと弾がものすごいスピードで曲がってきて不自然な動きになります。
	// 加速度が大きすぎる場合は補正
	if(llVecMag(newacc) > 10)
	{
		newacc = newacc * 10 / llVecMag(newacc);
	}
不自然な弾の動き



最後に運動方程式(F=ma)を使って、加速度から力を求めて返します。
	// 力 = 質量 × 加速度    
    return llGetMass() * newacc;


あとは、llSetForce関数の第2引数をFALSEにして、グローバル軸にたいして力をかけてあげれば完了です。

完成した弾
  
タグ :LSL物理

Posted by sabro at 21:06Comments(6)TrackBack(0)LSL

2007年11月01日

同一プリム内のすべてのスクリプトをリセットする

小さな小さなネタ。

スクリプトがおかしな状態にならないよう、しっかり作りたかったのですが、外部アバターのSayや想定外なCollisionとか、はたまた、微妙なタイミングでのログオフやSLクライアントのハングアップなど、対応事項が多すぎるので、もうユーザの手動リセット作ってゴマカしとけという思いでリセット関数作ることにしました。

以下の関数を呼び出すと、同一プリム内のすべてのスクリプトをリセットします。
(同一オブジェクト内ではないので注意)
resetAllScript()
{
	integer i;
	for(i=0; i<llGetInventoryNumber(INVENTORY_SCRIPT); i++)
	{
		llResetOtherScript(llGetInventoryName(INVENTORY_SCRIPT, i));
	}
}

For文では、llGetInventoryNumberで、コンテンツ内のスクリプトの数を取得し、その数だけループをまわしています。そして、llGetInventoryNameで、スクリプト名を取得して、llResetOtherScriptに引き渡してリセットしてるわけです。

以外に小さい関数になってビックリ。エントリにするまでもなかったか・・・


追記:

先ほどのスクリプト、バグがありました。上記のままでは、リセットを実行しているスクリプト自身もリセットされてしまうので、まだリセットすべきスクリプトが残っているうちに自分がリセットされてしまうと、それ以後のリセットがされなくなります。

バグ修正版を載せておきます。こちらは、スクリプト名が自分自身の場合、リセットを飛ばすようになっています。
resetAllScript()
{
	integer i;
	for(i=0; i<llGetInventoryNumber(INVENTORY_SCRIPT); i++)
	{
		string scriptName = llGetInventoryName(INVENTORY_SCRIPT, i);
		if(scriptName != llGetScriptName())
		{
			llResetOtherScript(scriptName);
		}
	}
}

自分をリセットしないので、完璧なものではないです。メインのスクリプトと分けて、リセットをトリガするだけの小さなスクリプトとして使うのがいいと思います。


追記:

maayaさんにもらったコメントを反映して修正しました。
これで、自分自身もリセットされます^^
resetAllScript()
{
	integer i;
	for(i=0; i<llGetInventoryNumber(INVENTORY_SCRIPT); i++)
	{
		string scriptName = llGetInventoryName(INVENTORY_SCRIPT, i);
		if(scriptName != llGetScriptName())
		{
			llResetOtherScript(scriptName);
		}
	}
	llResetScript();
}
  
タグ :LSLTips

Posted by sabro at 20:51Comments(4)TrackBack(0)LSL

2007年09月14日

パーティクル小ネタ

プリム本体に向かって飛んでくるパーティクルです。

溜め撃ちみたいな、武器をつくりたかったので。

particle

パーティクル関数のソース。使ってたのをそのまま持ってきたから、いらないパラメータも、いっぱいあるかも。
getEnergy1(vector color){    // 色は変更可にしてあります
    llParticleSystem([
        PSYS_PART_FLAGS, PSYS_PART_EMISSIVE_MASK | 
                         PSYS_PART_TARGET_POS_MASK,  // これがポイント
        PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_EXPLODE,
        PSYS_PART_START_ALPHA, 1.0,
        PSYS_PART_END_ALPHA, 0.0,
        PSYS_PART_START_COLOR, color,
        PSYS_PART_END_COLOR, color,
        PSYS_PART_START_SCALE, <1.2, 1.2, 1.2>,
        PSYS_PART_END_SCALE, <1.2, 1.2, 1.2>,
        PSYS_SRC_MAX_AGE, 0.0,
        PSYS_PART_MAX_AGE, 1.0,
        PSYS_SRC_ACCEL, <0.0, 0.0, 0.0>,
        PSYS_SRC_ANGLE_BEGIN, PI,
        PSYS_SRC_ANGLE_END, PI,
        PSYS_SRC_BURST_PART_COUNT, 1,
        PSYS_SRC_BURST_RADIUS, 3.0,   // ここでパーティクル半径を指定
        PSYS_SRC_BURST_RATE, 0.0,
        PSYS_SRC_BURST_SPEED_MIN, 0.0,
        PSYS_SRC_BURST_SPEED_MAX, 0.0,
        PSYS_SRC_OMEGA, <0.0, 0.0, 0.0>,
		PSYS_SRC_TEXTURE, ""
		PSYS_SRC_TARGET_KEY, llGetKey()   // ターゲットを自分に指定
    ]);
}

PSYS_PART_FLAGS に PSYS_PART_TARGET_POS_MASKを指定すると、PSYS_SRC_TARGET_KEYで指定したターゲットに、パーティクルが飛ぶようになります。

アタッチしてみた


余談ですが、このブログに書かれたスクリプトは、自由に自分の作品に組み込んでもらったりしてかまいません。ただ、検証不十分なことも多いので、十分にテストして自己責任でお使いください。  

Posted by sabro at 01:04Comments(0)TrackBack(0)LSL

2007年08月26日

物理オブジェクトの回転を防ぐ

物理オブジェクトって体当たりすると、くるくる回転しちゃうよね。

昔、移動制御用の物理オブジェクトが回転して、制御されているアバターも回りだしちゃったことがあって、対策したから書いとこーかな。

実は、最初に対処法を探したときは、LSL関数の一覧をダーっと見たんだけど、回転を止めるみたいな関数はなかったんで、サラリとあきらめた orz

で、2週間くらい前にリファレンスをタラタラ見てたら、llSetStatus関数に、STATUS_ROTATE_Xみたいなパラメータを発見。X軸の周りを回転させる、させないを制御できるらしい。YとZもあった。

これらのパラメータをFALSEにセットしてやれば、
回転しない物理オブジェクトの出来上がり\(^o^)/

state_entry()
{
// stop rotation X Y Z
llSetStatus(STATUS_ROTATE_X |
STATUS_ROTATE_Y |
STATUS_ROTATE_Z,
FALSE);
}

こうすれば、Z軸の周りのみ回転させることもできる。
state_entry()
{
    // stop rotation X Y
    llSetStatus(STATUS_ROTATE_X | STATUS_ROTATE_Y, FALSE);
    
    // not stop rotation Z
    llSetStatus(STATUS_ROTATE_Z, TRUE);
}

で、ちょっとした実験。微妙に浮かした物理オブジェクトに体当たりしてみる。左は全方位回転、真ん中はZ軸のみ回転、右は回転しない。


以下が実験のムービー

ちゃんとできてる(^_^)  
タグ :tipsLSL

Posted by sabro at 19:34Comments(1)TrackBack(0)LSL