javascript - 在 JavaScript 中的对象数组中查找数字的快速方法

标签 javascript arrays html object side-scroller

我需要检查一个物体是否在远处以将其显示在屏幕上(它是一个横向卷轴视频游戏)

到目前为止我有这个:

for ( var i=0; i < Coins.length; i++ )
{
    var obj = Coins[i];


    if ( worldObj.distance > obj.distance && worldObj.distance < obj.distance + canvas.height )
    {

        DrawCoins(obj);
    }
}

其中 worldObj.distance 是玩家走过的距离,obj.distance 是物体的距离。

问题:

由于关卡中的硬币数量(超过 10,000),这个 for 循环导致移动设备的性能大幅下降,并且每秒执行 60 次(60 fps)

我该如何解决这个问题?

谢谢! :)

编辑:尝试在循环之前将 canvas.height 缓存到变量中(例如:var height = canvas.height;)。没有性能差异(44 毫秒与 I5 2500K 上的 44 毫秒,想象一下在移动设备上!!)。

编辑:尝试在循环之前缓存 Coins.length,(例如:var len = Coins.length;)。没有性能差异(44 毫秒与 44 毫秒)。

编辑:这就是我创造硬币的方式:

for(var i=0; i<10000; i++)
{

    /* Coins */
    for ( var z=0; z < 6; z++ )
    {
        if ( RNG(0,100) < Upgrades.coinChance ) // random number generator, Upgrades.coinChance = 5; -> 5% chance
        {
            Coins.push({ active: 1, type: "Gold", cash: 5, x: 60*(z+1), distance: i*RNG(20,100) });
        }
    }
}

最佳答案

好的。我做了一些数字运算并提出了两种算法,并在它们之间进行了权衡。

作为测试平台,我正在运行以下初始化代码:

var n,m;

var Coin=function(x)
{
    return {x:x,r:1};
}
var coins=[];
var map={};

var viewSize=50;
var worldSize=1000;

n=100000;
while(n--)
{
    coins[n]=Coin(worldSize*Math.random());
}

如您所见,这里有 100000 个硬币。我知道,比你在回答中规定的要多,但我想对事情进行压力测试。

第一个算法是您在问题中发布的算法的优化版本。它只是循环并测试每个硬币的最近边缘是否小于 viewSize/2 到某个点 x 的距离。如果是这样,它会将其添加到一个数组中,并最终返回该数组。

var checkCoins1=function(list,x,w)
{
    var selected,k,n,no;
    selected=[];
    n=list.length;
    while(n--)
    {
        no=list[n];
        if(Math.abs(no.x-x)<w/2+no.r)
        {
            selected.push(no);
        }
    }
    return selected;
};

这种方法不需要额外的时间来设置,每次执行我们的 100000 个硬币需要 7 毫秒。绝对是动画循环中的成本,但可以控制。

第二种算法使用 map 。它首先对硬币列表进行排序,然后在 worldSize 中选择一组点,每个点都与最后一个点相距 viewSize。它创建一个以这些点为键的对象。然后循环遍历所有硬币并保存最接近对象中每个点的硬币的索引。这需要一些时间,但只需要完成一次。当实际循环运行时,它只是在 map 中找到紧靠查看窗口左边缘(或下边缘,视情况而定)之前的点。然后它向前循环遍历列表中的所有硬币,将它们保存到一个数组中,直到它到达比查看窗口的右(或上)边缘更远的硬币。然后它停止并返回数组。这样,它就不必检查列表中的每个硬币,而只需检查其中的几个。

设置代码如下所示:

coins.sort(
    function(a,b)
    {
        return -(a.x<b.x)+(a.x>b.x);
    }
);
n=Math.floor(worldSize/viewSize);
while(n--)
{
    map[n*viewSize]=undefined;
}
n=coins.length;
while(n--)
{
    for(m in map)
    {
        if(map[m]===undefined || Math.abs(coins[n].x-m)<Math.abs(coins[map[m]].x-m))
        {
            map[m]=n;
        }
    }
}

主循环是这样的:

var checkCoins2=function(list,map,x,w)
{
    var selected,y,k,n,no;
    selected=[];
    y=x-w/2;
    n=map[Math.floor(y/w)*w];
    while(1)
    {
        no=list[n++];
        if(Math.abs(no.x-x)<w/2+no.r)
        {
            selected.push(no);
        }
        else if(no.x>x)
        {
            break;
        }
    }
    return selected;
};

初始化耗时高达 900 毫秒,但循环每次运行仅需 1 毫秒。随着 worldSizeviewSize 之间的比率增加,循环将变得越来越快。

总的来说,我会说第一种算法更简单,但是如果您发现自己在动画循环中时间紧迫并且可以在游戏(或关卡)加载时花一秒钟时间进行初始化,那么您应该使用第二种算法.

也许,如果您一开始就知道硬币的放置位置,您甚至可以在编写代码时预先对列表进行排序并预先构建 map 。那么您根本不需要客户端进行初始化。

如有任何问题,请提出!

关于javascript - 在 JavaScript 中的对象数组中查找数字的快速方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23172885/

相关文章:

javascript - 要保存的 url 参数是 JavaScript 中的

arrays - 如何删除数组数组中的 [""]?

javascript - 两个按钮一个功能(递增、递减)

javascript - 选择数组中的项目 - Javascript - 使用 Filter 方法

javascript - jQuery 中的鼠标按下事件

jquery - 隐藏版权 Bing map Ajax 控件 7.0

javascript - e.keycode 在 firefox 19.0.2 、chrome 25.0.1364.172 m、IE 8 中未定义

javascript - d3.js 时间序列无限滚动

javascript - 计算先前元素的数量

javascript - 减少和合并对象集合的最佳方法是什么