2Dグリッドの障害物で「見通し線」をシミュレートしますか?


10

興味深い問題にぶつかった。見通し線をシミュレートする方法を理解する必要があります-障害物がある2Dグリッド上で十分に単純です。グリッドセルが表示されているか、表示されていません。

プレイヤーからn個のスペースを広げたり、隣接する障害物が検出されたときに水平方向の伝播をブロックしたりするなど、本当に初歩的なものを得ることができますが、それを我慢することはできません。他の多くのアプリは、隅などの視線を傾斜させるより洗練された方法を使用しており、私は標準に近づきたいと思っています。

これまでのところ、困惑したときのDCSSは私のインスピレーションの源でした。私は彼らが持っているものに近いものを手に入れたいと思っています:http : //crawl.sz.org/

どんな洞察もいただければ幸いです-助けてくれてありがとう!

(これが恥ずかしいほどにうるさい場合は許してください-数週間前にゲーム開発を始めただけで、追いつくように頑張っています。)


2
「視線をコーナーの周りに傾斜させる」と言うとき、正確にはどういう意味ですか?
ジェントルマン2013年

私が言える最高のことは、crawl.sz.orgでゲームをチェックアウトすることです。例として、プレーヤーが5タイル幅の水平壁の下に立っている場合、視線はその壁の水平面より上にありますが、現実的ではありません。私が概算できた最高のものは、見通し線を壁の水平面に保つことです。
CodeMoose 2013年

回答:


7

レイキャスティングは、視線を決定するための非常に高速で効率的な方法です。これは基本的に、特定の位置から特定の方向に光線(リダイレクトできない無限レーザーのようなものと考える)を送信することを含みます。このレイを使用すると、交差するポイントや、特定のポイントと交差したときに原点からどれだけ離れているかなどを判断できます。

したがって、たとえば、プレーヤー/敵のシナリオでは、光線は敵から発生し、方向はプレーヤーの位置になります。レイが固体タイルに衝突すると、敵はプレイヤーを見ることができません。そうでない場合、敵はプレイヤーを見ることができます。

これは、役立つはずの優れたチュートリアルです。

より簡単にタイルにスケーリングできるものについて、ブレゼンハムのラインアルゴリズム(要約するとラインを作成する)を検討することもできます。


1
行く方法のようです-特にブレゼンハムのようです。ヘルプdjentをありがとう!
CodeMoose 2013年

3

私がしているコードをブログに書い高さマップからの視界の計算行に。障害物がある単純なフラットマップは、非常にフラットな高さマップであり、この実装はまだ完全に適用可能です。

ここに画像の説明を入力してください

ここでは、C ++とそのO(n); マップの最大の高さがわかっている場合は、その高さの下に光線が残っていない走査線を追跡して、早期に追跡できます。

typedef std::vector<float> visbuf_t;

inline void map::_visibility_scan(const visbuf_t& in,visbuf_t& out,const vec_t& eye,int start_x,int stop_x,int y,int prev_y) {
    const int xdir = (start_x < stop_x)? 1: -1;
    for(int x=start_x; x!=stop_x; x+=xdir) {
        const int x_diff = abs(eye.x-x), y_diff = abs(eye.z-y);
        const bool horiz = (x_diff >= y_diff);
        const int x_step = horiz? 1: x_diff/y_diff;
        const int in_x = x-x_step*xdir; // where in the in buffer would we get the inner value?
        const float outer_d = vec2_t(x,y).distance(vec2_t(eye.x,eye.z));
        const float inner_d = vec2_t(in_x,horiz? y: prev_y).distance(vec2_t(eye.x,eye.z));
        const float inner = (horiz? out: in).at(in_x)*(outer_d/inner_d); // get the inner value, scaling by distance
        const float outer = height_at(x,y)-eye.y; // height we are at right now in the map, eye-relative
        if(inner <= outer) {
            out.at(x) = outer;
            vis.at(y*width+x) = VISIBLE;
        } else {
            out.at(x) = inner;
            vis.at(y*width+x) = NOT_VISIBLE;
        }
    }
}

void map::visibility_add(const vec_t& eye) {
    const float BASE = -10000; // represents a downward vector that would always be visible
    visbuf_t scan_0, scan_out, scan_in;
    scan_0.resize(width);
    vis[eye.z*width+eye.x-1] = vis[eye.z*width+eye.x] = vis[eye.z*width+eye.x+1] = VISIBLE;
    scan_0.at(eye.x) = BASE;
    scan_0.at(eye.x-1) = BASE;
    scan_0.at(eye.x+1) = BASE;
    _visibility_scan(scan_0,scan_0,eye,eye.x+2,width,eye.z,eye.z);
    _visibility_scan(scan_0,scan_0,eye,eye.x-2,-1,eye.z,eye.z);
    scan_out = scan_0;
    for(int y=eye.z+1; y<height; y++) {
        scan_in = scan_out;
        _visibility_scan(scan_in,scan_out,eye,eye.x,-1,y,y-1);
        _visibility_scan(scan_in,scan_out,eye,eye.x,width,y,y-1);
    }
    scan_out = scan_0;
    for(int y=eye.z-1; y>=0; y--) {
        scan_in = scan_out;
        _visibility_scan(scan_in,scan_out,eye,eye.x,-1,y,y+1);
        _visibility_scan(scan_in,scan_out,eye,eye.x,width,y,y+1);
    }
}

これは良いことですが、彼が望んでいるのは彼が投稿したリンクのようなものだとしたら、彼が思っているよりはるかに多いと思います。
ジェントルマン2013年

非常に詳細で印象的ですが、djentは正しいです-私の範囲をはるかに超えています。投稿ありがとうございます!
CodeMoose 2013年

@CodeMooseええと、その作業コード。カットアンドペーストするだけで、対象とする言語に文字通り翻訳できます。これはブレゼンハムの実装であり、段階的に行われるため、各正方形を1回しか訪問しません。グリッドの四角ごとにプレーヤーにブレゼンハム線を引くと、非常に遅くなります。
ウィル

良い点は
CodeMoose 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.