自分で簡略化されたバージョンをコーディングしている最中なので、NetHackで遊んでいました。私の質問は、廊下はどのように実装されているのですか?私はここ数日アプローチを考えようとしていて、合理的なものを思い付くことができません。
2 に答える
Nethack でのマップ生成は mkmap.c で行われます。メソッドjoin_map
は、どの部屋を接続するかを決定します。dig_corridor
sp_lev.cのメソッドが実際の掘り下げを行います。
関心のある行:
if (tx > xx) dx = 1;
else if (ty > yy) dy = 1;
else if (tx < xx) dx = -1;
else dy = -1;
これは、「現在の X と Y」を「ターゲットの X と Y」と比較して、最初に掘り下げる方向を決定します。
while(xx != tx || yy != ty) {
/* loop: dig corridor at [xx,yy] and find new [xx,yy] */
if(cct++ > 500 || (nxcor && !rn2(35)))
return FALSE;
いくつかの例外を除いて、目標に到達するまで続けます。「回廊数」cct
が 500 の場合、長い道のりを掘ったことになり、あきらめたいと思います。nxcor が true の場合、回廊は行き止まりになります。rn2
は乱数ジェネレーターであるため、行き止まりが発生する可能性がある場合は、各ループ中にあきらめる可能性がわずかにあります。
crm = &levl[xx][yy];
if(crm->typ == btyp) {
if(ftyp != CORR || rn2(100)) {
crm->typ = ftyp;
if(nxcor && !rn2(50))
(void) mksobj_at(BOULDER, xx, yy, TRUE, FALSE);
} else {
crm->typ = SCORR;
}
crm は、現在表示されているタイルです。ほとんどの場合、タイルを通常の廊下にします。場合によっては、タイルを SCORR (秘密の回廊) にすることもあります。これは、検索して見つけた後にのみ通過できます。道が行き止まりになる可能性がある場合は、岩も配置します。
/* do we have to change direction ? */
if(dy && dix > diy) {
register int ddx = (xx > tx) ? -1 : 1;
crm = &levl[xx+ddx][yy];
if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
dx = ddx;
dy = 0;
continue;
}
} else if(dx && diy > dix) {
register int ddy = (yy > ty) ? -1 : 1;
crm = &levl[xx][yy+ddy];
if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
dy = ddy;
dx = 0;
continue;
}
}
現在の位置と目標位置の間に引かれた線の「傾き」が 45 度からかなり離れている場合、方向を変更しようとします。X 軸に沿って移動している場合は、代わりに Y 軸に沿って移動を開始します。およびその逆。これにより、2 つの対角線の部屋をつなぐ典型的な曲がりくねった階段状の廊下ができます。方向を変えると障害物 (他の部屋、溶岩など) にぶつかる可能性がある場合は、進んでいた方向に進み続けます。
ソースを自分で確認できます。リンク
ずっと前にソースコードを調べたことを覚えています。メモリは少しさびていますが、かなり単純なシーケンシャル プロセスだったと思います。ボックスは、利用可能なタイルの特定の比率で部屋に描画され、廊下を生成し、それらに対して部屋をマスクします。彼らはアクセスできないエリアを探すパスを持っていたと思います(フラッドフィルを使用していますか?)。
次に、階段/ドア/その他が取り込まれました。
あなたが探しているのは、迷路生成アルゴリズムです。トンがあります。