Re: [閒聊] 區域產生器
※ 引述《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
→
11/06 16:51, , 1F
11/06 16:51, 1F
→
11/06 18:49, , 2F
11/06 18:49, 2F
→
11/06 18:49, , 3F
11/06 18:49, 3F
推
11/07 14:10, , 4F
11/07 14:10, 4F
推
11/07 21:24, , 5F
11/07 21:24, 5F
→
11/07 21:56, , 6F
11/07 21:56, 6F
推
11/09 02:33, , 7F
11/09 02:33, 7F
→
11/09 02:33, , 8F
11/09 02:33, 8F
→
11/09 02:34, , 9F
11/09 02:34, 9F
→
11/09 02:35, , 10F
11/09 02:35, 10F
→
11/09 02:35, , 11F
11/09 02:35, 11F
→
11/09 02:36, , 12F
11/09 02:36, 12F
→
11/09 02:37, , 13F
11/09 02:37, 13F
→
11/09 02:37, , 14F
11/09 02:37, 14F
→
11/09 02:38, , 15F
11/09 02:38, 15F
→
11/09 02:39, , 16F
11/09 02:39, 16F
→
11/09 09:40, , 17F
11/09 09:40, 17F
→
11/09 12:54, , 18F
11/09 12:54, 18F
推
11/09 15:47, , 19F
11/09 15:47, 19F
推
11/09 16:18, , 20F
11/09 16:18, 20F
推
11/10 00:32, , 21F
11/10 00:32, 21F
推
11/10 01:53, , 22F
11/10 01:53, 22F
→
11/10 01:54, , 23F
11/10 01:54, 23F
→
11/10 01:55, , 24F
11/10 01:55, 24F
隨機敘述還有一種做法,適用於發展已久的 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)
推
11/10 15:02, , 25F
11/10 15:02, 25F
→
11/10 15:03, , 26F
11/10 15:03, 26F
→
11/11 03:43, , 27F
11/11 03:43, 27F
→
11/11 03:43, , 28F
11/11 03:43, 28F
→
11/11 03:48, , 29F
11/11 03:48, 29F
→
11/11 03:49, , 30F
11/11 03:49, 30F
討論串 (同標題文章)
mud 近期熱門文章
PTT遊戲區 即時熱門文章