精華區beta mud 關於我們 聯絡資訊
傳統物件的特色是 void create() { 裡面呼叫一些設定函數,將資料設定在 data 變數裡; } void init() { 定義一些動作; } 動作函數() { bla bla } 然後這樣的物件通常被玩家攜帶在身上,取出的方式是 if( ob = present("物件id", 玩家) ) 或者說該物件本身為玩家所存在的環境,取出的方式是 if( ob=environment(玩家) ) 或者其它的「實體物件型式」,例如以 find_living、 find_player、find_object、....等取出的物件。 因為資料都在物件裡頭,所以取出時通常是這樣.. ob -> query("xxx") ob -> query_xxx() . . ================================================ 傳統物件及虛擬物件的差異,可以用一個例子來說明。 比方某物件叫做 pill,它 add_action 了一個 eat 動 作,可以讓玩家 eat pill。 int eat_pill() { 玩家吃了藥; this_object()->remove(); // 讓藥消失 return 1; } 假設我們這個 mud 有很多可以 eat 的東西,那麼最直 覺的想法就是,eat 不能寫成像 chat、look 等等的「 全域指令」嗎? 於是有了第一種變型寫法,就是 eat 是全域指令 int cmd_eat(string str) { if(ob=present(str,this_player())) { if(ob->query("這東西可被 eat 的參數")) { 玩家吃了藥; ob->remove(); 這樣寫的好處,就是「所有的藥」都不需要再定義 eat 動作以及相關的函數,只要寫一個 eat 指令,然後所有 可 eat 的藥都設定可被 eat 的參數,則有設參數的藥 就可被 eat,其效果如同在物件裡面定義 eat 動作一樣 ================================================= 那麼,進一步來想,「pill」這個 物件 真的需要存在 嗎?例如改寫上面的東西.. int cmd_eat(string str) { // 比方 eat str pill(力量藥丸) if(this_player()->query("obj/"+str)>0) { 玩家吃了藥; this_player()->add("obj/"+str,-1); . . 換言之,玩家取得了藥或買了藥: this_player()->add("obj/"+str,1 或 n); 玩家吃了藥或賣出了藥或將藥給人: this_player()->add("obj/"+str,-1 或 -n); if(this_player()->query("obj/"+str)<1) this_player()->delete("obj/"+str); 這就是第二種變型寫法,也就是「藥」這個物件實際 上已經不存在了,它變成只是一個「資料stream」, 只存在著被加減、設定及刪除等特性,我稱此為虛擬 物件。 當我們的 mud,很多的實體物件都能被虛擬物件所取 代時,它達到的最直接效果就是物件減量,我們不僅 可以省去「創造」物件的時間,還能更快速地處理一 些動作(如喝藥水)。 ============================================== 假設我們把 str pill(力量藥丸) 給虛擬化了,那麼 我們可能會寫一個指令來列出我們身上到底有哪些這 類的物品.. > obj 力量藥丸 138顆 生命藥水 144瓶 內力藥水 50瓶 蘋果 12顆 . . 今天我們有了一個 eat 指令可以吃力量藥丸了,進一 步來說,我們或許也想 view 看看力量藥丸究竟係啥 米碗糕。 寫法有非常多種,這裡只舉一種,就是定義「資料集 物件」,例如.. mapping obj_data= ([ "str pill":(["name" : "力量藥丸", "unit" : "顆", "desc" : "這是一顆力量藥丸,吃了(eat)之後力量會增加喔!", "value" : 5000, . . ]), "hp pot" :(["name" : "生命藥水", "unit" : "瓶", "desc" : "這是一瓶生命藥水,喝了(drink)它可以回復生命值。", "value" : 1000, . . ]), . . ]); 那麼,當我們 view str pill 時,就去呼叫上述的物件 取得 obj_data["str pill"] 的所有資料,自然就能得到 下列結果 > view str pill obj_data["str pill"]["name"] ========================================== 英文: str pill 單位: obj_data["str pill"]["unit"] 價錢: obj_data["str pill"]["value"] 敘述: obj_data["str pill"]["desc"] ========================================== 這就是第三種變型寫法,也就是所有虛擬物件的資料,其 實都集中存放於一個物件的 mapping 資料裡頭,有需要 的時候就去讀出即可。 這樣既可確實減少物件的數量,但同時又能令虛擬物品具 有「實體感」。 ================================================== 再來的話,既然可以有「虛擬物品」,那能否有「虛擬村 民」呢?比方說我們要列出房間所有的物品時是這樣做的 obs = all_inventory(room); foreach(ob in obs) { if(userp(ob)) msg += ob->query("short")+"正站在這裡。\n"; else msg += ob->query("short")+"\n"; } 那假設我們讓虛擬村民的列表排在前頭,那麼我們就可以 這樣幹.. vobs = room->query("vobs"); // 讀取房間的虛擬資料 foreach(vob in vobs) msg += 虛擬資料物件->query_vob_name(vob); // 讀取該虛擬物件的名稱 // 然後才做實體物件的列表 obs = all_inventory(room); foreach(ob in obs) { if(userp(ob)) msg += ob->query("short")+"正站在這裡。\n"; else msg += ob->query("short")+"\n"; } 這樣村民就會先被列在前頭。而所謂的 look 村民的動作 就套用上面讀取村民 desc 的應用即可。 這個適用於「村民通常沒啥用途只是擺著好看」的 mud, 它可以確實減少村民物件的數量。 甚至,如果想寫的更完善一點的話,還可以實現村民的「 loop speak」、「random moving」、「cound ask」.... 這些都可以用虛擬物件來實現,而且都存在著多種寫法。 此即虛擬物件的變通應用。例如聖殿目前使用的 quest 任 務系統(以任務腳本為主體)即是其變通應用的一種。 虛擬物件的好處在於可以省去許多 ob->query/set/add/.. 或是 ob->query_xxx/set_xxx/add_xxx 的物件資料存取動 作,直接做本地式的資料存取,「有需要」時才去讀取該 物件的其它資料即可,例如: view 時 -> 才去讀 desc sell 時 -> 才去讀 value . . 以上,一點心得跟大家分享。 Laechan@Sanc -- ※ 發信站: 批踢踢實業坊(ptt.cc) ※ 編輯: laechan 來自: 210.61.157.53 (12/12 22:06)
kyoe:我還以為是 virtual object= = 12/12 22:39
laechan:嗯? 12/12 23:33
bnn:推 12/13 03:16
fishsquare:push 12/13 04:27
Jate:這種方式在給其他低階GM撰寫區域時, 不會造成困擾跟限制嗎? 12/19 10:07
我們假設該 GM 已經寫好區域及怪物,只差「掉落物品」沒有 設定,以我自己在聖殿為例 /u/l/laechan/area/newsnake/room // 區域檔存放位置 /u/l/laechan/area/newsnake/mob // 怪物檔存放位置 > areadata short snake1.c 一群啪啦啪啦蛇(Snake) [13條蛇] snake2.c 一群唏咻唏咻蛇(Snake) [13條蛇] snake3.c 一群波米波米蛇(Snake) [13條蛇] 目錄下共有三種怪物,我想設計讓它們都會掉蛇鱗、蛇牙以及 蛇尾,那我就先設計好三種虛擬物品。 > vobjs -filter name = 毒蛇 編號 名稱 設定者 單位 性 質 攜帶 價錢 賣店 交易 ============================================================================ m003 毒蛇的鱗片 laechan 片 怪掉落 99 100 m004 毒蛇的牙齒 laechan 顆 怪掉落 99 300 m005 毒蛇的尾巴 laechan 條 怪掉落 99 500 ============================================================================ 設定好之後,再設定「怪物掉落虛擬物品」,如下.. /u/l/laechan/area/newsnake/mob: list ([ "snake1" : ([ "m003" : 500, "m005" : 200, "m004" : 300 ]), "snake3" : ([ "m003" : 500, "m005" : 200, "m004" : 300 ]), "snake2" : ([ "m003" : 500, "m005" : 200, "m004" : 300 ]) ]) 其中 500 代表掉落機率 50%。(這時 1 就代表 0.1%), "m003" : 500 就代表鱗片掉落率 50%。 從這時起,玩家到這個區域打這三種怪物,就會掉鱗片、 牙齒及尾巴,而且不需要更動到怪物檔。 而某一天例如我們想調整牙齒的價格時,使用 vobjs 指 令調整即可,價格可馬上套用;又某一天想變更 snake1 的牙齒掉落率為 40% 時,用 vobjs 指令同樣可馬上變更 並套用。 它的好處就是擺脫傳統「掉落物」的設定方式,將物品改 為虛擬(即實際上並沒有鱗片這個物件存在),好更新、好 管理、而且其更動具有即時性。 > call snake;die 一群啪啦啪啦蛇發出一聲慘叫!! 一群啪啦啪啦蛇慢慢的倒在地上死了...你得到 5346點的經驗值。 你取得了一個毒蛇的鱗片。 再使用聖殿的 ob 指令即可進行觀看及商店販售 > ob 你的物品欄帶著 4/99 種物品: ───────────────────────────────────── 1.毒蛇的鱗片 ( 36) 2.測試物品 ( 99) 3.毒蛇的尾巴 ( 2) 4.毒蛇的牙齒 ( 15) > ob sell 36 毒蛇的鱗片 你賣掉 36 片毒蛇的鱗片獲得 3600 影特幣。 換言之,可依自己 mud 的需要,看是只寫出虛擬物品用 來讀值就好,或是搭配怪物掉落的設計、掉落物販售交易 的設計都可。 然後其最終目的,都是為了讓 wiz 「只需透過設定而非 撰寫 code」的方式來配置怪物掉落物。 ※ 編輯: laechan 來自: 210.61.157.53 (12/19 11:42)
laechan:聖殿目前從區域繪圖到區域完成,通通只需做設定不需寫code 12/19 11:44