[英]Increase efficiency of a loop with jQuery
我有一個用jQuery編碼的游戲,其中機器人在屏幕上移動。 下面的代碼是一個每20毫秒運行一次的循環,當前,如果您有超過15個漫游器,您會開始注意到瀏覽器滯后(這是因為所有高級碰撞檢測都在進行)。
有什么辦法可以減少延遲,我可以提高延遲效率嗎?
ps抱歉,僅發布了一段代碼,如果沒有它,我看不到一種方法可以使我的觀點足夠清楚!
$.playground().registerCallback(function(){ //Movement Loop
if(!pause) {
for (var i in bots) {
//bots - color, dir, x, y, z, spawned?, spawnerid, prevd
var self = $('#b' + i);
var current = bots[i];
if(bots[i][5]==1) {
var xspeed = 0, yspeed = 0;
if(current[1]==0) { yspeed = -D_SPEED; }
else if(current[1]==1) { xspeed = D_SPEED; }
else if(current[1]==2) { yspeed = D_SPEED; }
else if(current[1]==3) { xspeed = -D_SPEED; }
var x = current[2] + xspeed;
var y = current[3] + yspeed;
var z = current[3] + 120;
if(current[2]>0&&x>PLAYGROUND_WIDTH||current[2]<0&&x<-GRID_SIZE||
current[3]>0&&y>PLAYGROUND_HEIGHT||current[3]<0&&y<-GRID_SIZE) {
remove_bot(i, self);
} else {
if(current[7]!=current[1]) {
self.setAnimation(colors[current[0]][current[1]]);
bots[i][7] = current[1];
}
if(self.css({"left": ""+(x)+"px", "top": ""+(y)+"px", "z-index": z})) {
bots[i][2] = x;
bots[i][3] = y;
bots[i][4] = z;
bots[i][8]++;
}
}
}
}
$("#debug").html(dump(arrows));
$(".bot").each(function(){
var b_id = $(this).attr("id").substr(1);
var collision = false;
var c_bot = bots[b_id];
var b_x = c_bot[2];
var b_y = c_bot[3];
var b_d = c_bot[1];
$(this).collision(".arrow,#arrows").each(function(){ //Many thanks to Selim Arsever for this fix!
var a_id = $(this).attr("id").substr(1);
var piece = arrows[a_id];
var a_v = piece[0];
if(a_v==1) {
var a_x = piece[2];
var a_y = piece[3];
var d_x = b_x-a_x;
var d_y = b_y-a_y;
if(d_x>=4&&d_x<=5&&d_y>=1&&d_y<=2) {
//bots - color, dir, x, y, z, spawned?, spawnerid, prevd
bots[b_id][7] = c_bot[1];
bots[b_id][1] = piece[1];
collision = true;
}
}
});
if(!collision) {
$(this).collision(".wall,#level").each(function(){
var w_id = $(this).attr("id").substr(1);
var piece = pieces[w_id];
var w_x = piece[1];
var w_y = piece[2];
d_x = b_x-w_x;
d_y = b_y-w_y;
if(b_d==0&&d_x>=4&&d_x<=5&&d_y>=27&&d_y<=28) { kill_bot(b_id); collision = true; } //4 // 33
if(b_d==1&&d_x>=-12&&d_x<=-11&&d_y>=21&&d_y<=22) { kill_bot(b_id); collision = true; } //-14 // 21
if(b_d==2&&d_x>=4&&d_x<=5&&d_y>=-9&&d_y<=-8) { kill_bot(b_id); collision = true; } //4 // -9
if(b_d==3&&d_x>=22&&d_x<=23&&d_y>=20&&d_y<=21) { kill_bot(b_id); collision = true; } //22 // 21
});
}
if(!collision&&c_bot[8]>GRID_MOVE) {
$(this).collision(".spawn,#level").each(function(){
var s_id = $(this).attr("id").substr(1);
var piece = pieces[s_id];
var s_x = piece[1];
var s_y = piece[2];
d_x = b_x-s_x;
d_y = b_y-s_y;
if(b_d==0&&d_x>=4&&d_x<=5&&d_y>=19&&d_y<=20) { kill_bot(b_id); collision = true; } //4 // 33
if(b_d==1&&d_x>=-14&&d_x<=-13&&d_y>=11&&d_y<=12) { kill_bot(b_id); collision = true; } //-14 // 21
if(b_d==2&&d_x>=4&&d_x<=5&&d_y>=-11&&d_y<=-10) { kill_bot(b_id); collision = true; } //4 // -9
if(b_d==3&&d_x>=22&&d_x<=23&&d_y>=11&&d_y<=12) { kill_bot(b_id); collision = true; } //22 // 21*/
});
}
if(!collision) {
$(this).collision(".exit,#level").each(function(){
var e_id = $(this).attr("id").substr(1);
var piece = pieces[e_id];
var e_x = piece[1];
var e_y = piece[2];
d_x = b_x-e_x;
d_y = b_y-e_y;
if(d_x>=4&&d_x<=5&&d_y>=1&&d_y<=2) {
current_bots++;
bots[b_id] = false;
$("#current_bots").html(current_bots);
$("#b" + b_id).setAnimation(exit[2], function(node){$(node).fadeOut(200)});
}
});
}
if(!collision) {
$(this).collision(".bot,#level").each(function(){
var bd_id = $(this).attr("id").substr(1);
if(bd_id!=b_id) {
var piece = bots[bd_id];
var bd_x = piece[2];
var bd_y = piece[3];
d_x = b_x-bd_x;
d_y = b_y-bd_y;
if(d_x>=0&&d_x<=2&&d_y>=0&&d_y<=2) { kill_bot(b_id); kill_bot(bd_id); collision = true; }
}
});
}
});
}
}, REFRESH_RATE);
非常感謝,
有很多方法可以改善您的代碼。
您幾乎只使用O(n 2 )算法進行碰撞檢測。 您正在針對每個對象測試每個機器人。 例如,如果您有20個機器人和30個障礙,則計算機必須測試(19+18+...+1) + (20*30) = 190+600 = 790
碰撞。
減少必要的碰撞測試數量的一種簡單方法是將磁場分成較小的部分。 一種簡單的方法是使用排序列表。 我假設您的對象具有矩形邊界。 只需創建左邊緣的排序列表即可。
sorted_left_border = [40, 51, 234, 240];
這是使用的偽代碼:
for bot in all_bots:
left = bot.x, right = bot.x + bot.width
top = bot.y, bottom = bot.y + bot.height
// binary search is O(log n)
colliding_objects = binary_search for range in sorted_left_border
for obj in colliding_objects:
// check the other 3 borders
有使用所有4個邊界的方法,但是它們要復雜得多。
如果輸入幾乎被排序,則有一些排序算法可以在O(n)時間附近進行排序,但是我只使用Javascript內置的排序功能。 (如果太慢,您可以稍后編寫自己的。)
嘗試脫機更新DOM,然后再將其重新插入瀏覽器HTML。 現在的操作方式是,每次更改內容時,瀏覽器都必須更新DOM。 瀏覽器每幀更新DOM的時間不得超過1次。
為了從DOM中提取元素,jQuery中提供了detach方法。 確保使用僅與分離元素匹配的jQuery選擇器:
// remove from DOM, avoid updating it.
var theGame = $("#theGame").detach();
// select all bots and do the updating
var bots = $(".bot", theGame);
// reinsert
theGame.appendTo("body");
將jQuery與DOM元素一起使用是錯誤的技術。 DOM不是為此而構建的。 如果您僅針對現代瀏覽器進行編程,請考慮使用<canvas>
元素 。
我認為格奧爾格(Georg)所描述的就是這樣 。 它是一個Java applet,因此它比javascript更快,但它說明了原理。 您會注意到,僅在對象與網格中相鄰的8個正方形中的對象之間計算距離。 如果在這8個正方形中沒有其他對象,則根本不會檢查該氣泡是否存在碰撞。
該技術建立在哈希表的基礎上,在哈希表中實現起來應該不難,因為每個js對象都是哈希表!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.