在画布中随机生成对象,不重复或重叠

Posted

技术标签:

【中文标题】在画布中随机生成对象,不重复或重叠【英文标题】:Randomly generate objects in canvas without duplicate or overlap 【发布时间】:2012-12-31 02:40:29 【问题描述】:

如何在地图上生成对象,而不让它们占用相同的空间或在 html5 画布上重叠?

X 坐标在一定程度上是随机生成的。我想检查数组内部是否已经存在,以及之后的 20 个值(以考虑宽度),但没有运气。

var nrOfPlatforms = 14,
platforms = [],
platformWidth = 20,
platformHeight = 20;
var generatePlatforms = function()
  var positiony = 0, type;
  for (var i = 0; i < nrOfPlatforms; i++) 
    type = ~~(Math.random()*5);
    if (type == 0) type = 1;
    else type = 0;
    var positionx = (Math.random() * 4000) + 500 - (points/100);
    var duplicatetest = 21;
    for (var d = 0; d < duplicatetest; d++) 
      var duplicate = $(jQuery.inArray((positionx + d), platforms));
      if (duplicate > 0) 
        var duplicateconfirmed = true;
      
    
    if (duplicateconfirmed) 
      var positionx = positionx + 20;
    
    var duplicateconfirmed = false;
    platforms[i] = new Platform(positionx,positiony,type);
  
();

我最初通过让它们生成在大约 4000 大的区域中来进行作弊修复,降低了几率,但我想随着游戏的进行增加难度,通过让它们看起来更在一起,使其更难。但随后它们重叠。

粗略的图片形式,我想要这个

....[]....[].....[]..[]..[][]...

不是这个

......[]...[[]]...[[]]....[]....

我希望这是有道理的。

作为参考,这里是数组检查和难度之前的代码,只是便宜的距离破解。

var nrOfPlatforms = 14,
platforms = [],
platformWidth = 20,
platformHeight = 20;
var generatePlatforms = function()
  var position = 0, type;
  for (var i = 0; i < nrOfPlatforms; i++) 
    type = ~~(Math.random()*5);
    if (type == 0) type = 1;
    else type = 0;
    platforms[i] = new Platform((Math.random() * 4000) + 500,position,type);
  
();

编辑 1

经过一些调试,重复返回 [object Object] 而不是索引号,但不知道为什么

编辑 2

问题是对象在数组平台中,而x在数组对象中,那么我该如何再次搜索呢? ,这就是它之前失败的原因。 感谢 firebug 和 console.log(platforms);

platforms = [Object  image=img,  x=1128,  y=260,  more..., Object  image=img,  x=1640,  y=260,  more... etc

【问题讨论】:

对象的宽度是否可变? @JasonSperske 没有 20px 的固定宽度 您可以将它们映射到一个网格(将对象捕捉到 20 个像素增量),然后跟踪填充在 2d 散列对象中的内容。 @Shmiddty 我该怎么做? 【参考方案1】:

您可以实现一个 while 循环,该循环尝试插入一个对象,如果它发生冲突,它会静默失败。然后添加一个计数器并在放置所需数量的成功对象后退出 while 循环。如果对象靠得很近,则此循环可能会运行更长的时间,因此您可能还想给它一个最长的寿命。或者你可以实现一个'是否甚至可以将 z 对象放在 x 和 y 的地图上'以防止它永远运行。

这是一个例子(demo):

//Fill an array with 20x20 points at random locations without overlap
var platforms = [],
    platformSize = 20,
    platformWidth = 200,
    platformHeight = 200;

function generatePlatforms(k) 
  var placed = 0,
      maxAttempts = k*10;
  while(placed < k && maxAttempts > 0) 
    var x = Math.floor(Math.random()*platformWidth),
        y = Math.floor(Math.random()*platformHeight),
        available = true;
    for(var point in platforms) 
      if(Math.abs(point.x-x) < platformSize && Math.abs(point.y-y) < platformSize) 
        available = false;
        break;
      
    
    if(available) 
      platforms.push(
        x: x,
        y: y
      );
      placed += 1;
    
    maxAttempts -= 1;
  


generatePlatforms(14);
console.log(platforms);

【讨论】:

仍然存在检查它们是否碰撞或重叠的功能失败的问题,并且仍然放置它 @RudigerKidd 我添加了一些应该执行此操作的 javascript【参考方案2】:

以下是实现网格捕捉哈希的方法:http://jsfiddle.net/tqFuy/1/

var can = document.getElementById("can"),
    ctx = can.getContext('2d'),
    wid = can.width,
    hei = can.height,
    numPlatforms = 14,
    platWid = 20,
    platHei = 20,
    platforms = [],
    hash = ;

for(var i = 0; i < numPlatforms; i++)
  // get x/y values snapped to platform width/height increments
  var posX = Math.floor(Math.random()*(wid-platWid)/platWid)*platWid,
    posY = Math.floor(Math.random()*(hei-platHei)/platHei)*platHei;

  while (hash[posX + 'x' + posY])
    posX = Math.floor(Math.random()*wid/platWid)*platWid;
    posY = Math.floor(Math.random()*hei/platHei)*platHei;
  

  hash[posX + 'x' + posY] = 1; 
  platforms.push(new Platform(/* your arguments */));

请注意,我正在连接 x 和 y 值并将其用作哈希键。这是为了简化检查,并且只是一个可行的解决方案,因为我们将 x/y 坐标捕捉到特定的增量。如果我们不捕捉,碰撞检查会更加复杂。

对于大型集合(根据您的标准似乎不太可能),使用排除方法可能会更好:生成所有可能位置的数组,然后对于每个“平台”,从数组中随机选择一个项目,然后将其从数组中删除。这类似于你如何洗牌。

编辑 — 需要注意的一点是numPlatforms &lt;= (wid*hei)/(platWid*platHei) 的计算结果必须为真,否则 while 循环将永远不会结束。

【讨论】:

我现在必须尝试一下,我最终想通了,但解决方案让它真的很慢。所以,让我们试一试。谢谢 @RudigerKidd 哈希几乎总是比在数组中搜索值更快。某些浏览器上的小数据集除外。【参考方案3】:

我使用这段代码搜索数组中的对象,找到了另一个问题 (Searching for objects in JavaScript arrays) 的答案

function search(array, value)
    var j, k;
    for (j = 0; j < array.length; j++) 
        for (k in array[j])   
            if (array[j][k] === value) return j;
        
    

我最终还重写了一堆代码,以在其他地方加速并更好地回收平台。

它有效,但缺点是我的平台较少,因为它真的开始变慢了。最后这就是我想要的,但这样做已经不可行了。

var platforms = new Array();
    var nrOfPlatforms = 7;
    platformWidth = 20,  
    platformHeight = 20;
    var positionx = 0;
    var positiony = 0;
    var arrayneedle = 0;
    var duplicatetest = 21;

    function search(array, value)
        var j, k;
        for (j = 0; j < array.length; j++) 
            for (k in array[j])   
                if (array[j][k] === value) return j;
            
        
    

    function generatePlatforms(ind)  
        roughx = Math.round((Math.random() * 2000) + 500);
        type = ~~(Math.random()*5);  
        if (type == 0) type = 1;  
        else type = 0;  

        var duplicate = false;

        for (var d = 0; d < duplicatetest; d++) 
            arrayneedle = roughx + d;
            var result = search(platforms, arrayneedle);
            if (result >= 0) 
                duplicate = true;
            
        

        if (duplicate = true) 
            positionx = roughx + 20;
        
        if (duplicate = false) 
            positionx = roughx;
        
        platforms[ind] = new Platform(positionx,positiony,type);  
      

    var generatedplatforms = function()
        for (var i = 0; i < nrOfPlatforms; i++) 
            generatePlatforms(i);
        ;
    ();

【讨论】:

【参考方案4】:

您使用大数据,生成所有可能性,将每个可能性存储在一个数组中,对数组进行洗牌, 修剪前 X 项,这是您的非启发式算法。

【讨论】:

以上是关于在画布中随机生成对象,不重复或重叠的主要内容,如果未能解决你的问题,请参考以下文章

生成不重复随机数函数

如何让C#产生不重复的随机数

excel如何随机生成不重复整数?

excel如何生成一定范围内不重复的随机整数?

怎么用python生成随机的且不重复的整数?

求PHP语言随机自动生成不重复的数字