ソラマメブログ
プロフィール
ぺんぎん
ぺんぎん
どもっす( ◎v◎ )
ぺんぎんっす。

「ぺんぎんさん」でいいっす。
「ぺんさん」でもOKっすよ。
何だって良いんっすけどね。
[個体名:Naoya Bellic]
(非商用)
読者登録
メールアドレスを入力して登録する事で、このブログの新着エントリーをメールでお届けいたします。解除は→こちら
現在の読者数 1人

2010年09月19日

講座2回目っす

ここまでのオフィスアワーで半分以上出ちゃってるっすね。
何回もやればそのうち覚えていくっすよ。
どうもぺんぎんっす( ◎v◎ )


ログはまだまとめてないので、原稿だけ出しておくっす。
自分が実際にしゃべった順番とは若干違ってるっす。
その点は注意して読んでみてくださいっす。

お題はこれっす。
default
{
  collision_start(integer total_number)
  {
    if(llDetectedType(0) & AGENT)
    {
      string name = llDetectedName(0);
      llOwnerSay(name);
    }
  }
}


では第2回の講座を始めるっす
宿題はやってきたっすか?
自己紹介文をSayするオブジェクト(前回の復習)は
今のうちに自分に渡してくださいっす
ちょっと時間を取るっすね

その間にワンポイントだけやるっす
実は、自己紹介文を書いてもらったのにはワケがあるっす
頑張ってたくさん書いたのに、途中で切れたヒトいないっすか?
300文字以上書かないと遭遇しないんっすけどね
http://wiki.secondlife.com/wiki/LlSay
前回も見たwikiのページっす
ここに「テキストは1024バイトまで」って出てるっすね
これを超えると、超えた分以降はSayされないっす
LSLは文字コードをUTF-8で扱ってて、
日本語で使ってる文字のほとんどはUTF-8だと3バイトになるっす
気になる方は
http://ja.wikipedia.org/wiki/UTF-8
を後で見ておくと良いっす
そんな理由で、さっき300文字っていう数字を出したわけっす
厳密には全て3バイトコードを使った場合、
1023を3で割った341文字まではセーフっす

出せるヒトは全員出したっすかね?
提出したヒトの分はしっかりと読ませてもらうっすよ
どうやって1024バイト制限を突破してるのか見るっす
A. 1024バイトまでに収める
B. 超えた分は2つ以上の関数に分ける
どっちでも良いっす
切れちゃってても今回はOKっす
むしろ貴重な体験をしたと思ってくださいっす
でも次からは気を付けて書いてみてくださいっす

宿題その1については以上っす

では、今回のお題っす
(TypeWith.meのURLを出す)
お題は「ウェルカムマット」っす
使ってる関数は宿題で調べてきてると思うので、
それ以外の部分を補足するっす

LSLスクリプトは「○○の状態で□□されたとき△△する」
っていうのが基本っす
「○○の状態」っていうのがstate
「□□されたとき」っていうのがイベント
「△△する」っていうのが、実際にやる処理っす
頭の片隅に置いておいてくださいっす

お題を見ていくっす
state(ステート)はdefaultだけっす
この講座では「state遷移」は使わないで進めて行くっす
使わなくても作れるっすからね
stateについてはさらっと流すっす
(ここら辺はオフィスアワーでやるかもっす)

イベントはcollision_start(コリジョン・スタート)
っていうのが書いてあるっすね
オブジェクトがコリジョン(衝突)されたときに
ブロック( { と } で囲まれた部分)の中身が実行されるっす

その中身はというと
「もし衝突したのがアバターならば、そのアバター名をSayする」
というものっす

順番に上から説明していくっす
まずは if っす
イメージとしては
「もし~なら処理Aを、
そうでなければ処理Bを行う」
となるっす
これをそのままLSLで表現すると
if(条件式)
{
  処理A
}
else
{
  処理B
}
こうなるっす

「もし~なら処理Aを、
そうでないなら何もしない」
という場合は、else以下が省略できて
if(条件式)
{
  処理A
}
と書けるっす

実際に見ながらの方が良いっすね
お題を見てくださいっす
(TypeWith.MeのURLを出す)
お題でのif文は
if(条件式)
{
  処理
}
となってるっす
これがさっき説明した
else以下を省略したif文のカタチっす

続いて条件式のところを説明していくっす
ifのすぐ後ろにあるカッコのところっす
llDetectedType(0) & AGENT
となってるっすね
これが「オブジェクトに衝突したのがアバターなら真(TRUE)」
という条件を表してるっす

これだけだと何を言ってるか分からないと思うっす
ここから今日のテーマその2、Detect(ディテクト)系関数についてやるっす
LSLを解説してるところでは「デテクト」と表記されることが多いっすけど
自分は「ディテクト」と書くのが好みっす
いや、どっちでも分かれば良いんっすよ?
好みの問題っす

あ、話が逸れたっすね
さっきスクリプトは「○○の状態で□□されたとき△△する」
っていうのが基本と話したんっすけど、
Detect系関数は
「どういう風にアバター/オブジェクトに□□された」
のかを取得する関数っす

お題では2種類のDetect系関数が使われてるっす
if文の条件式に入ってるllDetectedTypeと、
条件式が「真」のときに実行される処理に書かれている
llDetectedNameの2種類っす

2つの関数とも引数(ひきすう)が 0 となってるっすよね
引数っていうのは関数に渡す値のことなんっすけど、
今は言葉だけ覚えてもらえれば良いっす

この 0 っていうinteger型の値がどこから来たかと言うと、
collision_start(integer total_number)
の total_number に関係があるっす

ここからややこしいっすよ
(もう既にややこしいかも知れないっすけどね)

collision_startイベントが起きた時、
つまりオブジェクトがコリジョン(衝突)された時に
それがどんな状況であったのかが保管されるっす
total_numberっていうのは
その保管されている情報が全部でいくつあるか、っていう「数」っす
引数の0っていうのは、
その保管されている情報の「番号(インデックス)」っす

すごく間違えやすいんっすけど
番号(インデックス)はゼロから始まるっす
数(=total_numberの値)が1のときは
0番だけに情報が入ってるっす
数が2のときは0番と1番に、
数が3のときは0, 1, 2番に入ってるというわけっす

お題は数(=total_numberの値)が何であっても
インデックス 0の情報を取得してきているっす
2人以上で「せーのっ」で同時に衝突した場合は
1人分の情報しか取ってこないっす

ちょっと試してみるっすかね
(TypeWith.MeのURLを出す)
1行だけ加えたっす
コピペしないで手打ちしてくださいっす
「total_numberの値をOwnerSayする」という処理っす
(string)の部分は型変換、またはタイプキャスト
単にキャストと言われるっす
llOwnerSayの引数はstring型じゃないとダメなんっすけど、
total_numberはinteger型っす
llOwnerSay(total_number);
とすると型の不一致で
Function call mismatches type of number of arguments
が出るっす
(string)total_number
とすることで、integer型からstring型に変えてるわけっす
これから何回も出てくるっすから
次第に覚えていくと思うっすよ

じゃあ、ちょっと時間を取るっすから
動き回ってみてくださいっす
2以上の値がOwnerSayされたときに、
本当に1人分の名前しかOwnerSayされないのか
試してみてくださいっす

そろそろ良いっすかね?
total_numberが2以上でも1人分の名前しか出なかったと思うっす
衝突した全員分を出したいときにはどうするかというと、
……面白そうなので宿題にするっす
各自で考えてきてくださいっす

ここまでやって、ようやく戻れるっす
if(llDetectedType(0) & AGENT)
の部分っす
長かったっす…
if文の使い方その3「フラグ」っす
いきなり3っす
ちなみにその1は「一致/不一致」
その2は「大小比較」で、ちゃんとあるっすよ
出てきたら説明するっす

宿題で調べてきてると思うんっすけど
llDetectedTypeはinteger型の値を返すっす
AGENTもそのページに書いてあったと思うんっすけど
これもあるinteger型の定数(ていすう)っす
定数っていうのは、
あらかじめ値が決まっているデータに名前を付けたものっす
例えば円周率を表す PI もそうっす
PI と書けば、これは3.14159...を表すわけっすね
それと同じで、AGENTと書けばinteger型の1を表すわけっす
0x1となってるのは16進数の1だからっすよ

llDetectedTypeとAGENTの間にある記号 & は
これはそのままAND演算の演算子っす
説明しようとすると2進数のところからやらないといけないので
時間の問題でやらないっすけど、
すごくざっくり説明すると
integer型のデータの各ビットを比較して、
両方とも1なら1、一方でも0なら0
としていくっす
2進数で考えるわけっすね
A = 0x6d3(2進数で 0110 1100 0011)
B = 0x36d(2進数で 0011 0110 1100)
このとき A & B はどうなるかというと
縦に書くと分かりやすいっすね
0110 1100 0011
0011 0110 1100
----------------------
0010 0100 0000
これを16進数に直すと0x240っす
ざっくりこんな感じっす

で、これがどう条件式に関係あるかと言うと
llDetectedType(0) & AGENT
の結果が 0 でなければ「真」になるっす
wikiのif文のところにも出てたっすね
後で確認しておいてくださいっす
アバターではなくオブジェクトが衝突した場合には
結果は 0 になるっすよ
つまり「偽」になるっす
アバターであれば結果は 1 となるっす
つまり「真」になるわけっすね
というわけで
「オブジェクトに衝突したのがアバターなら真(TRUE)」というのは
llDetectedType(0) & AGENT
で表せるわけっす

今回はもうちょっとで終わるっすよ
ラストは変数(へんすう)についてっす
「変数」っていうのは、容器で例えられることが多いんっすけど、
数値とか文字列を入れておくための箱だと思ってくださいっす
どの箱に何が入ってるか分からなくなるので
それぞれの箱には名前を付けておくわけっす

string name = llDetectedName(0);
ここのところを見てくださいっす
これは2つのことを同時にやってるっす
1.string型の変数であるnameを宣言
「変数を宣言する」っていうのは、
さっき言った容器(箱)を作ることっす
容器(箱)のカタチ[データ型]はどんなのかっていうのと、
その容器(箱)に付ける名前[変数名]を指定してやるっす
宣言する方法はデータ型を書いて、
半角スペースを開けて、
変数名を書くっす
string型の変数であるnameの宣言は
string name;
こうなるっす
セミコロン(;)が付いてるっすけど、
1つの処理を2つに分けたっすから、
それぞれでセミコロンが必要になるっす
行の終わりはセミコロンを忘れずにっす
このままだと名前を付けた容器を用意しただけで
中身が無いっす
(実際には初期値が入ってるんっすけどね)

そこで2つ目っす
2.nameにllDetectedName(0)の値を代入(だいにゅう)
容器(箱)に中身を詰めてやることを代入と言うっす
ちゃんとカタチ(データ型)に合ったものを入れないとダメっす
代入には=演算子を使うっす
=を使うっすけど、算数的なイコールじゃないっす
「左辺に右辺の値を代入する」という演算子っす
name = llDetectedName(0); で
nameにllDetectedName(0)の値が入るっす

変数を使うと何が便利かと言うと、
後で使い回し出来る事っす
同じ値を2回使うようなら変数に入れておいた方が良いっす
関数の呼び出しよりも変数の参照の方が速いっす
お題は説明するためだけにnameを使ってるっす
1回しかnameが使われてないっすから
こういうときは変数に入れないで
llOwnerSay(llDetectedName(0));
と直接入れた方が速いっすね
でもスクリプトの可読性(読みやすさ)の面から言うと
変数nameを使った方が読みやすかったりするので
1回しか使ってないので変数に入れてはダメというわけでもないっす
ここら辺は経験を積むしかないっすね

今回は以上っす
では一部で好評を博している宿題っす
その1(次回の予習)
次回のお題について調べて来てくださいっす
できれば改造して遊んで欲しいんっすけどね
(TypeWith.MeのURLを出す)
次はリンクされたオブジェクトを使うっす
注意事項がお題の上の方にコメントとして書いてあるっす
3プリムをリンクさせておくのを忘れないようにしてくださいっす

その2(今回の復習+α)
+αの部分は次回のお題に含まれてるので
次回のお題について調べれば、きっとできるっす
collision_startイベントを使って、以下を満たすオブジェクトを作ってくださいっす
1.オブジェクトに何か衝突したらtotal_numberをsayする
2A.衝突してきたのがアバターなら、以下の情報をsayする
 ・"いらっしゃいませ (衝突したアバターの名前)さん"
 ・これまでに衝突した人数
 ・10, 20, 30人目などのキリ番のときはお祝いのメッセージを出す
2B.衝突してきたのがアバターでないなら
 ・"アバターではありません"とsay
オブジェクトのパーミッションはmod/copy
スクリプトのパーミッションはフルパーミッションでお願いしますっす
オブジェクトの名前は Obj2_(各自の名前)
スクリプトの名前は Scr2_(各自の名前)
と変更したうえで次回提出してもらうっす。

今回のログとパネルは後でそこら辺に置いておくっす
なお、今回の講座原稿は自分のブログにも上げておくっす
これまでのオフィスアワーのまとめも載せてあるっすから
見ておいてくださいっす

次回の講座は2週間後の10/2(土)になるっす
次のオフィスアワーは水曜日、New Script SIMっす
ではお疲れさまでしたっす



次のお題は
//////////////////////////////////////////////////////
// リンクされたオブジェクトを扱います。
//////////////////////////////////////////////////////
// 1.3プリムをリンクさせたオブジェクトを作る
// 2.ルートプリムに「お題」を入れる

//*******************
// グローバル変数
//*******************
integer count;
vector TEXT_COLOR = <0.0, 0.75, 0.0>;

//********************
// state default
//********************
default
{
  state_entry()
  {
    count = 0;
    llSetText("", TEXT_COLOR, 1.0);
  }
  touch_start(integer total_number)
  {
    integer detected_link_num = llDetectedLinkNumber(0);
    if(detected_link_num == LINK_ROOT)
    {
      llOwnerSay("count: " + (string)count);
    }
    else if(detected_link_num == 2)
    {
      count++;
      llSetText((string)count, TEXT_COLOR, 1.0);
    }
    else if(detected_link_num == 3)
    {
      count--;
      llSetText((string)count, TEXT_COLOR, 1.0);
    }
  }
}


質問とかはまとまり次第追加していくっす。

2010/09/19 19時ごろ追加
出てきた質問とかっす。

・イベントの{ } の後ろにセミコロン(;)が無いのは何で?
{ } で囲うと、その塊(ブロック)で文とみなすのでいらないっす。
if文で{ }を省略(※)した場合はセミコロンの有無が関係あるっす。
お題がちょうど説明にピッタリなので使うっす。
(※ 実行する文が1つだけの場合は省略可能)
// A(お題そのまま)
default
{
  collision_start(integer total_number)
  {
    if(llDetectedType(0) & AGENT)
      llOwnerSay(llDetectedName(0));
  }
}
// B(セミコロン付加)
default
{
  collision_start(integer total_number)
  {
    if(llDetectedType(0) & AGENT); // ここにセミコロン
      llOwnerSay(llDetectedName(0));
  }
}
AとBの違いはセミコロン1つだけっす。
Bはオブジェクトをぶつけても名前をOwnerSayするはずっす。
セミコロンを付けたことで、処理する文が終わっちゃってるっす。
どう解釈されてるかというと、
1.条件式が真のときは何もしない。
2.llDetectedName(0)をOwnerSayする。
という風に、別々になってるっす。
Aと同じスタイルにすると違いが分かるっすね。
// B'(Bのインデントとかを変えただけ)
default
{
  collision_start(integer total_number)
  {
    if(llDetectedType(0) & AGENT)
      ;
    llOwnerSay(llDetectedName(0));
  }
}

ちなみ例外はdo-while文っすね。最後にセミコロンが必要っす。
do
{
  処理;
}while(継続条件式); // ここにセミコロンが必要

・あれ?動かない?
SIMが重いといろいろとあるわけっす。
確認して欲しいのは
 ・「実行中」のチェックボックスにチェックが入っているか
 ・コンパイルエラーは無いのか
  (ウィンドウを閉じて保存したときにありがち)
 ・グリッドステータスでメンテナンス等がないのか
 ・Regionの状態
の、とりあえず4点っす。
別のオブジェクトを新たに出して、そこに入れると動くこともあるっすね。

・collision_startイベントのtotal_numberは最大いくつ?
床に仕込んでSayさせたところ8だったっすね。
Aグループのときにはキレイに8が出たっす。
Bグループのときには1回だけ8が出たっすね。


2010/09/19 21時ごろ追加
パネルにも書いてあるんっすけど、今回は4点やったっす。
・イベントドリブンなLSL
  これがキモっす。
  やりたいことを「○○されたとき△△する」っていう日本語に直せれば、
  あとはイベントなり関数を調べてLSLに直せば良いっす。
・Detect系関数
  collision系、touch系、sensorイベントに関係あるっす。
  ポーズスタンドだとtouch系イベントで使うことになるっすね。
・if文(フラグ)
  あちこちで登場してくるので、ビット演算の説明もコミで出したっす。
  changed、control、run_time_permissionsの各イベントでは
  絶対に使うことになるっすからね。
  アンケートで「乗り物を作りたい」っていうのが多数あったので、
  少し意識して時間を多めに取ったっす。
  ここは確かに分かりにくいところではあるんっすけど
  やってもらわないといけないっすからね。
・変数
  「宣言」「代入」「参照」を一通りやったっす。
  講座3回目で変数のスコープについてやるっす。

前回の1回目は「とりあえず書いてみる」に重点を置いてたので、
自分としては今回からスタートという感じっす。
講座の密度はこれ以降そんなに変わらないんじゃないかと思うっすよ。


同じカテゴリー(デジアカ)の記事
 全6回のまとめっす (2011-02-07 19:50)
 締め切りについてっす (2011-01-12 00:35)
 講座5回目の宿題についてっす (2010-12-19 23:46)
 質問は12月いっぱいまでっすよ (2010-12-05 14:02)
 講座6回目っす (2010-11-21 01:09)
 講座4回目の宿題についてっす (2010-11-13 16:53)

Posted by ぺんぎん at 00:34│Comments(0)デジアカ
上の画像に書かれている文字を入力して下さい
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。