2007年12月29日 星期六

啥SL—【給初心者的話……專題開發可能的方向……】

開發時要注意的一些小事

  在這邊有一些東西忘了提,就是在Second Life裡面開發LSL是有一些麻煩的,首先,Second Life的LSL是只能在裡面撰寫的,所以哪天Second Life在維修,也就代表你可以休息一天了,雖然外部是有一些編輯器可下載外掛,但那個只是擺好看的,到最後你還是得複製貼上。

  老實說,這個不方便倒還好,真正不方便的是在Second Life裡寫程式,只要你網路太慢,配備太差(網路問題和Second Life很吃資源問題應該比較大),你存檔compiler、修改一些share相關(不是修改程式碼),都會等上幾秒鐘,我就曾經發生過,因為我所有程式碼都是用老師帳號寫的,但我的裝備都是用我shortlin Yue這帳號做的,所以我必須把我的裝備給老師那個帳號。而Second Life有個奇怪的設定,當我給老師裝備時,我有些地方沒做同樣的處理(比如被Link的物件也要修改他是可以給下一個使用者修改的),用老師的帳號買下後還是無法做修改。更扯的是,當我把這物件放在魔王內,因為魔王被打敗會給玩家裝備嘛,這時魔王卻認不得那個裝備了,所以他沒有把裝備給玩家,後來發現因為那個裝備名稱後面會被加上(no copy)(no transfer),他就這樣認不得那個裝備Orz……我後來把物件的權限一個一個修改好後才沒這問題,也因為裝備太多,我在修改這個東西就花了我兩個小時……那個認不得裝備的一定是bug呀……所以當我要每一個地方修改時,每個地方都要等上數秒,這樣就大大拖累了開發速度Orz……

  以上是我在寫LSL非常麻煩的地方…… 

  還有就是當你一段LSL寫好後你要給另一個人修改或繼續撰寫,只對一個物件勾選share with group是沒有用的,除了本身物件要勾外,該程式(Script)也要右鍵選Properties勾選該程式的share with group。如此一來你的程式碼才能給別人修改。

  現在終於要進入正題了,不過由於老師已經規定好題目,老實說線上醫療和SLS(Social Learning Space)這方面我的幫助大概不大……因為這不是我擅長的,我擅長的是LSL遊戲方面相關的程式以及喇叭。

  首先要再講一個廢話,就是開發方向有兩種:
  建議可以從這兩點一起下手,個人認為,LSL是最簡單的(不過還是得花點時間摸熟),libsecondlife的話要會C#。因為我libsecondlife碰得不多,只有曾經照著官網上的步驟一步一步讓帳帳號利用C#讓我在上面可以像個機器人一樣說話(不必開Second Life,我是用另一個帳號去看確定他會說話,只是很神奇的是我那個帳號竟然變成女的了……)。但libsecondlife有什麼其他功用可能有待各位去摸索了。

  忘了說,專題的開發,建議一定要留記錄,方便各位到時候寫文件時有東西可尋,因此梅興老師以往web之類的課有提到的basecampactivecollab之類的東西可以申請一個來用,總之就是屬於你們自己的討論板。

線上醫療相關
老實說,一提到線上醫療,我滿腦子都在想醫龍這部作品(漫畫日劇第一部日劇第二部)……

  因為老師已經訂題目了,我就不說其他我曾經覺得可能可以開發的東西(其實我想到的都是遊戲相關Orz……)。

  嗯,該怎麼辦呢,我滿腦子想的都是如何要在Second Life進行batista手術……

  我在YouTube找到這個影片:



只要在Second Life搜尋bar輸入Second Health就可以找到該地

  不過說真格的,這東西應該只是廣告,因為虛擬的3D人物骨折照樣能飛能跑呀!!而且要是遇到自以為是機器人的病患那該怎麼辦!?Zzzz

  所以這個影片個人認為頂多是有辦法讓醫生能夠一直上線,聆聽病患實際生活的問題。但問題是Second Life還無法像msn那樣普及呀……所以站在使用者的角度,我其實是不看好這樣的線上醫療的,不過在上面寫些Robot可以回答一些基本的醫療問題,是一定可以開發的……只是就使用者而言,於其用Second Life,不如直接用瀏覽器去找,像我上網隨便找,就找到了

  但感覺要在Second Life開發,能做的事情並沒有上瀏覽器查得多,反而很難利用Second Life有的優勢……

  所以我猜想,梅興老師可能是要做到,像這個影片這樣有外觀的東西吸引人,然後用llLoadURL(key avatar_id, string message, string url)讓學生點了之後可以連到外面的網站查尋跟醫療相關的問題,所以在這方面LSL應該不會站太大的技術,只是要做好外觀,那剩下的,就是我不擅長的網頁與伺服器語言了,這點我可能就沒什麼能力幫忙了。

  所以這一組在LSL頂多要碰的大概只有HTTPRequest
XML-RPC這兩樣選一個了,甚至可以不用。還有就是有方便的外觀(意思是或許也可以用Sloodle之類的東西!?),這點可能和另一組SLS會重複到,因此這組的建議我就到這邊結束了。


Social Learning Space
是要搞個線上教學之類的嗎!?老實說,我不是很懂。

  唉,這個也不是我擅長的,我其實應該也幫不太到忙。但還是說一下自己的發現吧,提到SLS,就不得不提Sloodle,這個網站會說他們在哪裡有地,我有去他們的地拿過免費的東西,只是東西都被我拆解,所以我現在無法照圖,基本上從他那邊拿到的一個教學板蠻特別的,就是你可以真的留言在上面,而且不是llSetText,之前看了一下,發現那個教學板是有很多物件組成的,所以我懷疑是他每個物件都有a-z26個英文字母的texture,然後在留言時顯示。

  不過我們沒實際做過,也就不清楚了,只碰了一段時間就卡關,也搞不太懂
Sloodle到底能做些什麼,但如果要和我們那一屆要做的SLS,應該是比較有關係的,或許看過Sloodel的moodle教學後可以直接去問他們(喔,如果是Sloode或Second Life的問題可能就得自己摸索了……)

  順帶一提,我在這個blog(這裡好像有蠻多跟Second Life學習的相關文章)發現了這一個影片,其中那個化學的結構式我又再度懷疑他是有用到libsecondlife……如果那個要用LSL寫……我實在是不知道要怎寫……




  還有,根據曾文仙助教發現的http://secondlifegrid।net/,應該是有提供一些跟教學有關的3D物件,因為國外在Second Life真的有一些學校在裡面搞教學平台,所以Second Life應該會提供一些方便的道具才是,只是我之前對這方面沒太大的興趣就沒有鑽研了,如果我有看懂什麼或許會繼續發文也說不定。

  在這邊分享一下當時另一個組員—林泰昇提到的gamebased-learning,我個人是覺得這想法是蠻有趣的,因為梅興老師透露出他挺渴望做一個學習相關的……所以我們當時有往這方面去思考……

最後……

  所以就目前看來……這兩組專題都會用Second Life的部分應該不會太多,所以儘快把這部分可能要學的地方搞定,或著把工作分配好,哪邊負責Second Life,哪邊負責外面的網站。我想應該是以外面網站為主,Second Life為輔,剛開始就儘可能快一點搜集相關資訊了……

  雖然我頂多只能寫些LSL相關的程式分享,可能對以上兩點幫助不大,但如果對LSL有什麼問題,歡迎來問我,這是我的msn:shortlin.tw@yahoo.com.tw

相關連結:
啥SL—【給初心者的話……前言與應用】
啥SL—【給初心者的話……我們的專題主程式介紹】

啥SL—【給初心者的話……我們的專題主程式介紹】

  我們的專題是以LSL為主PHP與MySQL為輔,分工方式就是我林家民和賴永昌寫LSL,Second Life3D美工與企劃還是我,PHP和MySQL全權交給林泰昇,而PHP和MySQL不是我擅長的,所以這邊當然只提LSL,因此這個blog很有可能不會介紹到Second Life提供的網頁相關api(像是我們網站的地圖)。

  在介紹前,我先放上我們網站的連結(http://sl.weco.net/)、專題文件與LSL程式碼(還未整理),有興趣可以去看和打包下載。

  而因為我們所有的物件與程式都有share with group,所以只要是weco的學生都可以更改,只要別改爛就好……
 
  首先,在SL開發有個很重要的重點,就是物件與物件傳遞訊息的方式,我把這些整理起來成以下三篇文章:
  【訊息傳遞—前言與Chat】
  【訊息傳遞—Link Message】
  【訊息傳遞—HTTPRequest】

  了解完資訊是怎溝通後,我一一分批介紹必備的Event功能。

  因為我們是做第一人稱射擊遊戲,所以一定要有個封閉的場地,因此要讓玩家到達我們封閉的場地,有個很重要的功能,就是傳送(Teleport),因此可以參考以下這篇文章:
  【Teleport(傳送)】

  而在玩我們的遊戲時,必須要觸碰遊戲選單,因此一定要處理觸碰(Touch)的Event,所以請看以下這篇文章:
  【Event—Touch】

  而因為我們的遊戲是屬於單人的,所以有時間上的限制,故,一定要有Timer這個Event,關於這個Event請看這篇文章:
  【Event—Timer】

  那,我們的怪物是如何感應追蹤玩家與感受到傷害的呢?

  我們是利用Seonsor去感應,再利用一個非常簡單的程式碼llApplyImpulse(vector force, integer local),這程式會讓被設定為Physical的物件開始推動,force就是力量的方向,而local是傳入布林值,當TRUE時他是以該物件坐標系統為主,FALSE的話就是以Second Life整個坐標系統為主,老實說我也沒比較過這兩個的不同,不太好講,畢竟這程式碼是直接參考wiki上的程式的,所以整個程式必須要搭配Sensor,寫出這樣的程式碼:

sensor(integer total)
{

llSetStatus(STATUS_PHYSICS,TRUE);
//object moves physically

llApplyImpulse(-llVecNorm(llGetPos() - llDetectedPos(0)) * forward_para * llGetMass(), FALSE);
//move to target

}//end state searching sensor(integer total)

  只要寫下以上程式碼,那物件就會以很好玩地方式來追你唷。
  Sensor的用法可參考以下這篇文章:
  
Event—Sensor】

  至於感受傷害,當然是讓物件感到碰撞(Collision)的event:
  【Event—Collision】

  至於怪物的特效,其中火魘(Fire Mare)的招式就是利用的分子系統,分子系統可參考這篇文章:
  【ParticleSystem(分子系統)】

  其實機器人的程式有很多,可以參考紅色wiki這個條目。大至上是分成兩種,一種是非物理性質的移動(如我們怪物的瞬移,就是用llSetPos(vector pos))和物理性質的移動(如上面有用到的)。

  最後玩家不是要穿上裝備嗎?那穿上裝備或戴上能量砲都要有反應,前者是加防禦,後者是要發射武器,這兩個都有用到attach event,可參考:
  【Event—Attach】

  由於發射武器是要進入第一人稱模式,那這方面的程式碼,我們是參考了LSL紅色wiki這個條目

  我們的專題差不多就是這樣了,如果到了最後要寫文件的時候,千萬別參考我們的目錄,因為我們寫了200頁,導致那裡做得有一點隨便。而那200頁有2/3是程式碼,只是因為我每個程式碼都有流程圖,所以才想放上,加上程式碼又沒縮排,所以才搞到200多頁= ="因此不見得厚就是好……我只是單純地想紀念而已XD~

相關連結:
啥SL—【給初心者的話……前言與應用】
啥SL—【給初心者的話……專題開發可能的方向……】

2007年12月28日 星期五

啥SL—【給初心者的話……前言與應用】

前言

  這篇文章呢,是要寫給學弟妹們看的,主要是因為當時寒假碰Second Life怎麼碰都不懂,不清楚他到底有怎樣的應用,當時我也沒發現有巴哈姆特這討論區,也沒有發現第二人生網,也沒有老師現在手上已經出版的LSL書籍,加上因為英文能力還不太夠,導致當時一直原地踏步,整個寒假下來可以說什麼也沒有碰(只有拼命地製作方塊……),也因為這樣,我知道碰Second Life的難處就是英文要夠強,所以多少想做點中文筆記希望有幫助到學弟妹們。

  也因此,老實說,現在要我重做一款Second Life有關的遊戲,我大概有把握做得比之前好……

  不過啦,我LSL大概只摸熟了50-60%,並不是完全都懂,所以我會將我所知道的程式中較主要功能分享給大家知道。題外話,梅老師說我在巴哈姆特啥有頭有臉,他錯了Orz……我在那裡根本沒發啥發言,只有留個msn,結果有一兩三個不認識的加我,一個想要創業,但現在已經沒興趣了,一個是景文科技大學也是想開發Second Life相關,大概就只是這樣吧……OK,以下進入主題。

  基本上我已經寫了一些Second Life的入門了,可以點入以下連結先搞清楚一下Second Life到底是什麼,到底有怎樣的東西在裡面,還有哪邊的論壇可以幫助你:

  【SecondLife入門】
  【在SL的華人地點(?)介紹】

  如果你要了解建造物品,可以看這篇文章:
  
【Creator入門】  

  而是要先了解Secon Life的程式碼LSL,可以看下列文章:
  
【LSL入門連結推鑒】
  【LSL程式基本架構】

  我其實沒想到兩組都會是跟Seond Life有關。那天被通知是一點半開始的關係因此而遲到,所以我是問同組的小賴才知道的,我想,你們應該也是被梅興老師逼的吧(淚)……(喂)

  所以本來是想講點可能的開發方向,但既然已經被老師鎖定為線上醫療和SLS(Social Learning Space),那就也沒辦法了,雖然當時老師也是想做跟線上教學有關,因為我執意想做單機遊戲,所以就妥協了個Second Life上的單機遊戲……如果是遊戲方面的idea我應該算有一些,但這兩樣我就真的有點苦惱了,老實說如果要我來做,我實在不清楚要怎麼做。

  不過,也不是說沒有其他方向的可能性,建議就是多把自己的想法提出來。所以在為學弟妹們想你們開發的方向前,我會先介紹在YouTube上看到跟Second Life相關的開發以及我們這屆專題所有有用到的主要功能。

YouTube影片



這個是和google map的相關應用




這是會發泡泡的東西,老實說有一點不是很了解這東西的應用,但是至少知道他有用到notecard,所以要開發時應該是可以利用notecard開發的,而這一點是我們那時專題所沒想到的



這是即時的資料,看起來像大氣系統……



這一樣是用即時資料,是氣像預報和飛機航班的系統……



有點類似於關鍵字廣告……



這個是我看過最屌的應用影片,因為這是我唯一摸不著這到底是用什麼開發的Second Life應用,只能從相關影片看到他有用到KML,我猜想很有可能是利用libsecondlife



這個老實説我也不太清楚是怎麼用的,但總之就是skype的視訊可以看到Second Life

  以上的影片大都是由http://nwn.blogs.com/nwn/、與http://digitalurban.blogspot.com/這兩個人分享的,所以還可以從You Tube看一下該使用者分享的影片再去看看還有哪些可能的應用……

其它連結

  還有其他的網站可以去看看Second Life有什麼其他可能的應用與好玩的東西,像是Second Life NewsLinden Lab官網Second Life Grid(這東西好像跟建東西有關,但目前我還沒研究)、libsecondlife(可利用C#去操控Second Life裡面的帳號,他也有提供一些api可用)、Sloodle(教學平台相關),這些都是我在我之前文章還沒有提到的,或許大家可以過去看看,雖然都是英文看起來應該會挺辛苦的……

相關連結:
啥SL—【給初心者的話……我們的專題主程式介紹】
啥SL—【給初心者的話……專題開發可能的方向……】

啥SL—【ParticleSystem(分子系統)】

  分子系統是一個在3D世界中很常聽到的東西,我們玩的3D遊戲常會有火的流動特效或水噴灑的特效都要靠他,在LSL可利用llParticleSystem(list parameters)這個method,可以點入連結觀看他list內的參數,老實說我想一開始剛碰LSL的人應該看不懂,不過說實在話的,裡面有一大堆參數我也不是很了解,所以LSL有提供範例給我們參考,他那個範例很簡單,就是你可以改變每個參數,一個一個去試。

啥SL—【Teleport(傳送)】


  TelePort的功能其實沒有想像地那麼簡單,說要傳送就直接用一個method直接可以傳送,他的原理是很奇怪的。原理是先讓使用者坐在某個地方,然後讓他站起來。所以在Second Life,往往會把Sit On here這個Pie Mwnu上的字改為"Teleport",因此有時候字沒有更改的時候,按Sit On Here也可以傳送。

  所以他是利用llSitTarget(vector offset, rotation rot)llAvatarOnSitTarget()llUnSit(key id)changed Event這四個做搭配。

  除了以上連結的範例,我自己也有寫一個範例程式如下:

vector color = <0,1,1>; // set float text color to blue
string staticText = "Teleport to ground !!";
default
{
state_entry()
{
llSetText(staticText, color, 2.0);
llSetSitText("Teleport"); // change "sit" option to "Teleport"
llSitTarget(<0.0,>, ZERO_ROTATION); // needed for llAvatarOnSitTarget to work

if(llAvatarOnSitTarget() != NULL_KEY) // if someone is sitting
llUnSit(llAvatarOnSitTarget()); // unsit him
}
changed(integer change)
{
if (change & CHANGED_LINK)
{ // if a link change occurs (sit or unsit)
llResetScript();
}
}
}

  簡單來講,就是先讓使用者坐在某物件時,利用llSitTarget讓他坐到一個相對位置(就是離這物件多遠的位置,也就是修改vector),至於rotation就是更改使用者坐下時的角度,而之後因為坐下時啟動了changed event,所以整個程式Reset一次,因為Reset一次後他會跑一次state_entry,他測到有人坐在上面,所以他就用llUnsit讓使用者站起來,所以整體看起來很像是用傳送的。

  其實我的寫法是有點怪的,因為這是為了測試我想法對不對的程式碼,所以要是能的話請直接參考連結內的範例程式。

  要注意的是,利用這種方法有可能會因為你的顯示卡不夠力或網路lag導致你有時候好像傳送到異空間一樣(如圖)。

啥SL—【結界師……】

  今天在專一看到熊哥在看《結界師》……主角一直站在方塊的結界上(如圖)跳來跳去……

  我除了很直覺地想到洛克人也有類似的關卡設計外……還想到了Second Life的方塊(茶),只要有人扮成結界師的主角右鍵Create就產生一堆結界了呢!Zzz




有影片有真相呀!

2007年12月21日 星期五

啥SL—【Event—Attach】

這是我做的裝備,每個裝備都有用到attach event

  Attach Event就是當使用者把一物體穿上(右鍵選Pie Menu的Attach或Wear)所啟動的Event
,就是把
attach(key attached)放入state內就可以啟動,attached這個key值所代表的意義是該穿上物品的key值,如果脫下時就是NULL_KEY。因此可以用這個來判斷使用者穿上時與脫下時的狀態。

  範例程式如下:

default
{
attach(key attached)
{

//object has been attached
if (attached != NULL_KEY)
{
llSetScale(<0.01,0.01,0.6>);

}//end if (attached != NULL_KEY) // object has been attached

// object has been detached
else
{
llSetScale(<0.05,0.05,3>);

}//end else // object has been detached

}//end state default attach(key attached)
}


  llSetScale(vector scale)這個method是改變大小用的,裡面傳的vector是改變物體x、y、z方向的大小,簡單來講,這個程式碼是會讓使用者穿上後改變該物體大小,脫下後又變大小。其實這個範例的靈感是想說,他放在地板上看起來很平常,結果一讓使用者戴上後就變成別的東西……

  關於Attach有一點要記住,穿上的物品是無法消失的,所以無法使用llDie

啥SL—【Event—Timer】


  所有跟時間有關的程式在這裡有,而這邊要提的只有timer這個Event。

  而要啟動這個Event,要使用
llSetTimerEvent(float sec)這個method,這個method一啟動,代表他每sec秒就會啟動一次timer()這個event,而當sec=0時,就會停止啟動。

  之前在介紹LSL架構時有提到timer這個event和其他event有不同的地方,在於state轉換後這個event會繼續啟動,因此建議在轉換state時可以在
state_exit裡寫下llSetTimerEvent(0);部分程式碼範例如下:
state_exit()
{
  llSetTimerEvent(0);
}
  state_exit意思就是在轉態轉移時他一定會先啟動state_exit內的程式再轉到下一個state。

  現在,展示一下Timer的使用範例:

default
{
touch_start(integer total_number)
{
llSetTimerEvent(1);
}

timer()
{
second++;

if(second==10)
{
llSay(0,"Good Bye!Master!");
llDie();
}

llSay(0,(string)(10-second));
}
}

  llDie意思就是讓該物消失,所以這程式碼會每秒啟動一次timer(),到了10秒時會消失。

啥SL—【Event—Collision】

Collision

  如同字義,就是碰撞,只要你把collision(integer num_detected)collision_start(integer num_detected)collision_end(integer num_detected)land_collision(vector pos)
land_collision_start(vector pos)
land_collision_end(vector pos)
這幾個Event放入程式碼就會因為物體受到碰撞而啟動該Event內的程式。

  在這邊先來說說collision和land_collision有什麼差別好了,前者是只要有使用者(AGENT)和物件(object)觸碰就會啟動,後者是只要碰到土地才會啟動。而獲得的參數資料,前者是測到有幾個人或物同時碰到,後者是測碰到該物的土地位置。

  而有start、end以及沒有這兩個字樣的event都和之前的SeonsorTouch一樣,剛開始碰撞,和碰撞結束以及持續碰。

  不過因為他這event並不像那樣
Seonsor那樣有什麼重複和單一次碰,所以只要有碰撞他都會偵測,搞得我覺得這三樣好像功用差不多,雖然持續碰撞確實是會持續一陣子啟動,但我使用的效果並沒有那麼好,感覺他的感應太過於敏感。

  總之,以下是範例程式碼:

default
{
collision_start(integer num_detected)
{
llSay(0,"Don't kiss my ass!!!");
}

collision(integer num_detected)
{
llSay(0,"Don't fuck me!!");
}
collision_end(integer num_detected)
{
llSay(0,"Don't leave me!!!");
}

land_collision_start(vector pos)
{
llSay(0,"I touch the land!!");
}

land_collision(vector pos)
{
llSay(0,"I can't leave the land!!!");
}

land_collision_end(vector pos)
{
llSay(0,"Go to find another land!!!");
}

}


  嗯,因為實驗結果和我預期的有一點不太一樣,所以我不太好解釋,建議去試著寫看看。

  還有,
collisioncollision_startcollision_end這三個event如果要特別過慮某種物件可以使用llCollisionFilter(string name, key id, integer accept)這個method,這個method在我們的遊戲當中是很重要的成份,他降低了event一直被碰撞啟動的麻煩……不過還是不夠完美,因為他只能特別針對一個物件過濾,不能對多個物件過濾,所以在我們的遊戲當中,魔王本來是要只能對我們的武器感應到碰撞,但因為這個限制,我們只能寫只對"Object"物件過濾。

  看不懂?那看以下使用範例應該會比較快:

default
{
state_entry()
{
llCollisionFilter("shortlin Yue", NULL_KEY, TRUE);
}

collision_start(integer num_detected)
{
llSay(0, "Oh my god, you are shortlin!!");
}
}


  上面這個程式碼呢,就是我"shortlin Yue"或著名叫"shortlin Yue"的物件去碰他,他就會說話了,其他東西碰到就不會說話,所以name是傳物體或使用者名字,id就是該使用者或物體的key值,但這裡可有可無,當是NULL_KEY時就代表沒有特別限制"哪一個"特別的物件或使用者,而accept是要傳0或1的布林值,當是TRUE時,就代表只允許,FALSE就代表不允許。

  所以當時我們的專題本來是想用這個方法特別限定只會測到我們的武器,可惜的是我們的武器有很多樣,這個method多寫又沒有用(他只針對最後一個),所以我們最後才寫了
llCollisionFilter("Object", NULL_KEY, FALSE);因為我們的地板是叫"Object",為了避免魔王每次碰地板都會啟動event所以才這樣寫。

啥SL—【Event—Sensor】

  Sensor指的就是偵測感應,這個Event我最常拿來應用自動門和機器人。

  Sensor有兩種Event:
  意思就是當有感應時會啟動sensor當沒有感應時會啟動no_sensor
  
  這兩個Event須要利用以下兩種方法來啟動:

  
sensorno_sensor兩個Event也可以利用llSensorRemove來移除,減少程式負擔。

  而
llSensorllSensorRepeat的不同處就在於llSensorRepeat多傳一個參數,就是rate,意思就是幾秒Sensor一次。也就是說llSensor只會呼喊一次,llSensorRepeat則會一直按照頻率喊叫。

  現在來解釋一下每個參數的意義:
  • name:偵測感應到的物件或使用者名稱
  • id:偵測感應到的物件或使用者的key值
  • type:限定感應到的是哪種類型的東西,參數如下表格:
    Constant Value Searches for
    AGENT 1 agents (users)
    ACTIVE 2
    physical objects that are moving or objects containing an active[1] script
    PASSIVE 4
    non-scripted or script is inactive[2] AND non-physical or, if physical, not moving
    SCRIPTED 8 objects containing an active[3] scrip

    這裡翻譯一下,AGENT只會感應到使用者;ACTIVE是只會感應到會移動的物件(包括有使用者對一物件編輯時產生了移動也會感應到);PASSIVE是感應不會動的物件;SCRIPTED是只要該物件有程式碼且他又會動,就會被感應,也就是說該物件沒程式碼,就算你編輯時進行上下移動也沒反應。
  • range:是感應的距離,也就是半徑。
  • arc:感應的角度,你可以用PI來表示,PI等於180度,而在這裡就等於是全部範圍,也就是360度,因為他這數字的意思是兩邊180度做感應。
  • rate:剛提到過了,就是更新頻率,以秒為單位。
  而啟動的sensor這個Event內有個參數可以接收,就是上面的total,這和touch一樣,統記數量用的,不過比touch還好用,就是統記瞬間偵測感應到的物件數量(當然要先符合條件,比如是使用者或物件或在幾公尺以內之類的)。 

  現在來放一下Sensor的範例程式:

default
{
state_entry()
{
llSensorRepeat("shortlin Yue", NULL_KEY,AGENT, 10, PI,1);
}

sensor(integer total)
{
llSay(0,(string)total);
}

no_sensor()
{
llSay(0,"no_sensor");
}
}

 
  由於llSensorllSensorRepeat用法類似,所以只用後者當範例。這個程式碼會每秒鐘感應10m範圍內的使用者(AGENT),而我限制一定要感測到一名叫"shortlin Yue"的使用者,如果有感應到,就會說他感應到的人數,一般來講應該是1,除非有兩個玩家都叫shortlin Yue,不過這應該不可能發生。而如果沒感應到的話,他會說"no_sensor"。

  如果,你想要知道你感應到的玩家是誰?你可以利用Detected相關程式……這之後會特別說明(記得放連結)。

  基本上,這個Seonsor有個缺點,就是他只會以X軸來當基準點,要是你特別想感應某個以Y軸或Z軸為主的角度,你得把物件轉個方向……有點像最近殺戮都市最新幾回有一個人一直拿著會發射死亡光線的人頭攻擊敵人那樣,如圖:
殺戮都市的故事挺特別的

  嗯……所以,你知道我又想到了什麼了嗎?沒錯!就是白眼!
  利用Sensor可以做出火影忍者日向寧次的白眼效果!

白眼也是有死角的!所以arc的設定千不能設為PI呀!!

啥SL—【Event—Touch】

Touch
當你一直對著一物件點選時就會啟動Touch Event

  Tocuh的Event總共有三個:

  Touch的意思就是玩家用游標點選物件,而不是碰撞物件。然而,這三個Event有什麼差別呢?基本上,如果你習慣對一物件右鍵,利用PieMenu上的Touch點選物件,這三種Event是不會感覺有差的……但是,如果你習慣是像上圖那樣有出現一隻手時點選物件,那就有差了。


這就是所謂的PieMenu

  基本上Touch的動作分成三個步驟:
  1. 點選開始
  2. 點選中
  3. 點選結束
  這看起來很像廢話,但指的就是上面的三個Event。基本上,你只要將這三種Event寫入,當有人Touch時,每個Event都會被啟動,而且會依照touch_starttouchtouch_end這樣的順序來啟動。

  而什麼叫點選中呢?這裡解釋一下,當使用者用滑鼠左鍵點選(有小手圖示出現的狀態)不放,他就會一直啟動
touch,也就是上面提到的點選中的Event。而這個也就是前面第一段提到,如果你習慣用小手一直點和利用PieMenu上的Touch的差別。只要按著不放,就會先啟動touch_startEvent,再不斷地先啟動touchEvent,最後再啟動touch_endEvent。

  至於上面的參數num_detected指的又是什麼呢?

  那是統記目前Touch人數用的,如果同一時間有兩個人在Touch,那num_detected就會是2,不過這要2的機率其實不大……實用性應該也不是很高。

  雖然我是想過一個用法,就是假若遊戲開發者有怪叔叔特戰隊的加農砲需要五個人一起操作的設定,那我想可以利用Touch,只要有同時五個人Touch加農砲按住不放,就會把加濃砲發射出去……



這讓我想起這段很有趣的影片……
來利用Touch Event製作五人戰隊的武器吧!!


  在這邊寫了一個Touch的程式範例:
default
{
touch_start(integer num)
{
llSay(0,"touch_start");
}

touch(integer total_number)
{
llSay(0,"touch");
llSay(0,(string)total_number);
}

touch_end(integer num)
{
llSay(0,"touch_end");
}
}
  簡單來講,就是當有人Touch時,該物件會先說"touch_start",再說"touch"與目前有幾個人碰,而如果這時你是用滑鼠左鍵按住不放,那他就會一直喊著"touch"以及目前有幾個人碰的數字,這時有別的使用者觸碰,這數字就會加1,而當你不碰時,就會喊"touch_end"

啥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應該也可以。

啥SL—【訊息傳遞—HTTPRequest】

HTTPRequest
  老實說,個人認為會選擇梅興老師的大部分應該都有一定的網路知識基礎,所以我這個門外漢(哈,我應該是梅興老師底下小組成員裡擔任主力中的例外XD)要介紹這個還挺吃力的……所以個人認為這邊的講解可能會漏洞百出,請敬請指正。

  雖然圖中是用
php來介紹,但是不代表LSL只能用php……不過我也只會用php來和LSL做溝通= ="

  簡單來講,就是利用HTTP這個很普遍的通訊協定來和外部的伺服器做溝通。

  有一點要注意,根據這裡可以知道,在Second Life每一個土地擁有者所能做的Request有限制,雖然不清楚有多少限制就是了,這裡提一下的原因是,上次老師問如果要求學生做SL相關的project要做什麼,我提議可用HTTPRequest相關的應用,泰昇就用了以下的理由說,要是修老師課的有60人,那邊如果有60個物件同時Request的話,應該會被限制,這樣學生作業就交不成了……

  其實使用方法就是利用
llHTTPRequest向伺服器請求,這時伺服器會回傳訊息給Second Life裡一個被稱為http_response的event(如上面的圖解),而這訊息是傳送該頁面的html語法,也就是整個body,這裡指的body不是<body></body>內的東西而是整個html語法可以跑的頁面。

  而這裡有非常好的例子,內有整個php程式碼範例和LSL程式碼範例。
 
  由於不懂的東西太多,所以許多細部就不解釋了,等我哪天開竅了再說吧……那個範例已經說明了如果想要和外部的網站做溝通是如何實作的,只是有沒有其他方法我不清楚,而如果是這個範例程式碼不懂,就再問吧……

  只能說當初知道很多地方要快點趕工,所以就沒有心在這方面了,因為當時還想說還得摸熟php和mysql……沒想到昇哥一下子就包辦了,而且還做得很好……不過我是有一種知道工具怎用就直接上,而不清楚工具是怎做出來的感覺……雖然大多時候是要這樣啦……但他既然都提供出來了,也沒好好了解就的確有點糟糕了Orz……

2007年12月20日 星期四

啥SL—【訊息傳遞—Link Message】

物件被Link起來的模樣

  Link Message可以把訊息傳給本身自己其他的Script與其他Link物件的Script。而圖中黃色為parent藍色皆為child。Link Message的優點是傳的速度快,且不會被竊聽,但缺點就是要把兩物件Link起來,距離不能太遠,我算過大約只能4.346m的距離。不過這不代表所有被link的物件一定要這樣的距離,像以下圖中這樣,只要最近的兩塊物件沒有超過這個距離,就可以Link,雖然還是有限制,但在Second Life裡看到很多房子的製作其實都是被Link起來的。

如果要超過4.346m的距離得要有中間物件

  那Link Message到底是如何使用的?只要使用llMessageLinked,就會啟動指定物件的link_message這個event。

  
llMessageLinked的格式如下:
llMessageLinked(integer linknum, integer num, string str, key id)

  
linknum指的是要傳給訊息的物件的種類代號。代號有以下五種:
Constant Value Description
LINK_ROOT 1 root prim in linked set (but not in a single prim, which is 0)
LINK_SET -1 all prims in object
LINK_ALL_OTHERS -2 all other prims in object besides prim function is in
LINK_ALL_CHILDREN -3 all child prims in object
LINK_THIS -4 prim script is in

  在這邊翻譯一下,LINK_ROOT指的是要傳給parent。LINK_SET是要傳給所有被的物件。LINK_ALL_OTHERS是要傳給除了自己以外的物件。LINK_ALL_CHILDREN是要傳給所有的child。LINK_THIS則是傳給自己本身其他的Script。

  num是要傳給物件屬於數字的訊息。

  str是要傳給物件屬於字串的訊息。

  id是要傳給物件屬於key的訊息。

  llMessageLinked使用範例如下:
  llMessageLinked(LINK_THIS,1,"ohohohoh!!",NULL_KEY);

  這樣的用法就是我要傳給自己物件其他的script數字為1字串為
ohohohoh!!key值為NULL_KEY的訊息

  而啟動的
link_message這個event要寫入的參數格式是(integer linknum, integer num, string str, key id),使用範例如下:

link_message(
integer linknum, integer num, string str, key id)
{
  if(str=="It is from A Object")
  {
    llSay(0,"A");
  }

  if(str=="
ohohohoh!!" && num==1)
  {
    llSay(0,"You're dead!!!");
  }
}

  意思就是收到字串為
It is from A Object就會說A,收到ohohohoh!!(喔喔喔喔!!)就會說You're dead!!!(你已經死了!!!)。

  
Link Message的整個使用範例如下:

  當A物件和B物件被Link起來的時候,A是parent,B是child,而A除了有A1程式碼外還有A2。A物件的A1程式碼如下:

integer LM_SEND_TO_CHILD=88;//和之前的Chat一樣,給定常數方便管理
integer LM_SEND_TO_OTHER_SCRIPT=2;
default
{
  state_entry()
  {
    llMessageLinked(LINK_ALL_CHILDREN,LM_SEND_TO_CHILD,"I am your father!!!",NULL_KEY);

    llMessageLinked(LINK_THIS,LM_SEND_TO_OTHER_SCRIPT,"I am your brother!!",NULL_KEY);
  }
}

  而A物件的A2程式碼如下:

integer LM_SEND_TO_OTHER_SCRIPT=2;
default
{
  link_message(integer linknum, integer num, string str, key id)
  {
    if(num== LM_SEND_TO_OTHER_SCRIPT)
    {
      llSay(0,"Btother!!!!!");
    }
  }
}

  因為A1有啟動了傳給其他Script的llMessageLinked,所以A2的 link_message event就一定會被啟動,而他if去判斷接收的num是不是我們要的,簡單來講,就是所謂的過濾。然後A物件就會很感傷地說"Btother!!!!!"

  而B物件的程式碼如下:
integer LM_SEND_TO_CHILD=88;
default
{
  link_message(integer linknum, integer num, string str, key id)
  {
    if(num== LM_SEND_TO_CHILD)
    {
      llSay(0,"No!!!!");
    }
  }
}

  因為A物件的A1是傳訊息給其他的child的,所以身為child的B物件就一定啟動link_message這個event然後再經由判斷正確後,B物件會像是路克天行者般地大喊:不!!!!因為A物件說了句"I am your father!!!"

  OK,以上就是利用Link Message傳遞資訊的方式,下一篇將會提到我們如何利用HTTPRequest來和外部溝通。

啥SL—【訊息傳遞—前言與Chat】

前言

  要在Second Life內開發,訊息的傳遞是很重要的。Second Life內的溝通在這個wiki頁面有介紹,但個人認為,最重要的只有四點,分別為:

  其中個人將以上四點又分為內部與外部。Chat、Link Message為內部;HTTPRequest、XML-RPC為外部,由於本人不是很了解XML-RPC,所以這裡暫不介紹,我本人是很希望有人能教教我,不過這也只是希望啦……

Chat

  Chat的方式大致就如同以上圖片所表示的,右邊的方塊用llWhisperllSayllShout這三種方式和其他物件溝通(這三者的差別在於距離的不同,分別為10m、20m、100m),而左邊的方塊可以用一個叫llListen的方法去聽取資訊,只要在state_entry內放置這個方法,就可以啟動listen這個event,而這樣的溝通方式不只出現在物件與物件間的溝通,玩家與物件間的溝通也是用Chat的方式。

  首先,先制定好頻道號碼(channel),頻道號碼為0是是和玩家溝通的頻道,而0頻道出現的訊息,就是左下角對話視窗的訊息,以我玩過的線上遊戲來說,就是範圍頻道……而Chat的溝通方式,就是在一定範圍內去聽取某些頻道號碼上的訊息,至於哪些號碼在SL是特定號碼,可以點選上面channel的連結。

  而在listen這個event內可以處理接收到的訊息,分別為(integer ch, string name, key id, string message)這裡的channel、name、id以及msg只是變數名稱,這個可以自訂,前面我標示的是變數型態。

  ch就是channel,意思是取得聽到資訊的來源是從哪個頻道來的,如果
llListen啟動太多種,不清楚是收到的資訊是哪個頻道來的,這裡可以用if條件來做判斷

  name就是取得聽到訊息的來源名稱,可以是物件名也可以是人名。

  id指的是聽取訊息來源的key值,可以是物件的key也可以是人的key值。

  message就是聽取迅息的內容,是字串型式。

  Chat使用範例如下:
  
  A物件的程式碼:

integer CH_TEST=358;
default
{
state_entry()
{
While(TRUE)
{
llShout(CH_TEST,"Fcuk You!!!");//範圍為100m
}
}
}

  意思就是,A物件在100公尺內無限迴圈內一直大喊著"Fuck You!!!"而且是在第358(上我吧!!Zzz)頻道大喊。(用CH_TEST當358是好習慣,因為以後可以某些頻道想改號碼,直接這樣改CH_TEST的變數即可)

  此時B物件要去聽取資訊,他的程式碼如下:

integer CH_TEST=358;

default
{
state_entry()
{
llListen(CH_TEST,"",NULL_KEY,"");//這裡的NULL_KEY也可以寫""來取代
  llListen(0,"shortlin Yue","","I want to play H game!!!")
}

listen(integer ch,string name,key id,string message)
{
if(ch==CH_TEST)
{
llShout(0,"Don't fuck me!!!");
llShout(0,(string)ch);
llShout(0,name);
llShout(0,id);
llShout(0,message);
}

if(ch==0)
{
llShout(0,"Sorry, I can't help you");
}
}
}

  此時B物件如果在A物件100m範圍以內,他就會啟動了listen,因為他llListen中的參數並沒有給太多的限制,只有啟動了會聽取頻道358的訊息。因此他會大喊"Don't fuck me!!!"接著喊"358",如果A物件叫做A那他還會喊"A"而如果A物件的key值是"595c90dc-feff-5a80-9401-0cc111e8d8bb"那他接下來會喊"595c90dc-feff-5a80-9401-0cc111e8d8bb",最後,他會喊A喊過的訊息"Fcuk You!!!"。

   此時,如果有玩家或物品名稱叫做shortlin Yue,他在頻道0以及B物件100m以內大喊著"I want to play H game!!!",這時也會啟動B物件的listen event,此時B物件就會喊"Sorry, I can't help you"。如果有特別限制聽取某物的訊息,可以利用該物的key值。如何取得該物的key?可以利用llSay(0,(string)llGetKey)這樣的方式在你要知道key值的物件上寫下這個程式碼。

  其實Chat這樣的溝通方式代表著,當一物件啟動了listen這個event,這物件就會接收從四面八方而來的訊息……如此一來是會增加很多負擔的。還有一點要注意,不管是llSay或是llShout,他們都會有一個毛病,就是說出來的順序有可能會delay且不依照順序

  意思就是,如果你寫了這樣的程式碼:


default
{
state_entry()
{
integer index;
for(index=0;index<10;index++)
{
llSay(0,(string)(index));
}
}
}

  這樣的程式照道理會依照順序出現0、1、2、3、4、5、6、7、8、9,但是由於llSay會delay,他可能會變成0、2、3、1、4、5、6、7、8、9這樣的情形出現。


  大體上來說,如果你要開發的東西是需要一個很大的環境,如RPG或FPS遊戲,Chat的方式還是比較常見,因為Link Message有距離的限制,而這點會在下篇談到。

啥SL—【Demo過後……】

我的工作,還沒有結束……

  大概在今年八月多的時候,梅興老師說我們的專題應該可以不錯,大概是看到了我們組員間都有東西可以報告,且因為我們三個人總是有聯絡,所以才會這麼說吧!?
 
  不過這樣的過程中其實是有一些犧牲的……

  還記得當初要放棄Second Life,原因無它,因為我知道,當我們的專題選擇了Second Life,我會變成主程式、企劃還有美工。

  我雖然確實看好Second Life,也想私底下自己進行觸碰,就算再怎麼不喜歡他的3D與大家總是把他當遊戲看待,我還是認為這是一個好的創作平台,可以讓我的作品,有機會和日本人交流……

  但重點是,我有我自己的人生規劃,擔任三種工作的負擔,會讓我自己的規劃前進不了……甚至毀了我三年前訂下要在大學四年做出一款至少自己認為好玩的遊戲的承諾……

  雖然如此,我還是扛了下來,不知道有人會不會說我後悔了?但我是覺得,我自己的道路,既然已經選擇,就不會後悔,也不能後悔……

  在摸熟LSL的過程中我很清楚,我們的遊戲,是達不到當初我自己的承諾的。這款遊戲,是無法讓我覺得好玩的……頂多就是完成三年前答應小賴要一起做完專題的承諾……但這樣的結果……不是我樂見的……

  所以我自己私底下訂下一個目標,那就是,這個專題,是要回報梅興老師的,雖然幫助不大,但至少,希望能讓下一屆的學弟在學習LSL時,不會像我們一樣一直遇到小小的問題就碰璧……

  所以專題完成了,Demo報告也過了……但我的工作,並沒有結束……

專題其實並沒有老師說得那麼好……

  不管是梅興老師,還是demo當天擔任評審的黃貞英老師,他們都覺得我們專題做得不錯(連國珍老師就不清楚了),但由於我是主程式、企劃兼美工,所以我很清楚,這個專題的企劃是失敗的……雖然程式我自己也在寫文件時發現了一些缺點,但這之後講解如何實作專題再談。美工很失敗不用講,但企劃有很多地方是很糟糕的……因為當初為了急於看程式跑出來的成果,所以企劃我就隨便訂了……

  在企劃中,每個怪物、道具以及技能的都還得再詳細分類,比如這招式延遲幾秒、這技能是屬於何種分類,後者意思就是,假若每隻魔王自己的補血技能並不同,而魔王因為自己的血量很低,想要補血,這時候判斷的不是自己會的招式,而是用技能種類判斷,因為有可能日後還要加個補全滿血的技能,這時候程式碼要再寫,就可以在技能判斷完後,繼續做判斷……

  所以有人能看得出來這企劃哪裡糟糕嗎?是的,就是彈性不夠。

  雖然這地方如果在遊戲業界的規劃可能不能只怪企劃,還得怪程式總監,因為這是這兩樣工作者得互相溝通的地方,程式總監知道哪邊的地方可以讓日後更有彈性,而企劃在寫一堆堆的表格時,也得要考慮這方面的問題……畢竟這是建立在溝通的問題,只是我因為是企劃姦程式,所以就沒這問題了,只是當時企劃想得太隨便了,才導致彈性不夠。喔,其實用姦還挺適合的,在遊戲界的話,企劃堅持就是要做到這樣那樣的時候,對程式而言就是被姦了(喂)。

  雖然說彈性還是有一點啦,就是可以修改魔王血量和會的招式與給予玩家物品= ="

  但總體來說,當十月多的時候,我想要在打魔王前有關卡可以玩,比如說射擊遊戲或獵魔蛛跑出來攻擊……玩家可以消滅他們,但想加的時候,卻發現彈性不夠,無法加入,要加入的話,一堆地方都得修改……

  我還想把Dr.M其實是最終大魔王給寫進去呀……還有那隻會一直顯示廣告,要玩家點的言靈魔王給寫進去呀……(淚)

  老師們問的問題……

  在DEMO問問題中,泰昇擋了很多問題,其實其中有一點他擋得讓我覺得我好像在說謊Orz……就是黃貞英老師在問我們為何不用XML-RPC時我先回答是因為先碰了HTTPRequest,後來才發現XML-RPC的,而一些架構已經出來了,所以才沒有改。但泰昇在後面接著回應其實有碰,但不太會,而且會導致架構變更。他這樣回答可能會變成說其實並不完全是會導致架構變更,很可能是早就知道XML-RPC了,是小組成員懶,所以才選擇了HTTPRequest……但其實我的部分並沒有說謊,我們先發現有HTTPRequest確實是事實。不過最重要的是後來再發現XML-RPC時,因為怎麼摸都摸不懂,加上之前了解了HTTPRequst時,我心裡確實是想了一些怎樣處理資訊的方法……這時如果要再碰我無法掌握的XML-RPC是會挺麻煩的……雖然泰昇是懂XML-RPC,也認為很簡單,但他願意碰一下LSL的時候是十一月的事了……

  嗯……現在想回憶一下老師當時問的問題……其實現在仔細想想,我的回答都回答挺含糊的= ="

  首先是連國珍老師的問題:

  1.Second Life沒有提供一個在裡面建立資料庫的服務,所以才要在外面用是吧?

  沒記錯的話,老師是這樣問的,當時我好像直接回答是的……說實在話的,那時我內心在想,要這樣的東西提供這樣的服務真的是不太可能,他已經做了太多了,還要做這方面的服務,會不會太OVER啦?而且資料庫最好還是建在自己的電腦呀……雖說可以把資料都寫進Second Life裡面,但這樣實在是不太好……因為在Seocnd Life裡面修改資料是很lag的……Orz

  2.如果你們要收費的話,是可以設定的對吧?

  嗯,一樣是那種已經幫我們做好回答的問題,所以我當然會說是的……

  3.在Second Life是否可以做投影片的效果?

  這個一樣,回答是的,像是我剛剛demo中的地下室就有。不過我內心的OS卻想,一張圖要10L$呀~~~雖然我是有想過把好幾張圖合在一起當一張圖,利用切換動畫的方式放……但這樣也很累……而且我試過了,有時候還會出問題……所以目前應該還沒有很適合做投影片的方法,除非你忍痛花那些L幣= =a

  沒記錯的話,連國珍老師都是問他已經幫我們做好回答的那種問題,我們只要回答是的就輕鬆過關……接下來是黃貞英老師的的問題:

  1.當初是怎樣的狀況,所以才不選擇XML-RPC?Seocnd Life應該還有更多像這樣的外部工具可以使用,為何你們不選擇?

  這問題除了上面的回答外,我在外部工具那裡說了一個我自己認為是白癡回答的回答……我明明知道老師指的外部工具是技術層面的,不是什麼編輯器……但有時候腦中一有想法閃過時,就會不自覺地說出口Orz……搞得老師認為我會錯意老師的問題了……因為想到外部工具,我直覺就是想到編輯器Orz……不過當我回答時,我發現不是這個東西,卻想停口也停不下來Orz……是最後泰昇幫我擋住的= ="

  2.你們的遊戲如果推出來,和外面的遊戲有什麼不同?

  老實說,之前在想老師會問的問題時我就想過了……但我還是回答的不好Orz……

  我回答我們的系統有參考洛克人,洛克人也是要選擇關卡,然後和打完每個關卡的魔王也都有相剋的設定……

  所以我們要推出,應該沒有什麼特點……(這句話我沒說,但我前面說成那樣,其實想要表達的是這句話)

  不過,前面的理由只要是讓內行人都知道……我們的遊戲這和洛克人還是差很多呀Orz……洛克人是ACT,我們的是FPS……像這樣要把洛克人這樣的設定和FPS結合應該可以算是創新……而因為一點都不好玩= ="所以我一直不敢自誇……

  3.為什麼會選擇Second Life,是自己選的還是指導老師指引的?

  這問題梅興老師幫我們擋了,他說是他逼的XD~主要是因為投影片我有放……但我那時候好像講太快了= ="不知道大家有沒有看到0 0"

  4.你們有打算讓學弟繼續你們的專題嗎?

  就我上面的說法,是有,所以我回答我們文件之所以那麼厚,都是程式碼……而每個程式碼都有流程圖,用意就在這裡。

  但事實上,我很清楚願意會去看人家程式碼的人並不多,其實我只是在做少量的幫助而已,因此我在我的blog寫Second Life教學,也是希望能對學弟有所幫助。而這也是我為什麼堅持要把未來很多應用的展望放在後面講,而不把重點放在我們的遊戲上,因為我認為這才是我們的重點,吸引更多的人觸碰Second Life,去做更多虛擬世界幫助現實世界的應用……

  不過感覺這樣回答怪怪的,所以我就只回答是有這樣的想法……

  5.你們的ER diagram是先畫再寫還是先寫再畫?

  這是泰昇回答的,他是說是先建好資料庫後再畫的……嗯,這地方就沒我插手的餘地了。

  黃貞英老師問的好像就是這樣了吧……

  最後我實在是沒有想到梅興老師竟然也會問= =",以下是梅興老師的問題:

  1.因為老師有給我800L幣玩其他人做出來的遊戲,所以老師問,他收800L$,那如果是你們的遊戲,你們會收多少?

  沒想到老師竟然會暴這個料Orz……不過我回答也回答很含糊……我說那款遊戲美工做得很好,坐上架駛時也很擬真,而我們的就……

  我大概就是很模糊的回答,其實我想要說的是,應該連收費都無法收費,因為外觀是一個很重要的商業模式,我們連外觀都沒達到,怎可以向外面收費……而且那邊是老師的地呀……當然重點是,我們的一點都不好玩……收費會很丟臉的= ="

  2.除了遊戲的應用,可以提出Second Life還可以有哪些應用?

  其實這問題我很想打算在之後寫一篇文章提一提,雖然之前確實是想過一些,但要我立刻回答,我腦袋瓜是回答不出來什麼的,只能說YouTube的影片有一個廣告的系統,就是輸入我想出去玩,就會有一個出去玩的廣告,輸入我想賺錢,就會出現這樣的相關廣告。這系統有圖片也有影片……

  要我現在想嘛,其實是有幾點可以去想的……不過用LSL做出的可行性還得再去觀望……有必要的話可能還得利用libsecondlife。

  1.blog的搭配,知道這人是否有在Second Life上線。
  2.Second Life照出的圖片上傳到flickr之類的相簿……
  3.機器人的導遊,記錄Second Life有哪些好玩的地方,只要設定好功能,他就會search這地方有哪些地方可以逛……帶玩家走過去並一一介紹……或請玩家teleport……這時或許可以搭配他網頁的api,每個人都可以在每個地方有特別標記並寫下記錄,有一點像趴哥做的虛擬版,趴哥做的是可以在google map記錄,比如哪邊發生了什麼樣的新聞,你可以在那些地方放上相關文章與圖片……而我剛講的是在Second Life版……
 
  其實應該還有很多應用,目前就想到這裡吧……

  這樣寫好像是我回答的問題比較多……我想我一定是忘了泰昇怎回答了,沒辦法,自己的事本來就是比較容易記得的 ̄▽ ̄

最後……

  雖然Demo感覺我好像說太快,但有看到有人笑了,這樣一來,我的目的也達到了(淚)。

  其實會不聽老師與助教建議—「把Second Life未來展望放在前面,不要讓我們專題看起來很弱」的主要原因是如果不把未來無限可能的展望放在最後說,是不符合我創作風格的,就算再爛,也要給人們感覺到希望,進而吸引更多的人來碰Second Life,這樣也是我的目的之一。

  OK,最後就是把最後我所會的教學完成,然後好好地把painter搞一搞……
  
  總之Demo過後,還有更多的工作……

2007年11月24日 星期六

啥SL—【state轉換會造成資訊遺漏測試】

  由於state轉換會把除了timer的event全部移除,所以在下認為,如果你下一個state還想要用上一個state用的listen,你可能會想,再加上一模一樣的listen就可以了。但是,個人認為,由於state轉換會做移除event動作,這樣會造成某些資訊的遺漏,所以我做了一個實驗。

  實驗準備:
  1. 請準備一盒衛生紙
  2. 一打A片
  Zzzzz

  實驗只需要兩個Object即可,我分別稱之為Object1和Object2。

  Object1程式碼如下:
integer count=0;
default
{
state_entry()
{
while(TRUE)
{
count++;
llSay(99,(string)count);

if(count%10==0)
count=0;

}
}

}

  是的,這是無限次在99頻道喊叫的有碼Object……Zzz
  總之,當他喊到10以後,又會重喊。

  Object2程度碼如下:
default
{
state_entry()
{
llListen(99,"","","");
}

listen(integer ch,string name,key id,string message)
{
llSay(0,"state default:"+message);

if((integer)message%10==0)
state test;
}

}

state test
{
state_entry()
{
llListen(99,"","","");
}

listen(integer ch,string name,key id,string message)
{
llSay(0,"state test:"+message);

if((integer)message%10==0)
state default;
}

}

  簡單來講,這個Object2的程式碼去聽99頻道,也就是Object1喊的數字,一喊到10就轉換到test state。而test state一喊到10就回到default state。

  實驗結果如下:
[7:24] Object: state default:1
[7:24] Object: state default:2
[7:24] Object: state default:3
[7:24] Object: state default:4
[7:24] Object: state default:5
[7:24] Object: state default:6
[7:24] Object: state default:7
[7:24] Object: state default:8
[7:24] Object: state default:9
[7:24] Object: state default:10
[7:24] Object: state test:9
[7:24] Object: state test:10
[7:24] Object: state default:9
[7:24] Object: state default:10
[7:24] Object: state test:4
[7:24] Object: state test:5
[7:24] Object: state test:6
[7:24] Object: state test:7
[7:24] Object: state test:8
[7:24] Object: state test:9
[7:24] Object: state test:10
[7:24] Object: state default:1
[7:24] Object: state default:2
[7:24] Object: state default:3
[7:24] Object: state default:4
[7:24] Object: state default:5
[7:24] Object: state default:6
[7:24] Object: state default:7
[7:24] Object: state default:8
[7:24] Object: state default:9
[7:24] Object: state default:10
[7:24] Object: state test:2
[7:24] Object: state test:3
[7:24] Object: state test:4
[7:24] Object: state test:5
[7:24] Object: state test:6
[7:24] Object: state test:7
[7:24] Object: state test:8
[7:24] Object: state test:9
[7:24] Object: state test:10
[7:24] Object: state default:1
[7:24] Object: state default:2
[7:24] Object: state default:3
[7:24] Object: state default:4
[7:24] Object: state default:5
[7:24] Object: state default:6
[7:24] Object: state default:7
[7:24] Object: state default:8
[7:24] Object: state default:9
[7:24] Object: state default:10
  
  雖然llSay會delay,但是,delay歸delay,他還是會say,而且say的時間不會晚得太離普,所以把say很晚的問題先排除。在這個前提下,注意紅色的state test,它確實有遺漏一些資料,因此實驗結果證明了我的假設—state轉換會造成資訊遺漏。

2007年11月12日 星期一

啥SL—【LSL程式基本架構】

  對一物件點選PieMenu的Edit,並在編輯視窗中點開more按鈕,在名為Content的標籤內點選New Script新增程式。對該程式點兩下就會出現以下視窗和LSL最基本的程式碼(有時候會挺緩慢的,請耐心等候)。

  這篇文章因為有考慮到完全沒寫過程式的初學者,所以寫得有點雜亂(其實可能沒有這種人來這裡XD~),建議已經掌握一些要點的朋友可以大約略看看有哪些型態,並注意每一段的注意事項和紅色字體即可。


  如圖,這就是LSL全部的基本架構了。切記,基本State區為default區塊,該區塊前後順序如圖,不能隨意更動位置,也就是說你自訂的State一定要在default後面,全域變數與全域函式一定要在default前面;而全域變數與全域函式的順序就沒有那麼嚴格了。

  看!!LSL沒有繼承、沒有abstract、沒有overloading當然也沒有interface!!!而且他每個Script還有16KB的限制!!(16KB的限制請參考這裡:http://lslwiki.net/lslwiki/wakka.php?wakka=Memory)

  很好,自high完後開始正式介紹一下LSL基本架購,由於自己程式語言學藝不精,要是自己有哪方面用詞說錯,敬請指正。

  在說明前有幾點列表,算是我之後沒有詳細談到的部分,希望對那些完全沒學過程式的初學者有所幫助:
  • 只要輸入"//"這兩個符號後,其後面的字皆為註解,不列入為執行的程式碼,但注意,LSL沒有像java一樣方便的駐解方式,就是/*.....*/,它只有"//"
  • LSL是是case-sensitive的,也就是大小寫區分的意思
  • 每個區塊均以"{"、"}"這兩個符號代表區格
  • 每個全域函式與event在其名稱後面都會有個"("、")"這兩個括符
  • 宣告變數、state轉移、return 型態、jump、使用@標計jump以及使用function或自訂的全域函式都得在最後加上";"這個符號
  • compiler指的就是把LSL編譯成電腦看得懂的語言,也就是當你對你的script按save時下方會出現compile....等字樣。詳細相關資料可看維基百科(http://zh.wikipedia.org/w/index.php?title=Compiler&variant=zh-tw)
  • save的快捷鍵為ctrl+S
  • 存檔會需要一點時間,請耐心等候,要是你在comipler期間關掉檔案,檔案是會回復原來狀態的
  • ctrl+z為回上一步,ctrl+y為回下一步。
  • 編輯器上方多少還是有可用的工具,在Edit中有Search/Replace這個工具方便使用者找尋或替代自己要的英文字母
  • 在LSL編輯器內無法輸入中文(新的Second Life軟體已經可以輸入)
  • LSL的程式碼是有可能會消失在SecondLife的Database的,請記得作好備份

變數型態

  先來介紹一下LSL的變數型態,他不像一般的程式語言所有型態都有,且宣告的名稱也有一點不太一樣(例如一般的程式語言宣告整數是"int a;",它是"integer a;")。LSL的變數型態只有:
  1. string(字串)(eg. string str="test";)
  2. integer(整數)(eg. integer int=2;)
  3. float(浮點數,意即含小數之數字)(eg. float fl=2.5;)
  4. vector(向量,x、y、z三方向為浮點數的向量)(eg. vector location=<1.25,4.22,3.2>;)
  5. rotation(角度,除了x、y、z外,還多了個s的四個浮點數。這四個浮點數字代表意義可參考這裡:http://www.lslwiki.net/lslwiki/wakka.php?wakka=quaternions,至於為何Liden不用直觀的x、y、z調角度我就不清楚了,希望知道的人可以告知一下,謝謝。)(eg. rotation rot=<0.1,02.,0.3,1.0>;)
  6. key(在SecondLife內,每個物件與人都有一個key,這是用來區別一個物件或人的代號,因此是一個有固定長度的特別字串)(eg. key object="595c90dc-feff-5a80-9401-0cc111e8d8bb";)
  7. list(有點像一般程式都會有的陣列,但不必宣告此陣列是屬於何型態。你只要想成是放很多不同型態的變數放在裡面的列表就可以了,不過list內不可以放list,雖然compiler會過,但程式碼正式執行會有run-time error)(eg. list test=["test",2,5.33,<1.0,2.0,4.2>,<0,0,0,1>];)
  至於宣告方法和很多一般程式語言一樣,便是:
  變數型態 變數名稱;
  例如:
  integer test;

  代表test這個變數是integer(整數)
  若要給他一個值,就加個"=",
  例如:
  integer test=2;

  意思便是test這個變數是2的意思。

  給值的部分當然可以之後的全域函式或Event內再給,但是絕對不可以在全域變數區寫:
  integer test;
  test=2;
  以上寫法只可以在全域函式或Event內寫。

  名詞解釋:
  全域變數:只要把變數宣告在default前就是全域變數。
  區域變數:只要把變數宣告在event或全域函式(在LSL的函式只有全域函式)內就是區域變數。變數名稱可以和其他區域的區域變數重複。

  注意事項:
  • 全域變數的宣告名稱不可重複,也不可以和state或函式名稱重複
  • 變數宣告不可宣告在event與state之間,不然不能compiler
  • vector和rotation內的浮點數其實可以輸入整數,只是這樣會比較慢。來源:這裡的第三段文字(LSL does do some implicit typecasting but the LSL compiler does not actualy convert types or simplify code; it just makes implicit typecasts explicit. So while <0,> is valid, it will use more bytecode and be slower then <0.0,>. For this reason please be sure to use a decimal point. 0. is enough you don't need an extra zero.
    ) 
強制轉型

  通常一個function(我習慣稱method)會要求你傳入的是字串或浮點數或整數,如果要傳入的是浮點數你直接傳整數,是行得通的,它會自動幫你轉成浮點數。但如果是要求傳入整數,你傳入浮點數,或字串是不行的,此時要在前面加個(integer)例如:
  float fl=5.2;
  string str="5";
  integer int1=(integer)fl;
  integer int2=(integer)str;
  此時int1和int2都為5。
  同理,像是llSay這個function有需要string,你只要這樣寫llSay(0,(string)5),他就會把5變成"5"了。以上範例只能適用在宣告區域變數,宣告全域變數不可這樣用,不然compiler不會過(很有可能是LSL的bug),不過基本上轉型在合理區塊都是可以用的。

布林值

  LSL沒有boolean這個變態,喔,是變數型態,但是他可以藉由integer來得知這是true還是faluse。例如:
  integer T=TRUE;
  integer F=FALSE;

  TRUE和FALSE都要大寫,代表這是LSL的Constant,也就是說你不可以宣告一個變數名稱叫TRUE。而TRUE代表1,FALSE代表0。


  Operator也就是程式語言的符號,由於資料龐大,請直接進入Operator上面連結觀看(沒錯!俺懶了!!!)。


  LSL的流程控制有以下幾個,這些都可在event或全域函式內撰寫
  1. if-else(如果if()內的條件為TRUE就執行,之後跳到下一個else if()內判斷,如再為FALSE就執行else內的程式碼。注意,這裡的else if與else可以不寫)
    (eg.
    if(TRUE)
    {
      ......
    }
    else if(test==2)
    {
      ......
    }
    else
    {
      ......
    }
    )
    流程圖可看此篇文章的下面圖片(http://squall.cs.ntou.edu.tw/cprog/Materials/IfStatement.html),基本上所有程式語言都是大同小異的。
  2. while(和do-while、for都是迴圈。只要符合while()內的條件,就會不斷重複執行{}內的程式碼,直到條件不符合為止)
    (eg.
    while(TRUE)
    {
      .........
    }
    )
    以上為無限迴圈,永遠跳不出來,除非你使用了jump。
  3. do-while(先執行do內的程式碼再判斷while內的條件,如果成立後便一直執行。)
    (eg.
    do
    {
      ......

    }while(進迴圈條件)
    )
  4. for(()內的格式如下:
    for(初始化;條件;改變)
    初始化和改變可以不寫,只有條件的話跟while是沒啥兩樣的。)
    (eg.
    integer index;
    for(index=0;index<5;index++)
    {
      ......
    }
    在index等於5前都不會跳出,也就是說這程式碼會執行五次,index++意即index=index+1一直遞增下去。)

  5. jump(嗯……就是……跳!在流程內的程式碼跳到指定的名稱那一行,從那一行之後開始執行,而這標計用@自訂名稱表示。jump 自訂名稱,@自訂名稱。)
    (eg.
    jump 自訂名稱;

    ................程式敘述
    @自訂名稱;)
  6. return(回傳所需型態的結果,有何用處會在之後介紹如何使用全域函式解釋)
    (eg. return
    所需變數型態的結果;)
  7. state(轉移state)
    (eg.state 你想要轉移的state名稱; )
  注意事項:
  • 在全域函式要寫轉移State有一個很大的bug,就是你直接在函式內寫state 你想要轉移的state名稱;,compiler是會error的,這時要脫褲子放屁一下,你要寫:
    if(TRUE)

    state 你想要轉移的state名稱;
  基本上,一個script一定要有一個default state,而一個default state一定要有一個event(沒有的話compiler過不了)。也就是說,當一個程式碼在跑的時候,他就是從default state開始跑起。

  default state如下:
  default
  {
   event名稱()
   {

   }
  }

  而自訂State方式如下:
  state 你想要的名稱
  {
   event名稱()
   {

   }
  }


  event的列表全部都有列在上面Event的連結,在這邊只會提到幾個較常使用的:

  state_entry:這是所有state進入後都會先執行的event。

  touch_start:只要玩家點選PieMenu的Touch,就會啟動目前程式跑到的state裡面的這個event。

  timer:只要啟動了llSetTimerEvent(浮點數)這個function,這個event就會啟動。那個浮點數代表每幾秒啟動一次timer內的程式碼。

  注意:
  • 同樣的Event可以被允許重複寫在同一個state上,雖然這個一點用都沒有,但是LSL是不會當例外處理的,當event被啟動時,他會啟動寫在最後面的event。因為本人曾經發生過不小心把程式碼複製貼上兩次,在debug時覺得自己沒寫錯怎會出錯,原來出錯是出在這種地方。
  • 如果該Event被啟動,但程式碼還停留在迴圈內,那這個程式碼會先處理迴圈,再來處理Event的啟動。如:
    state_entry()
    {
      while(TRUE)
      {
        llSetTimerEvent(1);
      }
    }
    timer()
    {
      llSay(0,"fuck!!!!!!");
    }
    由於這個程式很乖,所以它不會在每秒鐘喊fuck!!!!!!
    主要是因為無限迴圈永遠跑不出去,所以他永遠不會執行Event,代表只要有迴圈在,Event這裡並不能同步執行
  • 當state轉移時,event會被抽離,如果你下一個state有上一個state想要繼續啟動的event,這很有可能會造成資訊遺漏,所以要是能的話,我在這邊建議state轉換儘量少使用(但這個前題是有想要做遊戲這種需要每秒一直有event持續啟動的專題)
  • 雖然state轉換時會把event抽離,但只有timer這個event例外,他會從先前state的timer轉移執行現在state的timer。如果有必要在兩個state都用到timer的話,務必請在轉移state前把timer啟動設為0(代表不啟動timer),請重新在另一個state設定llSetTimerEvent()。以下為發生轉移state照樣執行另一個state的timer的情形:
  default
  {
  state_entry()
  {
  llSetTimerEvent(1);
  }

  timer()
  {
  state A;
  }
  }

  state A
  {
  state_entry()
  {

  }

  timer()
  {
  llSay(0,"state A timer()");
  }
  }
  上面的範例意思是,state A中並沒有llSetTimerEvent,結果他還是會跑state A中的timer程式碼證明了timer()這個event不會因為state轉移而被抽離。

全域函式

  在全域函式中,包含了要回傳和不回傳的型式。而你的自訂函式格式可以如以下四種:
  1. 變數型態 自訂函式名稱(){.......程式碼.......}
  2. 變數型態 自訂函式名稱(變數型態 自訂傳入變數名){.......程式碼.......}
  3. 自訂函式名稱(){.......程式碼.......}
  4. 自訂函式名稱(變數型態 自訂傳入變數名){.......程式碼.......}
  1和2皆為要回傳的型式,也就是說,在程式碼內你必須要使用return回傳一開始宣告的變數型態結果。

  (eg.
  string caculateYourCup(string name)
  {
    if(name=="Tina")
    {
      return "A Cup";
    }
   return "B Cup"; 
  
  }
  這涵式的意思是,當遇到名字為Tine的人就回傳"A cup",其餘為"B Cup"
  )

  注意:
  • 這裡可沒有什麼overloading這種東西。overloading就是同名字的函式,但傳入不同的變數

  簡單來說,連結內可以說是LSL的API,如前面有用到的llSay(0,"fuck!!!!")便是使用了LSL的Function。

  基本上我介紹LSL會把重心擺在這,藉由要做的物件來分享一些LSL的Function使用方法。所以基本的介紹就到此告一段落了……如果有LSL的相關問題,歡迎來詢問(跟SL有關的問題,也可以唷!SL不是SecondLife,是ShortLin!!!嗚……SecondLife把我的SL搶走了……Zzz)。