2016年01月27日
飛行機をつくる:(2) カメラコマンドをつける
2回目は前回のなんちゃって飛行機にカメラ制御を実装します。
正確にはなんちゃって飛行機にも簡単な方のカメラ制御は既についていて、その部分は以下の2行(state_entry内)です。
今回はこの2行ではなくて、チャットコマンドの「C」で切り替わる事が多いダイナミックカメラを対象にします。
読者の対象としては「スクリプトをかじってはいるものの、どうやってサクサクと考えていけばいいのかの道筋が今一つ分からない方」を対象にします。つまり、スクリプター(またはところてん)が脳内で考えている事の暴露(笑)となります。
前回、スクリプトは常に「~したら**」する、という部品の集合体だと述べました。というより、その形をはっきりイメージしないとスクリプトは決して作れません。なので、まず最初にやるべきことをこの「~したら**」に従ってストーリーにします。
といってもそれほど難しい事ではなくて、よそ様(あるいは私やてっちゃん)が販売している飛行機に乗っていて普段している自分の事を言葉にして並べるだけです。例えば・・・
このうち、カメラに関係ありそうなのは3)の部分だけなので、要するに「チャットでパイロットが「C」と喋った(他の人は無視)のを聴いたらカメラを切り替える」という機能を追加すればOK!という事です。
続いて、このストーリー3)について分からない部分をぐぐります。ここで一つコツというかお約束があります。それは、
必ず最初にリンデンの公式のLSL解説WIKIに目を通す
これがとても大事です。リンデンのサイトの場合ぐぐっても部品がヒットするだけで全体像が見えにくいのは確かなのですが、部品の説明に先に触れておき、触れる回数を増やしていくとサンプルの理解力が段々上がっていきます。また、サンプルは通常特定の事が出来る完成品として、それに関する説明しか書いてありませんが、リンデン公式の場合は下の方に「関連」や「警告(注意事項)」が書いてあったりして、今は関係ないものの見ておくと良い他の関連情報も見つけられます。
チャットを聞けるようになる方法が分からない場合は、まずはイベントを調べます。このページの中に登場しているリンク先はスクリで出来る「~したら」の全てで、これ以外の事はスクリでは原則出来ません。
該当するのは「listen」イベントですので、「~したら」の部分はこれで行う事になります。つまり「listen」イベントで「C」を聴くことが出来る様になれば良いわけですね。答えはもうそこに書いてあります。
「チャットによって発生します。 llListen を使って開始と検索条件の設定を行います。」
だそうなので、次に「llListen」の説明を読みます。
ややこしい単語は無視して概要を総合すると、llListenという命令は、指定のチャットチャンネルで、指定の検索条件に合致する発言を聴く事を開始する、という命令です。
なので「チャットでパイロットが「C」と喋った(他の人は無視)のを聴いたらカメラを切り替える」に戻ると、まずは、
聴くべき文字も指定できるのですが、パイロットが「c(半角小文字)」というか「C(半角大文字)」というか「C(全角大文字)」というか「c(全角小文字)」というか分かりませんので、聴くべき文字列は指定しません。ユーザーの利便性対応は大変です(笑)。
また、パイロットがいつ「C」と喋るかはパイロットの好き勝手ですので、パイロットが座ったら即座に聴くのを開始しないといけません。ですので、「~したら**」するをもう少し細かく変更します。つまり、
自前でスクリプトを作るとはこんな感じで、最初に大雑把な「~したら**する」をイベントと処理の組み合わせに置き換えて、それを段々と細かくしていく作業に他なりません。
パイロットが座ったかどうかの判定はchangedイベントの中でしていますので、私なら下の様にします。
listenイベントの冒頭で唱えているllToLower()は半角アルファベットを全て小文字にせよという命令です。一旦それで全ての半角文字を小文字にした後に、if (_command=="c" || _command=="c" || _command=="C")のところで「c(半角小文字)」または「c(全角小文字)」または「C(全角大文字)」だった場合は、と場合分けを入れています。「==」は等しい、「||」(SHIFT+¥を2回)は「または」の意味です。
ではいよいよ、怪しげなカメラをくっつけます。「パイロットが座ったらコマンドを聞きはじめ、Cと聞いたらカメラ制御をする」というストーリでした。「Cと聞いたら」までは出来上がっているので、引き続きぐぐります。
検索結果の中でまずはリンデンWIKIを開いてみます。すると、
「実行するには、llRequestPermissions による PERMISSION_CONTROL_CAMERA 権限が必要です。」
と書いてあります。この手の「権限が云々」という言葉がリンデンWIKIに出てくるときは、スクリがそれを行うにはアバターの許可が必要であるという意味で、その場合は必ずllRequestPermissions()を唱えます。
llRequestPermissions()を見ると、関係ありそうなのは「PERMISSION_CONTROL_CAMERA」です。権限の要求はパイロットが座った時にキー操作を要求していますので、その部分を書き換えてやればよい事が分かります。
続いて、「C」を聞いたら、の所にカメラ操作命令を入れてやります。直接そこに書き込んでも良いのですが、カメラ操作も意外と改造をしていくとあちこちで同じ処理をしたくなることが多いので、私はいつも関数としてスクリの上の方に書いておいています。listenの中はこんな感じです。
関数「setCamera()」の方はこんな感じです。
カメラの具体的なパラメーターは私が販売時に乗せている「シネマカメラ」と全く同じものです。この種のパラメーター設定をする物はパーティクルにしろカメラにしろ、理解するのに最も近道は具体的に数字を変えてみてどうなるかやってみる事です。カメラは簡単な方ですが、それでも説明を読んでも多分全く意味不明でしょうし、カメラを変えて飛行してみるだけで一日や二日は楽しく遊べます。
と、申しますか、是非遊んでみてください。カメラに凝った乗り物は意外と販売品でも少ないのですが、乗り物エンジンの方を全く変えなくても、カメラを変えるだけで乗り心地がガラリと変わって感じます。意外と腕の見せ所です。(↓例えばこんな感じです↓)
また、カメラパラメーターの変更でこの手の実験と結果の確認作業に慣れておくと、乗り物機能の複雑奇怪なパラメーターについても自分で調整して変更する作業の準備になります。SL内のこの場所に行くとゼロ戦と95式水上偵察機のデモ版が看板からREZ出来ます。コマンド「C」で3種類のカメラが両方に仕込んでありますので、カメラパラメーターと乗り物機能の設定差による、乗り味の違いを体験してみてください。シネマカメラは上と同じもので、ダイナミックカメラとカメラ操作なしモードは2機種で別のパラメーターになっています。
ということで、今回の完成状態は以下の枠内になりました。
次回は乗り物機能の細かいパラメーターを細かく調整できるように改造してみようと思います。
ひとつ前を読む
正確にはなんちゃって飛行機にも簡単な方のカメラ制御は既についていて、その部分は以下の2行(state_entry内)です。
llSetCameraEyeOffset(<-5.0,0.0,1.0>); //座った時のカメラの位置を指定します。
llSetCameraAtOffset(<2.0,0.0,0.0>); //座った時にカメラが見ている位置を指定します。
この二行は、座った時のカメラの位置と、座った時にカメラが見ている場所を指定しています。販売されている飛行機では必ずこの2つは指定されていて、デフォルトの状態ではこの設定が有効化されています。llSetCameraAtOffset(<2.0,0.0,0.0>); //座った時にカメラが見ている位置を指定します。
今回はこの2行ではなくて、チャットコマンドの「C」で切り替わる事が多いダイナミックカメラを対象にします。
読者の対象としては「スクリプトをかじってはいるものの、どうやってサクサクと考えていけばいいのかの道筋が今一つ分からない方」を対象にします。つまり、スクリプター(またはところてん)が脳内で考えている事の暴露(笑)となります。
1:全体の計画
前回、スクリプトは常に「~したら**」する、という部品の集合体だと述べました。というより、その形をはっきりイメージしないとスクリプトは決して作れません。なので、まず最初にやるべきことをこの「~したら**」に従ってストーリーにします。
といってもそれほど難しい事ではなくて、よそ様(あるいは私やてっちゃん)が販売している飛行機に乗っていて普段している自分の事を言葉にして並べるだけです。例えば・・・
1)座る
2)スロットルを上げて飛ぶ
3)チャットに「c」と入れてカメラを好きな状態にする
4)飛び回る
最初はこの程度です。2)スロットルを上げて飛ぶ
3)チャットに「c」と入れてカメラを好きな状態にする
4)飛び回る
このうち、カメラに関係ありそうなのは3)の部分だけなので、要するに「チャットでパイロットが「C」と喋った(他の人は無視)のを聴いたらカメラを切り替える」という機能を追加すればOK!という事です。
続いて、このストーリー3)について分からない部分をぐぐります。ここで一つコツというかお約束があります。それは、
必ず最初にリンデンの公式のLSL解説WIKIに目を通す
これがとても大事です。リンデンのサイトの場合ぐぐっても部品がヒットするだけで全体像が見えにくいのは確かなのですが、部品の説明に先に触れておき、触れる回数を増やしていくとサンプルの理解力が段々上がっていきます。また、サンプルは通常特定の事が出来る完成品として、それに関する説明しか書いてありませんが、リンデン公式の場合は下の方に「関連」や「警告(注意事項)」が書いてあったりして、今は関係ないものの見ておくと良い他の関連情報も見つけられます。
2:チャットを聞けるようにする
チャットを聞けるようになる方法が分からない場合は、まずはイベントを調べます。このページの中に登場しているリンク先はスクリで出来る「~したら」の全てで、これ以外の事はスクリでは原則出来ません。
該当するのは「listen」イベントですので、「~したら」の部分はこれで行う事になります。つまり「listen」イベントで「C」を聴くことが出来る様になれば良いわけですね。答えはもうそこに書いてあります。
「チャットによって発生します。 llListen を使って開始と検索条件の設定を行います。」
だそうなので、次に「llListen」の説明を読みます。
ややこしい単語は無視して概要を総合すると、llListenという命令は、指定のチャットチャンネルで、指定の検索条件に合致する発言を聴く事を開始する、という命令です。
なので「チャットでパイロットが「C」と喋った(他の人は無視)のを聴いたらカメラを切り替える」に戻ると、まずは、
パイロットが座ったらllListenをチャンネルゼロ(普通のチャット)で唱える。
その時、パイロットだけを聴く対象にする。
という事になります。その時、パイロットだけを聴く対象にする。
聴くべき文字も指定できるのですが、パイロットが「c(半角小文字)」というか「C(半角大文字)」というか「C(全角大文字)」というか「c(全角小文字)」というか分かりませんので、聴くべき文字列は指定しません。ユーザーの利便性対応は大変です(笑)。
また、パイロットがいつ「C」と喋るかはパイロットの好き勝手ですので、パイロットが座ったら即座に聴くのを開始しないといけません。ですので、「~したら**」するをもう少し細かく変更します。つまり、
1)座る
2)座ったパイロットの発言を聞けるようにllListenを唱える
3)チャットで「c」が聞こえた(listenイベントが発生して発言が「c」だった)らカメラを何かする
という事になります。2)座ったパイロットの発言を聞けるようにllListenを唱える
3)チャットで「c」が聞こえた(listenイベントが発生して発言が「c」だった)らカメラを何かする
自前でスクリプトを作るとはこんな感じで、最初に大雑把な「~したら**する」をイベントと処理の組み合わせに置き換えて、それを段々と細かくしていく作業に他なりません。
パイロットが座ったかどうかの判定はchangedイベントの中でしていますので、私なら下の様にします。
changed(integer change)
{
//プリムやスクリプトに状態変化があった場合のイベント
if (change & CHANGED_LINK)
{
//リンクが変更になった
key _av=llAvatarOnSitTarget(); //座っているアバターのUUIDを取得します。
if (_av!=NULL_KEY) //NULL_KEYでない⇒誰かが座っている。
{
if (pilot==NULL_KEY) //pilotがNULL_KEY⇒誰かが初めて座った。
{
pilot=_av; //pilotに座った人のUUIDを設定
llRequestPermissions(pilot,PERMISSION_CONTROL_CAMERA | PERMISSION_TAKE_CONTROLS); //カメラ操作とパイロットのキーやマウス操作の監視の権限を要求します
llListenRemove(handle); //追加:今まで聞いていたかもしれないListenをやめます。
handle=llListen(0,"",pilot,""); //追加:パイロットのチャット発言の傍受を開始します。
}
}
else //座っているアバターのUUIDがNULL_KEYなら誰かが立ち上がったか、または最初から座っていません。
{
init();
}
}
}
listen(integer channel, string name, key id, string message)
{
string _command=llToLower(message); //半角アルファベットをすべて小文字にします
if (_command=="c" || _command=="c" || _command=="C")
{
//コマンド”C”。飛行機では一般的にこのコマンドはカメラ操作に割り当てられます。
//ここで何かカメラを操作するか変更します
}
}
部分の抜粋ですので上だけでは動かないのですが、llListenを唱える前にllListenRemoveを唱えるのはお約束の構造です。何故そうしなければならないのかは考えてみてください。{
//プリムやスクリプトに状態変化があった場合のイベント
if (change & CHANGED_LINK)
{
//リンクが変更になった
key _av=llAvatarOnSitTarget(); //座っているアバターのUUIDを取得します。
if (_av!=NULL_KEY) //NULL_KEYでない⇒誰かが座っている。
{
if (pilot==NULL_KEY) //pilotがNULL_KEY⇒誰かが初めて座った。
{
pilot=_av; //pilotに座った人のUUIDを設定
llRequestPermissions(pilot,PERMISSION_CONTROL_CAMERA | PERMISSION_TAKE_CONTROLS); //カメラ操作とパイロットのキーやマウス操作の監視の権限を要求します
llListenRemove(handle); //追加:今まで聞いていたかもしれないListenをやめます。
handle=llListen(0,"",pilot,""); //追加:パイロットのチャット発言の傍受を開始します。
}
}
else //座っているアバターのUUIDがNULL_KEYなら誰かが立ち上がったか、または最初から座っていません。
{
init();
}
}
}
listen(integer channel, string name, key id, string message)
{
string _command=llToLower(message); //半角アルファベットをすべて小文字にします
if (_command=="c" || _command=="c" || _command=="C")
{
//コマンド”C”。飛行機では一般的にこのコマンドはカメラ操作に割り当てられます。
//ここで何かカメラを操作するか変更します
}
}
listenイベントの冒頭で唱えているllToLower()は半角アルファベットを全て小文字にせよという命令です。一旦それで全ての半角文字を小文字にした後に、if (_command=="c" || _command=="c" || _command=="C")のところで「c(半角小文字)」または「c(全角小文字)」または「C(全角大文字)」だった場合は、と場合分けを入れています。「==」は等しい、「||」(SHIFT+¥を2回)は「または」の意味です。
3:カメラをくっつける
ではいよいよ、怪しげなカメラをくっつけます。「パイロットが座ったらコマンドを聞きはじめ、Cと聞いたらカメラ制御をする」というストーリでした。「Cと聞いたら」までは出来上がっているので、引き続きぐぐります。
検索結果の中でまずはリンデンWIKIを開いてみます。すると、
「実行するには、llRequestPermissions による PERMISSION_CONTROL_CAMERA 権限が必要です。」
と書いてあります。この手の「権限が云々」という言葉がリンデンWIKIに出てくるときは、スクリがそれを行うにはアバターの許可が必要であるという意味で、その場合は必ずllRequestPermissions()を唱えます。
llRequestPermissions()を見ると、関係ありそうなのは「PERMISSION_CONTROL_CAMERA」です。権限の要求はパイロットが座った時にキー操作を要求していますので、その部分を書き換えてやればよい事が分かります。
llRequestPermissions(pilot,PERMISSION_CONTROL_CAMERA | PERMISSION_TAKE_CONTROLS);
こんな感じです。記号「|」はビット計算記号ですので、この場合「キー操作とカメラの制御」をパイロットに要求していることになります。これで準備はOKです。続いて、「C」を聞いたら、の所にカメラ操作命令を入れてやります。直接そこに書き込んでも良いのですが、カメラ操作も意外と改造をしていくとあちこちで同じ処理をしたくなることが多いので、私はいつも関数としてスクリの上の方に書いておいています。listenの中はこんな感じです。
listen(integer channel, string name, key id, string message)
{
string _command=llToLower(message); //半角アルファベットをすべて小文字にします
if (_command=="c" || _command=="c" || _command=="C")
{
//コマンド”C”。飛行機では一般的にこのコマンドはカメラ操作に割り当てられます。
camon=!camon; //カメラ状態を現在と逆にします。
setCamera(); //カメラ状態を反映させます。
}
}
{
string _command=llToLower(message); //半角アルファベットをすべて小文字にします
if (_command=="c" || _command=="c" || _command=="C")
{
//コマンド”C”。飛行機では一般的にこのコマンドはカメラ操作に割り当てられます。
camon=!camon; //カメラ状態を現在と逆にします。
setCamera(); //カメラ状態を反映させます。
}
}
関数「setCamera()」の方はこんな感じです。
//-----------------------------------------
//動的カメラ設定関数 setCamera()
//-----------------------------------------
integer camon=FALSE; //カメラタイプ
setCamera()
{
if (camon)
{
//camonがTRUE⇒カメラコントロールあり
if ((llGetPermissions() & PERMISSION_CONTROL_CAMERA) && llGetAgentSize(pilot)!=ZERO_VECTOR) //パイロットがいて、カメラコントロールがある場合だけ制御開始します。
{
list _rules=[
CAMERA_ACTIVE,TRUE,
CAMERA_BEHINDNESS_ANGLE ,0.0,
CAMERA_BEHINDNESS_LAG,0.3,
CAMERA_FOCUS_LAG,0.3,
CAMERA_FOCUS_THRESHOLD,0.0,
CAMERA_DISTANCE,3.0,
CAMERA_PITCH,5.0,
CAMERA_FOCUS_LOCKED, FALSE,
CAMERA_POSITION_LAG,0.6,
CAMERA_POSITION_THRESHOLD,0.0,
CAMERA_FOCUS_OFFSET,<0,0,0>
];
llClearCameraParams();
llSetCameraParams(_rules);
}
}
else
{
//camonがFALSE⇒コントロールなし
llClearCameraParams();
}
}
llGetPermissions()は現在許可されている権限を持ってくる命令で、権限がちゃんと取れているか念の為確認している部分です。また「&&(AND、かつ、さらに)」に引き続く「llGetAgentSize(pilot)!=ZERO_VECTOR」の部分は、パイロットの身長を調べています。パイロットの身長が無い場合というのは、パイロットがSIMにいなくなってしまった状態(例えば落ちた)ような場合を意味しますので、要するに「アバターがちゃんといるなら」という意味になります。お約束の使い方です。//動的カメラ設定関数 setCamera()
//-----------------------------------------
integer camon=FALSE; //カメラタイプ
setCamera()
{
if (camon)
{
//camonがTRUE⇒カメラコントロールあり
if ((llGetPermissions() & PERMISSION_CONTROL_CAMERA) && llGetAgentSize(pilot)!=ZERO_VECTOR) //パイロットがいて、カメラコントロールがある場合だけ制御開始します。
{
list _rules=[
CAMERA_ACTIVE,TRUE,
CAMERA_BEHINDNESS_ANGLE ,0.0,
CAMERA_BEHINDNESS_LAG,0.3,
CAMERA_FOCUS_LAG,0.3,
CAMERA_FOCUS_THRESHOLD,0.0,
CAMERA_DISTANCE,3.0,
CAMERA_PITCH,5.0,
CAMERA_FOCUS_LOCKED, FALSE,
CAMERA_POSITION_LAG,0.6,
CAMERA_POSITION_THRESHOLD,0.0,
CAMERA_FOCUS_OFFSET,<0,0,0>
];
llClearCameraParams();
llSetCameraParams(_rules);
}
}
else
{
//camonがFALSE⇒コントロールなし
llClearCameraParams();
}
}
カメラの具体的なパラメーターは私が販売時に乗せている「シネマカメラ」と全く同じものです。この種のパラメーター設定をする物はパーティクルにしろカメラにしろ、理解するのに最も近道は具体的に数字を変えてみてどうなるかやってみる事です。カメラは簡単な方ですが、それでも説明を読んでも多分全く意味不明でしょうし、カメラを変えて飛行してみるだけで一日や二日は楽しく遊べます。
と、申しますか、是非遊んでみてください。カメラに凝った乗り物は意外と販売品でも少ないのですが、乗り物エンジンの方を全く変えなくても、カメラを変えるだけで乗り心地がガラリと変わって感じます。意外と腕の見せ所です。(↓例えばこんな感じです↓)
また、カメラパラメーターの変更でこの手の実験と結果の確認作業に慣れておくと、乗り物機能の複雑奇怪なパラメーターについても自分で調整して変更する作業の準備になります。SL内のこの場所に行くとゼロ戦と95式水上偵察機のデモ版が看板からREZ出来ます。コマンド「C」で3種類のカメラが両方に仕込んでありますので、カメラパラメーターと乗り物機能の設定差による、乗り味の違いを体験してみてください。シネマカメラは上と同じもので、ダイナミックカメラとカメラ操作なしモードは2機種で別のパラメーターになっています。
ということで、今回の完成状態は以下の枠内になりました。
key pilot=NULL_KEY; //パイロットのUUID
float throttle=0.0; //スロットル状態
vector angular_motor=ZERO_VECTOR; //舵操作状態
integer handle=0; //チャット傍受識別番号
integer camon=FALSE; //カメラタイプ
//-----------------------------------------
//初期化関数 init()
//-----------------------------------------
init()
{
llListenRemove(handle); //チャット傍受を解除します。
pilot=NULL_KEY; //pilotを初期化します。
llSetStatus(STATUS_PHYSICS,FALSE); //物理を切ってその場に停止させます。
camon=FALSE; //カメラタイプを初期化します。
}
//-----------------------------------------
//エンジン設定関数 planeEngine()
//-----------------------------------------
planeEngine()
{
llSetVehicleType(VEHICLE_TYPE_AIRPLANE); //乗り物タイプを飛行機にします。
llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_TIMESCALE,0.0); //舵操作への反応速度を最高感度にします。
}
//-----------------------------------------
//動的カメラ設定関数 setCamera()
//-----------------------------------------
setCamera()
{
if (camon)
{
//camonがTRUE⇒カメラコントロールあり
if ((llGetPermissions() & PERMISSION_CONTROL_CAMERA) && llGetAgentSize(pilot)!=ZERO_VECTOR) //パイロットがいて、カメラコントロールがある場合だけ制御開始します。
{
list _rules=[
CAMERA_ACTIVE,TRUE,
CAMERA_BEHINDNESS_ANGLE ,0.0,
CAMERA_BEHINDNESS_LAG,0.3,
CAMERA_FOCUS_LAG,0.3,
CAMERA_FOCUS_THRESHOLD,0.0,
CAMERA_DISTANCE,3.0,
CAMERA_PITCH,5.0,
CAMERA_FOCUS_LOCKED, FALSE,
CAMERA_POSITION_LAG,0.6,
CAMERA_POSITION_THRESHOLD,0.0,
CAMERA_FOCUS_OFFSET,<0,0,0>
];
llClearCameraParams();
llSetCameraParams(_rules);
}
}
else
{
//camonがFALSE⇒コントロールなし
llClearCameraParams();
}
}
default
{
state_entry()
{
//初期化イベント
llSitTarget(<0.0,0.0,0.5>,ZERO_ROTATION); //アバターの座る位置
llSetClickAction(CLICK_ACTION_SIT); //クリックしたときの動作を「座る」にします。
llSetCameraEyeOffset(<-5.0,0.0,1.0>); //座った時のカメラの位置を指定します。
llSetCameraAtOffset(<2.0,0.0,0.0>); //座った時にカメラが見ている位置を指定します。
llSetStatus(STATUS_PHYSICS,FALSE); //物理をオフにします。
planeEngine();
}
on_rez(integer start_param)
{
init();
}
changed(integer change)
{
//プリムやスクリプトに状態変化があった場合のイベント
if (change & CHANGED_LINK)
{
//リンクが変更になった
key _av=llAvatarOnSitTarget(); //座っているアバターのUUIDを取得します。
if (_av!=NULL_KEY) //NULL_KEYでない⇒誰かが座っている。
{
if (pilot==NULL_KEY) //pilotがNULL_KEY⇒誰かが初めて座った。
{
pilot=_av; //pilotに座った人のUUIDを設定
llRequestPermissions(pilot,PERMISSION_CONTROL_CAMERA | PERMISSION_TAKE_CONTROLS); //カメラ操作とパイロットのキーやマウス操作の監視の権限を要求します
llListenRemove(handle); //今まで聞いていたかもしれないListenをやめます。
handle=llListen(0,"",pilot,""); //パイロットのチャット発言の傍受を開始します。
}
}
else //座っているアバターのUUIDがNULL_KEYなら誰かが立ち上がったか、または最初から座っていません。
{
init();
}
}
}
run_time_permissions(integer permissions)
{
//権限が許可または不許可であった場合に発生するイベント
if (permissions & PERMISSION_TAKE_CONTROLS) //アバターがキーやマウス操作の監視を許可した場合
{
//各種のキー操作の監視と、通常の動作の停止を要求します
llTakeControls(CONTROL_UP | CONTROL_DOWN | CONTROL_FWD | CONTROL_BACK | CONTROL_RIGHT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT | CONTROL_ML_LBUTTON | CONTROL_LBUTTON, TRUE, FALSE);
llSetStatus(STATUS_PHYSICS,TRUE); //物理をオンにします。
}
if (permissions & PERMISSION_CONTROL_CAMERA) //アバターがカメラコントロールを許可した場合
{
setCamera(); //カメラ状態を反映させます。(初期値は操作なし)
}
}
listen(integer channel, string name, key id, string message)
{
string _command=llToLower(message); //半角アルファベットをすべて小文字にします
if (_command=="c" || _command=="c" || _command=="C")
{
//コマンド”C”。飛行機では一般的にこのコマンドはカメラ操作に割り当てられます。
camon=!camon; //カメラ状態を現在と逆にします。
setCamera(); //カメラ状態を反映させます。
}
}
control(key name, integer keyPress, integer edges)
{
//llTakeControls()で要求したキー・マウス操作が行われた場合に発生するイベント
integer _keyDown=keyPress & edges; //押されているキーのうちで状態が変ったキーは今押され始めたキーです。keyPressとedgesのビット論理和(AND)を取ると取得できます。
integer _keyUp=~keyPress & edges; //押されているキーの逆のうちで状態が変ったキーは今離されたキーです。keyPressのビット反転とedgesのANDを取ると取得できます。
//--------------------------------------------------------
//スロットル(前進速度)
//PgUp(CONTROL_UP)で増速、PgDwn(CONTROL_DOWN)で減速します。
//--------------------------------------------------------
if (keyPress & CONTROL_UP) throttle=throttle+0.01; //この書き方もできるし。。
if (keyPress & CONTROL_DOWN) throttle-=0.01; //この書き方も出来ます。
if (throttle>1.0) throttle=1.0; //最大を超えそうなら最大にします。
else if (throttle<0.0) throttle=0.0; //最少を下回りそうなら最小にします。
//--------------------------------------------------------
//エルロン(ロール・左右傾斜)
//←→キー(CONTROL_ROT_LEFT/CONTROL_ROT_RIGHT)で操作します。
//--------------------------------------------------------
if (keyPress & CONTROL_ROT_LEFT) angular_motor.x-=0.1;
if (keyPress & CONTROL_ROT_RIGHT) angular_motor.x+=0.1;
if (_keyUp & CONTROL_ROT_LEFT) angular_motor.x=0.0; //飛行機では通常、キーを離したらならすぐに回転力をゼロにリセットします。
if (_keyUp & CONTROL_ROT_RIGHT) angular_motor.x=0.0;
if (angular_motor.x>1.0) angular_motor.x=1.0; //最大を超えそうなら最大にします。
else if (angular_motor.x<-1.0) angular_motor.x=-1.0; //最少を下回りそうなら最小にします。
//--------------------------------------------------------
//エレベーター(ピッチ・上下首ふり、水平尾翼)
//↑↓キー(CONTROL_FWD/CONTROL_BACK)で操作します。
//飛行機スクリプトでは慣習的に↑キーで機首下げです。
//↓キーで機首上げです。
//--------------------------------------------------------
if (keyPress & CONTROL_FWD) angular_motor.y+=0.1;
if (keyPress & CONTROL_BACK) angular_motor.y-=0.1;
if (_keyUp & CONTROL_FWD) angular_motor.y=0.0;
if (_keyUp & CONTROL_BACK) angular_motor.y=0.0;
if (angular_motor.y>1.0) angular_motor.y=1.0; //最大を超えそうなら最大にします。
else if (angular_motor.y<-1.0) angular_motor.y=-1.0; //最少を下回りそうなら最小にします。
//--------------------------------------------------------
//ラダー(ヨー・左右首ふり、垂直尾翼)
//SHIFT+←→キー(CONTROL_LEFT/CONTROL_RIGHT)で操作します。
//--------------------------------------------------------
if (keyPress & CONTROL_LEFT) angular_motor.z+=0.1;
if (keyPress & CONTROL_RIGHT) angular_motor.z-=0.1;
if (_keyUp & CONTROL_LEFT) angular_motor.z=0.0;
if (_keyUp & CONTROL_RIGHT) angular_motor.z=0.0;
if (angular_motor.z>1.0) angular_motor.z=1.0; //最大を超えそうなら最大にします。
else if (angular_motor.z<-1.0) angular_motor.z=-1.0; //最少を下回りそうなら最小にします。
llSetForce(<0.0,0.0,llGetMass()*9.8*throttle>,TRUE); //揚力を設定
//速度の最大値を27.0m/sで、それに0.0~1.0をかけて設定します。
llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION,<27.0*throttle,0.0,0.0>);
//ロール、ピッチ、ヨー回転にそれぞれ最大値に現在の状態をかけて設定します。
llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION,<10.0*angular_motor.x,1.0*angular_motor.y,0.5*angular_motor.z>);
}
}
float throttle=0.0; //スロットル状態
vector angular_motor=ZERO_VECTOR; //舵操作状態
integer handle=0; //チャット傍受識別番号
integer camon=FALSE; //カメラタイプ
//-----------------------------------------
//初期化関数 init()
//-----------------------------------------
init()
{
llListenRemove(handle); //チャット傍受を解除します。
pilot=NULL_KEY; //pilotを初期化します。
llSetStatus(STATUS_PHYSICS,FALSE); //物理を切ってその場に停止させます。
camon=FALSE; //カメラタイプを初期化します。
}
//-----------------------------------------
//エンジン設定関数 planeEngine()
//-----------------------------------------
planeEngine()
{
llSetVehicleType(VEHICLE_TYPE_AIRPLANE); //乗り物タイプを飛行機にします。
llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_TIMESCALE,0.0); //舵操作への反応速度を最高感度にします。
}
//-----------------------------------------
//動的カメラ設定関数 setCamera()
//-----------------------------------------
setCamera()
{
if (camon)
{
//camonがTRUE⇒カメラコントロールあり
if ((llGetPermissions() & PERMISSION_CONTROL_CAMERA) && llGetAgentSize(pilot)!=ZERO_VECTOR) //パイロットがいて、カメラコントロールがある場合だけ制御開始します。
{
list _rules=[
CAMERA_ACTIVE,TRUE,
CAMERA_BEHINDNESS_ANGLE ,0.0,
CAMERA_BEHINDNESS_LAG,0.3,
CAMERA_FOCUS_LAG,0.3,
CAMERA_FOCUS_THRESHOLD,0.0,
CAMERA_DISTANCE,3.0,
CAMERA_PITCH,5.0,
CAMERA_FOCUS_LOCKED, FALSE,
CAMERA_POSITION_LAG,0.6,
CAMERA_POSITION_THRESHOLD,0.0,
CAMERA_FOCUS_OFFSET,<0,0,0>
];
llClearCameraParams();
llSetCameraParams(_rules);
}
}
else
{
//camonがFALSE⇒コントロールなし
llClearCameraParams();
}
}
default
{
state_entry()
{
//初期化イベント
llSitTarget(<0.0,0.0,0.5>,ZERO_ROTATION); //アバターの座る位置
llSetClickAction(CLICK_ACTION_SIT); //クリックしたときの動作を「座る」にします。
llSetCameraEyeOffset(<-5.0,0.0,1.0>); //座った時のカメラの位置を指定します。
llSetCameraAtOffset(<2.0,0.0,0.0>); //座った時にカメラが見ている位置を指定します。
llSetStatus(STATUS_PHYSICS,FALSE); //物理をオフにします。
planeEngine();
}
on_rez(integer start_param)
{
init();
}
changed(integer change)
{
//プリムやスクリプトに状態変化があった場合のイベント
if (change & CHANGED_LINK)
{
//リンクが変更になった
key _av=llAvatarOnSitTarget(); //座っているアバターのUUIDを取得します。
if (_av!=NULL_KEY) //NULL_KEYでない⇒誰かが座っている。
{
if (pilot==NULL_KEY) //pilotがNULL_KEY⇒誰かが初めて座った。
{
pilot=_av; //pilotに座った人のUUIDを設定
llRequestPermissions(pilot,PERMISSION_CONTROL_CAMERA | PERMISSION_TAKE_CONTROLS); //カメラ操作とパイロットのキーやマウス操作の監視の権限を要求します
llListenRemove(handle); //今まで聞いていたかもしれないListenをやめます。
handle=llListen(0,"",pilot,""); //パイロットのチャット発言の傍受を開始します。
}
}
else //座っているアバターのUUIDがNULL_KEYなら誰かが立ち上がったか、または最初から座っていません。
{
init();
}
}
}
run_time_permissions(integer permissions)
{
//権限が許可または不許可であった場合に発生するイベント
if (permissions & PERMISSION_TAKE_CONTROLS) //アバターがキーやマウス操作の監視を許可した場合
{
//各種のキー操作の監視と、通常の動作の停止を要求します
llTakeControls(CONTROL_UP | CONTROL_DOWN | CONTROL_FWD | CONTROL_BACK | CONTROL_RIGHT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT | CONTROL_ML_LBUTTON | CONTROL_LBUTTON, TRUE, FALSE);
llSetStatus(STATUS_PHYSICS,TRUE); //物理をオンにします。
}
if (permissions & PERMISSION_CONTROL_CAMERA) //アバターがカメラコントロールを許可した場合
{
setCamera(); //カメラ状態を反映させます。(初期値は操作なし)
}
}
listen(integer channel, string name, key id, string message)
{
string _command=llToLower(message); //半角アルファベットをすべて小文字にします
if (_command=="c" || _command=="c" || _command=="C")
{
//コマンド”C”。飛行機では一般的にこのコマンドはカメラ操作に割り当てられます。
camon=!camon; //カメラ状態を現在と逆にします。
setCamera(); //カメラ状態を反映させます。
}
}
control(key name, integer keyPress, integer edges)
{
//llTakeControls()で要求したキー・マウス操作が行われた場合に発生するイベント
integer _keyDown=keyPress & edges; //押されているキーのうちで状態が変ったキーは今押され始めたキーです。keyPressとedgesのビット論理和(AND)を取ると取得できます。
integer _keyUp=~keyPress & edges; //押されているキーの逆のうちで状態が変ったキーは今離されたキーです。keyPressのビット反転とedgesのANDを取ると取得できます。
//--------------------------------------------------------
//スロットル(前進速度)
//PgUp(CONTROL_UP)で増速、PgDwn(CONTROL_DOWN)で減速します。
//--------------------------------------------------------
if (keyPress & CONTROL_UP) throttle=throttle+0.01; //この書き方もできるし。。
if (keyPress & CONTROL_DOWN) throttle-=0.01; //この書き方も出来ます。
if (throttle>1.0) throttle=1.0; //最大を超えそうなら最大にします。
else if (throttle<0.0) throttle=0.0; //最少を下回りそうなら最小にします。
//--------------------------------------------------------
//エルロン(ロール・左右傾斜)
//←→キー(CONTROL_ROT_LEFT/CONTROL_ROT_RIGHT)で操作します。
//--------------------------------------------------------
if (keyPress & CONTROL_ROT_LEFT) angular_motor.x-=0.1;
if (keyPress & CONTROL_ROT_RIGHT) angular_motor.x+=0.1;
if (_keyUp & CONTROL_ROT_LEFT) angular_motor.x=0.0; //飛行機では通常、キーを離したらならすぐに回転力をゼロにリセットします。
if (_keyUp & CONTROL_ROT_RIGHT) angular_motor.x=0.0;
if (angular_motor.x>1.0) angular_motor.x=1.0; //最大を超えそうなら最大にします。
else if (angular_motor.x<-1.0) angular_motor.x=-1.0; //最少を下回りそうなら最小にします。
//--------------------------------------------------------
//エレベーター(ピッチ・上下首ふり、水平尾翼)
//↑↓キー(CONTROL_FWD/CONTROL_BACK)で操作します。
//飛行機スクリプトでは慣習的に↑キーで機首下げです。
//↓キーで機首上げです。
//--------------------------------------------------------
if (keyPress & CONTROL_FWD) angular_motor.y+=0.1;
if (keyPress & CONTROL_BACK) angular_motor.y-=0.1;
if (_keyUp & CONTROL_FWD) angular_motor.y=0.0;
if (_keyUp & CONTROL_BACK) angular_motor.y=0.0;
if (angular_motor.y>1.0) angular_motor.y=1.0; //最大を超えそうなら最大にします。
else if (angular_motor.y<-1.0) angular_motor.y=-1.0; //最少を下回りそうなら最小にします。
//--------------------------------------------------------
//ラダー(ヨー・左右首ふり、垂直尾翼)
//SHIFT+←→キー(CONTROL_LEFT/CONTROL_RIGHT)で操作します。
//--------------------------------------------------------
if (keyPress & CONTROL_LEFT) angular_motor.z+=0.1;
if (keyPress & CONTROL_RIGHT) angular_motor.z-=0.1;
if (_keyUp & CONTROL_LEFT) angular_motor.z=0.0;
if (_keyUp & CONTROL_RIGHT) angular_motor.z=0.0;
if (angular_motor.z>1.0) angular_motor.z=1.0; //最大を超えそうなら最大にします。
else if (angular_motor.z<-1.0) angular_motor.z=-1.0; //最少を下回りそうなら最小にします。
llSetForce(<0.0,0.0,llGetMass()*9.8*throttle>,TRUE); //揚力を設定
//速度の最大値を27.0m/sで、それに0.0~1.0をかけて設定します。
llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION,<27.0*throttle,0.0,0.0>);
//ロール、ピッチ、ヨー回転にそれぞれ最大値に現在の状態をかけて設定します。
llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION,<10.0*angular_motor.x,1.0*angular_motor.y,0.5*angular_motor.z>);
}
}
次回は乗り物機能の細かいパラメーターを細かく調整できるように改造してみようと思います。
Posted by RBK Drachnyd(しお) at 03:49│Comments(0)
│LSLで作る