6

「タンクウォーズ」ゲームをプレイしたことがありますか?

ここに画像の説明を入力

私は JavaScript + Canvas を使ってこのゲームをプログラミングしています (個人的な挑戦のため)。必要なのは、ゲームを開始するたびにそのランダムな緑の土地を生成するアルゴリズムですが、私は数学があまり得意ではないので、自分でやるな。

誰かにコードを教えてもらいたくありません。アルゴリズムのアイデアだけが欲しいのです。

ありがとう!

4

6 に答える 6

5

ここに画像の説明を入力
(9セグメント)

フィドルのデモ

ここに画像の説明を入力
(7セグメント)

主な生成関数は次のようになります。

var numOfSegments = 9;                      // split horizontal space
var segment = canvas.width / numOfSegments; // calc width of each segment
var points = [], calcedPoints;
var variations = 0.22;                      // adjust this: lower = less variations
var i;

//produce some random heights across the canvas
for(i=0; i < numOfSegments + 1; i++) {
    points.push(segment * i);
    points.push(canvas.height / 2.8 + canvas.height * variations * Math.random());
}

//render the landscape
ctx.beginPath();
ctx.moveTo(canvas.width, canvas.height);
ctx.lineTo(0, canvas.height);

calcedPoints = ctx.curve(points);           // see below

ctx.closePath();
ctx.fillStyle = 'green';
ctx.fill();

このcurve()関数は、カーディナル スプラインを生成する別の関数です。ここで、張力値を保存してより多くのスパイクを作成するように変更できます。生成されたポイントを、タンクが移動する場所と角度の基準として使用することもできます。

カーディナル スプラインの関数:

CanvasRenderingContext2D.prototype.curve = function(pts, tension, numOfSegments) {

    tension = (tension != 'undefined') ? tension : 0.5;
    numOfSegments = numOfSegments ? numOfSegments : 16;

    var _pts = [], res = [], t, i, l, r = 0,
        x, y, t1x, t2x, t1y, t2y,
        c1, c2, c3, c4, st, st2, st3, st23, st32;

    _pts = pts.concat();
    _pts.unshift(pts[1]);
    _pts.unshift(pts[0]);
    _pts.push(pts[pts.length - 2]);
    _pts.push(pts[pts.length - 1]);

    l = (_pts.length - 4);
    for (i = 2; i < l; i+=2) {

        //overrides and modifies tension for each segment.
        tension = 1 * Math.random() - 0.3;

        for (t = 0; t <= numOfSegments; t++) {
            t1x = (_pts[i+2] - _pts[i-2]) * tension;
            t2x = (_pts[i+4] - _pts[i]) * tension;      
            t1y = (_pts[i+3] - _pts[i-1]) * tension;
            t2y = (_pts[i+5] - _pts[i+1]) * tension;

            st = t / numOfSegments;
            st2 = st * st;
            st3 = st2 * st;
            st23 = st3 * 2;
            st32 = st2 * 3;

            c1 = st23 - st32 + 1; 
            c2 = -(st23) + st32; 
            c3 = st3 - 2 * st2 + st; 
            c4 = st3 - st2;

            x = c1 * _pts[i]    + c2 * _pts[i+2] + c3 * t1x + c4 * t2x;
            y = c1 * _pts[i+1]  + c2 * _pts[i+3] + c3 * t1y + c4 * t2y;

            res[r++] = x;
            res[r++] = y;               
        } //for t
    } //for i

    l = res.length;
    for(i=0;i<l;i+=2) this.lineTo(res[i], res[i+1]);

    return res;  //return calculated points
}
于 2013-06-12T22:08:37.383 に答える
3

パーリン ノイズの生成を調べてください。これを優れた平滑化アルゴリズムと組み合わせることで、かなり優れた地形を生成でき、かなり高速です。コードのリファレンス バージョンがネットのどこかにあり、かなり有利なスタートを切ることができます。

于 2013-06-12T17:22:59.393 に答える
1

うわー...ある時点で、私は戦車戦に完全にハマっていました

あなたは学習の冒険をしているので...

context.globalCompositeOperation についても学ぶことができます。

このキャンバス操作により、実際の草の画像を取得し、それをゲームに合成できます。

drawImage(); の x/y を変更することで、草の外観をランダム化できます。

確かに、実際の草は、完成したゲームに含めるには気が散りすぎるかもしれませんが、合成について学ぶことは貴重な知識です。

...そして質問の+1:自分自身に挑戦してよかったです!

于 2013-06-12T20:08:37.080 に答える
1

@DesertIvyが指摘したように、フラクタルなどの斬新で書かれたアルゴリズムが確かにあり、ライブラリもあるかもしれませんが、画像にあるものを生成したい場合は、かなり簡単です。ポイント間の曲線)。一度に正しくしようとせず、段階的に行うと簡単です。

  1. ランダムを使用して、ゲーム画面の x 領域をセクション (最小幅と最大幅) に分割します (最後のセクションでは少しずれているかもしれませんが、それほど問題ではないと思います)。セクションが交わるx-esを覚えておいてください(ゲーム画面の境界にあるものを含む)
  2. 以前に記憶した xs に、ys も含めるデータ構造を準備します。から始めleftmost.y = 0ますslope = Math.random()-0.5;
  3. 1: で始まる次の未定義の y をそれぞれ生成しright.y = left.y + slope * (right.x-left.x);、各 y: の後に勾配を更新しますslope += Math.random()-0.5;。すべてがゲーム画面に収まる場合は、今のところ気にしないでください。
  4. 円弧が必要な場合は、セクションごとにランダムに「曲線」パラメーターを生成できます。これは、直線と比較して線の中央がどれだけ隆起しているかを表します。
  5. ys をゲーム画面に合わせます。まず、生成された最大および最小の y ( mingenymaxgeny) を見つけます (ポイント 4 で生成中にこれを追跡できます)。minscryゲーム画面 ( 、 )の最大値と最小値の y を選択します (maxscry上から 4 番目、下から 4 番目と言います)。minscry次に、生成された ys を と の間にまたがるように変換します。maxscryすべての点について、 do を行いますapoint.y = minscry + (maxscry-minscry)/(maxgeny-mingeny)*(apoint.y-mingeny)
  6. [x,y] ポイント間の線を地形として使用します。「曲線」を使用する場合は、curvemodifierleftx と rightx の間のセクションの特定の x の y に追加します。円弧は円である必要はありません: 簡単に生成できる放物線または余弦をお勧めします:var middle = (left.x+right.x)/2; var excess = (x-left)/(middle-left);そして、var curvemodifier = curviness * (1-excess*excess);またはvar curvemodifier = curviness * Math.cos(Math.PI/2*excess).
于 2013-06-12T18:27:46.860 に答える
1

まず、ランダムな y (55,65 の間) のポイントが必要です。got x=0 したがって、これが緑の原点です。x1,y1 のままにします (x1 は常に 0)。

次に、30 から 40 の間のランダムな整数が必要です。これは x2 です。そして、y1 + 8 から y1 + 20 の範囲にあるランダムな y。

次に、同じ原理で x3 と y3 (式タイプ 1 と呼びましょう)

ここで、最初に -1 または 1 のいずれかの乱数を取得する必要があります。これは y4 の方向になります。したがって、y4 は y3 より高くなったり低くなったりする可能性があります。これは式タイプ 2 になります。

新しい y の最大値と最小値の y を保持する必要があります。それが交差する場合は逆になります -> これは補正タイプの式 3 になります。

Xn はボードの幅 >= まで増加し続けます。

日食の行に参加してください...そして、ウェブ検索が進むべき道のようです!

于 2013-06-12T17:23:07.580 に答える
1

これを簡単にするために使用できるコード化されたライブラリがたくさんあると確信しています。しかし、これを自分でコーディングしようとしている場合、これが私の考えです。

他のすべてのものから地形を定義する必要があります。たとえば、環境のすべての部分がクラスターです。たとえば、ノード (ポイント) によって、これらのクラスターをどのように分離するかを定義する必要があります。

一連のポイントから多角形を作成できます。この多角形は、この場合は地形のように、任意のものにすることができます。

渡された画像にピークがあり、それらがノード (ポイント) であることを確認してください。環境の境界にもノードを定義することを忘れないでください。

于 2013-06-12T17:23:48.933 に答える