12

私は、子供たちが質問に従って正しい数字を打たなければならない新しい「もぐらたたき」スタイルのゲームを作成しています。タイマーがあり、正解と不正解を数え、ゲームが開始されると、設定された時間にコンテナにランダムに表示される「キャラクター」と呼ばれる多数の div があります。

私が抱えている問題は、完全にランダムであるため、「文字」が互いに重なって表示されることがあります。コンテナ内の設定された場所に表示され、表示されたときに重ならないように整理する方法はありますか。

ここに、div をコンテナーにマップするコードがあります。

    function randomFromTo(from, to) {
        return Math.floor(Math.random() * (to - from + 1) + from);
}

function scramble() {
    var children = $('#container').children();
    var randomId = randomFromTo(1, children.length);
    moveRandom('char' + randomId);
}

function moveRandom(id) {
    var cPos = $('#container').offset();
    var cHeight = $('#container').height();
    var cWidth = $('#container').width();
    var pad = parseInt($('#container').css('padding-top').replace('px', ''));
    var bHeight = $('#' + id).height();
    var bWidth = $('#' + id).width();
    maxY = cPos.top + cHeight - bHeight - pad;
    maxX = cPos.left + cWidth - bWidth - pad;
    minY = cPos.top + pad;
    minX = cPos.left + pad;
    newY = randomFromTo(minY, maxY);
    newX = randomFromTo(minX, maxX);
    $('#' + id).css({
        top: newY,
        left: newX
    }).fadeIn(100, function () {
        setTimeout(function () {
            $('#' + id).fadeOut(100);
            window.cont++;
        }, 1000);
    });

それが役立つなら、私はフィドルを持っています.. http://jsfiddle.net/pUwKb/8/

4

4 に答える 4

5

@aug が示唆するように、描画時に物を配置できない場所を把握し、有効な位置にのみ配置する必要があります。これを行う最も簡単な方法は、現在占有されている位置を手元に置いて、提案された位置と照合できるようにすることです。

私は次のようなものを提案します

// locations of current divs; elements like {x: 10, y: 40}
var boxes = [];

// p point; b box top-left corner; w and h width and height
function inside(p, w, h, b) {
     return (p.x >= b.x) && (p.y >= b.y) && (p.x < b.x + w) && (p.y < b.y + h);
}

// a and b box top-left corners; w and h width and height; m is margin
function overlaps(a, b, w, h, m) {
     var corners = [a, {x:a.x+w, y:a.y}, {x:a.x, y:a.y+h}, {x:a.x+w, y:a.y+h}];
     var bWithMargins = {x:b.x-m, y:b.y-m};
     for (var i=0; i<corners.length; i++) {
         if (inside(corners[i], bWithMargins, w+2*m, h+2*m) return true;
     }
     return false;
}

// when placing a new piece
var box;
while (box === undefined) {
   box = createRandomPosition(); // returns something like {x: 15, y: 92}
   for (var i=0; i<boxes.length; i++) {
      if (overlaps(box, boxes[i], boxwidth, boxheight, margin)) {
         box = undefined;
         break;
      }
   }
}
boxes.push(box);

警告: テストされていないコードです。タイプミスに注意してください。

于 2012-12-21T11:39:12.500 に答える
2

この問題には、少なくとも 2 つの方法でアプローチできます (これらの 2 つが頭に浮かびます)。

  1. 質問の数、質問パネルのサイズ、および各質問座標の位置を保持する配列に基づいて 2 次元のグリッド セグメンテーションを作成し、各時間枠でこれらのパネルを許可された座標の 1 つにランダムに配置します。

注: 詳細については、この記事を参照してください: http://eloquentjavascript.net/chapter8.html

  1. 2 番目のアプローチは同じ原則に従いますが、今回は、パネルをキャンバスに配置する前に、パネルが既存のパネルと重なっているかどうかを確認します。
var _grids;
var GRID_SIZE = 20 //a constant holding the panel size; 
function createGrids() {
    _grids = new Array();
    for (var i = 0; i< stage.stageWidth / GRID_SIZE; i++) {
        _grids[i] = new Array();
        for (var j = 0; j< stage.stageHeight / GRID_SIZE; j++) {
            _grids[i][j] = new Array();
        }
    }
}

次に、別の関数で衝突チェックを作成します。Actionscript での衝突チェックの要点を作成しましたが、Javascript でも同じ原則を使用できます。この要点は、インスピレーションを与える目的で作成しました。

于 2012-12-21T11:22:53.707 に答える
2

実装する必要がある基本的な考え方は、ランダムな座標が選択された場合、理論的には、許容されない境界を知っている必要があり、プログラムはそれらの場所を選択しないことを知っている必要があるということです (アルゴリズムを見つけるか、単にそれらを無視する方法を見つけるかどうか)。またはあなたのプログラムは、選択された数が境界内にないことを確認するために常にチェックします.後者は実装が簡単ですが、完全に偶然に頼っているため、それを行うのは悪い方法です)。

たとえば、座標 50、70 が選択されたとします。写真のサイズが 50x50 の場合、許可される範囲は、写真のサイズだけでなく、写真のすべての方向に 50px を除外して、重複が発生しないようにします。

お役に立てれば。時間があれば、例をコーディングしてみるかもしれませんが、それが問題を抱えていた場合、これが質問の概念的な側面に答えることを願っています.

ああ、ところで、このプログラムで本当に素晴らしい仕事をするのを忘れていました。それはすばらしく見えます:)

于 2012-12-21T11:09:03.183 に答える
0

ボードの幅に基づいた乱数を使用してから、高さでモジュロします...

ほくろを置くことができるセルを取得します。

位置については、9 つ​​のスポットがあるため、x と y は決して変化しないはずです。

x x x
x x x 
x x x

各セルは、ピクセルではなく % に基づいてサイズ変更され、画面のサイズ変更が可能になります。

1%3 = 1 (x) 3%3 = 0 (y)

その場合、オーバーラップはあり得ません。

ほくろが配置されると、必要に応じて拡張ロジックに基づいて、表示、非表示、または移動などを行うことができます。

物事を自分のやり方に保ちたいが、迅速な再配置アルゴリズムが必要な場合... x = y +高さを設定して、確認したい文字の X + 幅 >= x の場合は、NE を SW に設定するだけです。重複するアイテムの。また、最後の x をキャッシュし、乱数が < 最後 + アイテムの幅にならないようにすることで、描画ルーチンにそのロジックを強制することもできます。

newY = randomFromTo(minY, maxY); newX = randomFromTo(minX, maxX); if(newX > lastX + characterWidth){ /*needful*/}

ただし、まだ重複がある可能性があります...

それを完全に排除したい場合は、各 x がどこにあったかなどの状態を追跡し、そのリストを繰り返して新しい位置を見つけるか、最初にそれらを配置してから、交差せずにランダムに移動する必要があります。その時点からパディングだけで制御します。

全体として、X を 0 から開始し、X + 文字幅 > ボードの幅になるまでインクリメントする方が簡単だと思います。次に、Yを文字の高さだけ増やし、X = 0または文字幅またはその他のオフセットを設定します。

newX = 0; newX += characterWidth; if(newX + chracterWidth > boardWidth) newX=0; newY+= characterHeight;

その結果、オーバーラップがなくなり、現在行っていることを繰り返したり、追跡したりする必要がなくなります。唯一の欠点は、表示される文字のパターンが「チェッカー ボード スタイル」であるか、互いに隣り合っていることです (間にランダムな間隔がある可能性があります)。水平方向と垂直方向の配置 (必要に応じて、パディングをランダムに調整することもできます)

複雑さを増すのは、そもそもランダムなことです。

そして、私はあなたのフィドルを更新して、ランダムを排除し、重複を止めたことを証明しました:)

http://jsfiddle.net/pUwKb/51/

于 2013-01-09T09:02:10.000 に答える