2007年12月21日 星期五

啥SL—【製作投影片】

  我在Second Life裡有製作一個專門放圖片展示,類似於投影片的東西,畫面如下:


  這個投影片有以下功用:
  • Next Page(下一頁):當頁碼到了最後一頁,就不顯示(上方的字是用llSetText)。
  • Last Page(上一頁):當頁碼在第一頁時,就不顯示(上方的字是用llSetText)。
  • 使用者對他按Touch,會詢問使用者要看第幾頁,這時 使用者回答正確頁面就可以換頁(上方的圖片是用上傳的,並利用了llSetTexture切換頁面。
  • 顯示目前第幾頁與全部幾頁(Touch me and say a page字樣是用上傳圖片的與方塊上方的字是用llSetText)。
  • 只要使用者把圖片編碼後(1、2、3、4……)全部放入該投影片的inventory(content)以及設定好其程式碼內的all_page參數(全部頁面),reset後程式就可以跑了。如以下圖示:

  在介紹完功用後現在要介紹這個投影片需哪些物件:
  • 中間螢幕(該物件被稱為screen)

  • 箭頭朝左邊的三角形(代表上一頁)(該物件被稱為last page)

  • 箭頭朝右邊的三角形(代表下一頁)(該物件被稱為next page)

  • 顯示目前頁數的物件(該物件被稱為display page)
  

  共四樣,原理如下:

  所有物件都要知道目前到了第幾頁以及所有物件都要知道全部頁面總共有幾頁。因此,我利用了LinkMessage來互通資訊。主螢幕只要在程式reset時把所有頁數傳給其他物件知道就可以了,所以主程式在state_entry要利用LinkMessage傳給其它物件,而他還有三種功用,一就是傳給上一頁和下一頁物件知道目前是第幾頁;二是聽到要改變,就改變自己表面的Texture(材質);三是當使用者Touch,要把使用者有Touch的訊息傳給下面的display page,因為display page掌管當使用者想用說的到哪一頁就到哪一頁的功能。總之就是當主螢幕聽到"change"與要改變的頁面就會切換目前的表面Texture(材質)

  OK,現在要貼上各程式碼:

  screen:
=====開始screen的程式碼=====



integer side=4;
integer all_page=15;

default
{
state_entry()
{
llMessageLinked(LINK_SET,0, "reset", NULL_KEY);
llSetTexture("1",side);
llMessageLinked(LINK_SET,all_page, "all_page", NULL_KEY);
}

touch_start(integer total_number)
{
//llSay(0,llKey2Name(llDetectedKey(0)));//for test

llMessageLinked(LINK_SET,0, "touch", NULL_KEY);

}//end state default touch_start


link_message(integer sender_num, integer page, string str, key id)
{

if(str=="next_want")
{
llMessageLinked(LINK_SET,(integer)llGetTexture(side), "re_next_want", NULL_KEY);
}

if(str=="last_want")
{
llMessageLinked(LINK_SET,(integer)llGetTexture(side), "re_last_want", NULL_KEY);
}

if(str=="change")
{
llSetTexture((string)page,side);
}

}//end state default link_message

}//end state default



=====結束screen的程式碼=====

  last page:
=====開始last page的程式碼=====

integer all_page;
integer this_page;

default
{
state_entry()
{
llSetText("",<0,1,1>,1.0);
}

touch_start(integer total_number)
{
if(this_page>1)
{
llMessageLinked(LINK_SET,0, "last_want", NULL_KEY);

}

}//end state default touch_start

link_message(integer sender_num, integer num, string str, key id)
{

if(str=="all_page")
{
all_page=num;
this_page=1;
}

if(str=="re_last_want")
{

this_page--;

if(this_page<=1) { llSetText("",<0,1,1>,1.0);
}

llMessageLinked(LINK_ALL_OTHERS,this_page, "change", NULL_KEY);

}

if(str=="change")
{
this_page=num;
if(this_page<=1) { llSetText("",<0,1,1>,1.0);
}

else
{

llSetText("Last Page",<0,1,1>,1.0);

}

}

if(str=="reset")
{
state temp;
}

}//end state default link_message

}//end state default

state temp
{
state_entry()
{
state default;
}
}

=====結束last page的程式碼=====

  next page:
=====開始next page的程式碼=====

integer all_page;
integer this_page;

default
{
state_entry()
{
llSetText("Next Page",<0,1,1>,1.0);
}

touch_start(integer total_number)
{
if(this_page < all_page)
{
llMessageLinked(LINK_SET,0, "next_want", NULL_KEY);
}

}//end state default touch_start

link_message(integer sender_num, integer num, string str, key id)
{
if(str=="all_page")
{
all_page=num;
this_page=1;
}

if(str=="re_next_want")
{

this_page++;

if(this_page>=all_page)
{
llSetText("",<0,1,1>,1.0);
}

llMessageLinked(LINK_ALL_OTHERS,this_page, "change", NULL_KEY);

}

if(str=="change")
{
this_page=num;

if(this_page>=all_page)
{
llSetText("",<0,1,1>,1.0);
}

else
{
llSetText("Next Page",<0,1,1>,1.0);

}

}

if(str=="reset")
{
state temp;
}

}//end state default link_message

}//end state default

state temp
{
state_entry()
{
state default;
}
}

=====結束next page的程式碼=====

  上一頁和下一頁的程式碼原理大致上是當有人按下了該按鈕,他會像主螢幕(screen)要求目前的頁數是第幾頁的,此時再依據目前頁數判斷可否到該頁並更改顯示的Text

  display page:
=====開始display page的程式碼=====


integer all_page;
integer this_page;
integer handle;
key toucher;

default
{
state_entry()
{
llSetText("",<0,1,1>,1.0);

handle = llListen(0, "", NULL_KEY, "");

llListenControl(handle, FALSE);

}//end state default state_entry()

touch_start(integer total_number)
{
llListenControl(handle, TRUE);

llSay(0,"Say a page that you'd like to go");

}//end state default tiuch_start()

listen(integer ch, string name, key id, string message)
{
if((integer)message>=1 && (integer)message<=all_page) { this_page=(integer)message; llMessageLinked(LINK_ALL_OTHERS,this_page, "change", NULL_KEY); llSetText((string)this_page+"/"+(string)all_page,<0,1,1>,1.0);

llListenControl(handle, FALSE);
}

}//end state default listen()

link_message(integer sender_num, integer num, string str, key id)
{

if(str=="all_page")
{
all_page=num;

this_page=1;

llSetText((string)this_page+"/"+(string)all_page,<0,1,1>,1.0);
}

if(str=="touch")
{
//llSay(0,llKey2Name(id));//for test


llListenControl(handle, TRUE);

toucher=id;

llSay(0,"Say a page that you'd like to go.");
}

if(str=="change")
{
this_page=num;
llSetText((string)this_page+"/"+(string)all_page,<0,1,1>,1.0);
}

if(str=="reset")
{
state temp;
}

}//end state default link_message

}//end state default

state temp
{
state_entry()
{
state default;
}
}

=====結束display page的程式碼=====

  display page這個物件是啟動touch和顯示目前頁面與全部頁面的,所以當有玩家touch時,他要知道。而他這時會使用llListenControl來控制這時是否要聽取資訊,再從接收的資訊判斷該資訊是否為有效頁數。

  以上三個程式碼都有一個temp的state,由於LSL沒辦法直接state default來進行重回,所以只好用一個temp state重回,不過後來我突然想到,其實用llResetScript應該也可以。

2 則留言:

Piyo Kumaki 提到...

最近剛好也做了類似的東西。 :)

Piyo的心得是,如果使用
llGetLinkName(llDetectedLinkNumber(0))
來判斷按了哪個按鈕的話,只要在 Screen 放程式碼就夠了。這樣程式碼也會短很多~

Nil;Short 提到...

嗯,這樣的確是方便多了。
感謝<(__)>