精華區beta mud 關於我們 聯絡資訊
※ 引述《laechan (小太保)》之銘言: : 首先來一張簡單的 m x n 的地圖(底下是 7x7) : x-x-x-x-x-x-x : | | | | | | | : x-x-x-x-x-x-x : | | | | | | | : x-x-x-x-x-x-x : | | | | | | | : x-x-x-x-x-x-x : | | | | | | | : x-x-x-x-x-x-x : | | | | | | | : x-x-x-x-x-x-x : | | | | | | | : x-x-x-x-x-x-x string str,*tmps=([]); int i,n,n1,n2; sscanf(str,"%d-%d",n1,n2); n=(n1*2-1)*(n2*2-1); // 計算需產生的數量 tmps=allocate(n); // 事先配置 for(i=0;i<n;i++) { if( (i/n1)%2==0 ) // x-x-x- 行 { if( i%2 == 0) tmps[i]="x"; else tmps[i]="-"; } else // | | | 行 { if( i%2 == 0 ) tmps[i]="|"; else tmps[i]=" "; } } str=""; for(i=0;i<n;i++) { str+=tmps[i]; if( (i+2)%n1 == 0) // 換行 str=str+"\n"; } write(str+"\n"); // 秀出來確認產生的圖是不是對的 : 先隨機戳幾個洞,就變如下.. : x-x-x-x x-x-x : | | | | : x-x x-x-x : | | | : x-x x-x-x : | : x-x x-x-x : | | | | : x-x-x-x-x x : | | | | | : x-x-x-x-x-x : | | | : x x-x-x-x 隨機戳幾個洞的寫法很多,底下展示一種 n=n1*n2; h=random(n); // 先跑出要把第幾個 x 挖掉 // 第幾排 排尾 在哪一排的第幾個位置 h= (1+(h+1)/n2) * (n1*2-1) + ((h+1)%n1)*2-2; /* 假設是 3x3, n=25, 假設跑出的 h 是 4(代表中間的 x) 則新的 h = (1+(4+1)/3) x (3x2-1) + ((4+1)%3)x2 -2) = 2 x 5 + 2 = 12 (tmps[12] 剛好就是中間) */ tmps[h]=" "; // 挖洞 當然你也可以指定 tmps[12] = " ", 看是要隨機還是手 動挖都可以, 手動的好處是不侷限 "x", 你也可以把 "|" 或 "-" 挖掉。 : 然後把地圖編號一下 : 001-002-003-004 005-006-007 : | | | | : 008-009 010-011-012 : | | | : 013-014 015-016-017 : | : 018-019 020-021-022 : | | | | : 023-024-025-026-027 028 : | | | | | : 029-030-031-032-033-034 : | | | : 035 036-037-038-039 int r=1; n=sizeof(tmps); // 第一步: 先處理 x for(i=0;i<n;i++) { if(tmps[i]=="x") { if(r<10) tmps[i]="00"+r; else if(r<100) tmps[i]="0"+r; else tmps[i]=""+r; r=r+1; } } // 第二步: 再處理 | (-不需處理) for(i=0;i<n;i++) if(tmps[i]=="|") tmps[i]=" | "; // 第三步: 再處理 " " for(i=0;i<n;i++) if(tmps[i]==" ") tmps[i]=" "; : 接著依這個地圖產生出區域房間.. : > ls : 1 001.c 1 007.c 1 013.c 1 019.c 1 025.c 1 031.c 1 037.c : 1 002.c 1 008.c 1 014.c 1 020.c 1 026.c 1 032.c 1 038.c : 1 003.c 1 009.c 1 015.c 1 021.c 1 027.c 1 033.c 1 039.c : 1 004.c 1 010.c 1 016.c 1 022.c 1 028.c 1 034.c : 1 005.c 1 011.c 1 017.c 1 023.c 1 029.c 1 035.c : 1 006.c 1 012.c 1 018.c 1 024.c 1 030.c 1 036.c r=r-1; for(i=1;i<=r;i++) // 看最後產生幾個房間 { if(i<10) files=__DIR__+"00"+i+".c"; else if(i<100) files=__DIR__+"0"+i+".c"; else files=__DIR__+i+".c"; // 產生要寫的檔案 file_text=FILE_TEXT; // 讀入事先編好的房間檔 exits=get_exits(i); // 依據 i 去讀出這個房間有設哪些出口, 連接哪個房間 foreach(tmp in keys(exits)) file_text+="\""+tmp+"\":\""+exits[tmp]+"\",\n"; // "east":"/d/xxx", file_text+="}\n"; write_file(files,file_text); } FILE_TEXT 的定法類似底下 #define FILE_TEXT "#include <mudlib.h>\ninherit ROOM;\n\nvoid create...." get_exits 則看各家的寫法,基本上就是做座標判讀,判斷 第 n 個房間的上下左右有沒有連結,以左右的判斷為例 // 假設 tmps[n] 是房間 if(n>0 && tmps[n-1]=="-") // 代表左邊有連結房間 if(n<(n1*2-1)*(n2*2-1)-1 && tmps[n+1]=="-") // 代表右邊有連結房間 if(n>n1+2 && tmps[n-(n1+2)]=="|") // 代表上面有連結房間 if(n<(n1*2-1)*(n2*2-1)-n1 && tmps[n+(n1+2)]=="|") // 代表下面有連結房間 重點就是要做邊界判定。 上面是大致的概念,用「移動磁頭」的概念,當我們想要對 第 n 個 x 做操作時,第一步就是計算出相對的座標出來.. 經過計算 由n ───→ 得出相對的 tmps[m] 所以建議將部份計算函數化.. 1. 由 n 得到 m 的函數 2. 判定邊界的函數 3. get_exits 4. 秀圖程式(隨時確認修改後的 tmps 是否正確) 以上一點心得。 LAechan -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 111.253.169.46
Searle:對這種有興趣的可以去看RW的code 11/06 16:51
laechan:我記得以前 doom 也有 imm 討論過相關的設定, 另一個設定 11/06 18:49
laechan:是「如何在 mud 呈現一個 100x100 格的區域」 11/06 18:49
pssjim:FS狂想空間有個殭屍洞是類似的區域,有空可以去問一下喔 11/07 14:10
jaykill:pss不上線還在這邊喇賽 11/07 21:24
laechan:呵這應該是在各 mud 均列為機密的東西吧 11/07 21:56
Picoro:以前有寫過類似的程式 ... 不過我是反過來的作法 ... 11/09 02:33
Picoro:我是先隨機決定好兩個點或多個點為出口 11/09 02:33
Picoro:之後隨機放置障礙物 , 開始亂擺 11/09 02:34
Picoro:擺完後我是使用EDA用的routing演算法"flooding algorithm" 11/09 02:35
Picoro:從終點開始一直跑 , 直到它可以連結到起點 11/09 02:35
Picoro:之後再用隨機方式 , 看要它繼續淹幾次 11/09 02:36
Picoro:若一直沒有找到起點 , 但所有結點淹不下去 , 11/09 02:37
Picoro:那就重新擺障礙物 , 再淹一次 , 一直到有路連通起終點 11/09 02:37
Picoro:由於淹的過程已經建立好連結的指標 , 因此寫檔也很快 11/09 02:38
Picoro:但我最大的問題還是在敘述很難寫 ... 所以就不鳥鳥之 Orz 11/09 02:39
belion:應該也能將敘述用此類作法.? 11/09 09:40
laechan:做法有很多種可行 11/09 12:54
kyoe:敘述真是大家心中的一個痛阿!! 11/09 15:47
Picoro:畢竟MUD是文字敘述的東西 , 如果是圖型 , 或許會簡單許多 11/09 16:18
neoyori:圖形更困難吧,就算像RPGMaker那樣有素材給你貼也要貼超久 11/10 00:32
Picoro:不過如果每一格都可以用像FC時代的貼圖 , 看起來還ok的感覺 11/10 01:53
Picoro:畢竟以自動化設定區域來說 , 隨機選素材來貼應該比敘述好用 11/10 01:54
Picoro:不過沒有實際接觸那種東西 , 有些可能是我沒看到的東西 11/10 01:55
隨機敘述還有一種做法,適用於發展已久的 mud,它的做法 同樣是建立資料庫,但是建立的標的是「選定的房間」,例 如說底下三個房間.... /area/room/snake/009.c 毒蛇地穴 - 你看到在洞穴內長著一些從沒在其他地方見過的蕈類, 這些蕈類 的上頭有著一點一點暗紅色的圓形斑點, 據說這些蕈類都含有劇 毒, 吃了馬上靈魂出竅. /area/room/spipder/008.c 千蛛洞 洞穴內一片黑暗, 而且你感覺到你臉上與身體上都黏上了蜘蛛絲 , 感覺怪討厭的. /area/room/scorpion/003.c 天蠍洞 裡頭屍骨遍布滿地, 殘破的衣服上還沾滿著血跡, 可能是在與毒 物戰鬥時死去的冒險者吧! 因為在衣服上還有奇特的黑色液體殘 留著. 假設這類的房間搜集了約一兩百個,建成的資料錄如下.. string *room_files=([]); room_files=({ "/area/room/snake/009.c", "/area/room/spipder/008.c", "/area/room/scorpion/003.c", . . . }); 那基本做法有兩種.. 一、進入一個房間時,該房間的敘述「隨機取上述房間的其中一   個」 string query_long() { string files=room_files[random(sizeof(room_files))]; object room; if(room=find_object_or_load(files)) return room->query("long"); } 二、搭配三段敘述法 string get_msg(object r1,object r2,object r3); string query_long() { int s; object room1,room2,room3; room1=find_object_or_load(room_files[random(s)]); room2=find_object_or_load(room_files[random(s)]); room3=find_object_or_load(room_files[random(s)]); return get_msg(room1,room2,room3); } string get_msg(object r1,object r2,object r3) { string *m1,*m2,*m3,tmp,msg; int i,j; m1=explode(r1->query("long"),", "); m2=explode(r2->query("long"),", "); m3=explode(r3->query("long"),", "); tmp=sprintf("%s, %s, %s.",m1[0],m2[1],m3[2]); msg=""; j=strlen(tmp); // 每 28 個中文字一行 for(i=0;i<j;i=i+56) msg+=tmp[i..i+55]+"\n"; return msg+tmp[i..j-1]+"\n"; } 其中第二種做法只要做好資料前處理其實就是三段敘述法, 以這種方式形成的房間敘述有時會像底下這樣... xxx.c 某房間 你看到在洞穴內長著一些從沒在其他地方見過的蕈類, 而且你感 覺到你臉上與身體上都黏上了蜘蛛絲, 可能是在與毒物戰鬥時死 去的冒險者吧! 問題:像這樣完全不知所云的敘述真的可以嗎? 我只能說,嘛,聖殿是可以的。聖殿有好幾千個房間的敘述 都是許多巫師認真撰寫下的產物,從裡面取樣產生新的敘述 並不困難,聖殿的[新區域]以這樣的方式產生敘述完全沒有 問題,因為根本沒啥玩家在看房間敘述,這才是讓我興起想 寫隨機地圖、隨機敘述、甚至隨機怪物分配等工具或繼承用 物件的原因,這樣就不需要再徵新巫師、也不需要再向玩家 徵求相關的東西,更不需要忍受絞盡腦汁寫的敘述被蹧蹋的 不爽感。 (當然實際上我還是會要求產生的敘述要夠正常) 後 mud 時代,我覺得 coding 人員的時間應該花在重點上, 而不是花在這類純資料的構思上,我計劃讓聖殿明年至少增 加30個以「隨機」為主架構的區域,大部份是區域的附屬子 區域(如OX洞窟、OX塔)。 ※ 編輯: laechan 來自: 122.117.11.103 (11/10 05:45)
dannielz:推沒啥玩家在看敘述 尤其是這種隨機生成的地圖 11/10 15:02
dannielz:除非帶有解謎提示性質 否則沒什麼必要在敘述上鑽牛角尖吧 11/10 15:03
kruz:diablo剛出來的時候就有人寫過類似的,後來有發過paper的樣子 11/11 03:43
kruz:99年左右的mud研討會的時候也有發表過. 11/11 03:43
kruz:翻了一下,應該是第一屆研討會就發表了,所以是96 or 97的樣子 11/11 03:48
kruz:實作應該是在ES2上有跑過 11/11 03:49