# Q：优化循环2阵列的JavaScript帆布游戏

I'm working on my first javascript canvas game, and I wonder is there a better way for comparing collisons between objects in 2 arrays. For example i have an array with rockets, and array with enemies, the code is working, but i think when arrays length becomes much larger it will have effect on the performance. Example 100 rockets through 100 enemies is 10000 iterations per frame

``````for (i in rockets){
rockets[i].x+=projectile_speed;
for (j in enemies){
if(collision(rockets[i], enemies[j])){
enemies[j].health-=5;
sound_hit[hit_counter-1].play();
hit_counter--;
if (hit_counter==0){
hit_counter=5;
}
rockets.splice(i,1);
if (enemies[j].health <= 0) {
score += enemies[j].score;
sound_explode[Math.floor(Math.random()*25)].play();
}
} else if(rockets[i].x >= width){
rockets.splice(i,1);
}
}
}
``````

``````for (i in rockets){
rockets[i].x+=projectile_speed;
for (j in enemies){
if(collision(rockets[i], enemies[j])){
enemies[j].health-=5;
sound_hit[hit_counter-1].play();
hit_counter--;
if (hit_counter==0){
hit_counter=5;
}
rockets.splice(i,1);
if (enemies[j].health <= 0) {
score += enemies[j].score;
sound_explode[Math.floor(Math.random()*25)].play();
}
} else if(rockets[i].x >= width){
rockets.splice(i,1);
}
}
}
``````

If you want to test every rocket on every player its not really possible to do differently, without knowing more about position of players and rockets.

If you keep the collision function fast, this should though be no problem at all.

I can only think of two easy improvements on this:

• when a collision is found use `continue` since looping over the rest of players should not be necessary (unless players is allowed to collide)
• instead of splice'ing the rockets array multiple times, build a new one, excluding all "dead" rockets.

You should also consider using forEach, map and filter to make the code a bit easier to read:

``````rockets = rockets.filter(function(rocket) {
rocket.x+=projectile_speed;
if(rocket.x >= width) {
return false;
}
var enemy = enemies.find(function(enemy) { return collision(rocket, enemy) });
if(enemy) {
enemy.health-=5;
sound_hit[--hit_counter].play();
if (hit_counter==0){
hit_counter=5;
}
if (enemy.health <= 0) {
score += enemy.score;
sound_explode[Math.floor(Math.random()*25)].play();
}
return false;
}
return true;
});
``````

• when a collision is found use `continue` since looping over the rest of players should not be necessary (unless players is allowed to collide)
• instead of splice'ing the rockets array multiple times, build a new one, excluding all "dead" rockets.

``````rockets = rockets.filter(function(rocket) {
rocket.x+=projectile_speed;
if(rocket.x >= width) {
return false;
}
var enemy = enemies.find(function(enemy) { return collision(rocket, enemy) });
if(enemy) {
enemy.health-=5;
sound_hit[--hit_counter].play();
if (hit_counter==0){
hit_counter=5;
}
if (enemy.health <= 0) {
score += enemy.score;
sound_explode[Math.floor(Math.random()*25)].play();
}
return false;
}
return true;
});
``````

What you could try to do is to reduce the number of tests by grouping the enemies and rockets, so that you only have to test the elements in the same group.

Here is a simple implementation to show what I mean, this only partitions in X-direction, because your rockets only seem to travel horizontally:

``````var groupWidth = 100; // do some experiments to find a suitable value
var rocketGroups = [];
var enemyGroups = [];

// initalize groups, not shown (array of array of rocket/enemy),
// but here are some other function examples...

groups[element.x / groupWidth].push(element);
}

function move(element, groups, distance) {
if (element.x / groupWidth != (element.x + distance) / groupWidth) {
// remove element from the old group and put it in the new one
}
element.x += distance;
}

// Note: this is only to show the idea, see comments about length
function checkCollisions() {
var i,j,k;
for (i = 0; i < rocketGroups.length; i++) {
for (j = 0; j < rocketGroups[i].length; j++) {
for (k = 0; k < enemyGroups[i].length; k++) {
// only compares elements in the same group
checkPossibleCollision(rocketGroups[i], enemyGroups[i], j, k);
}
}
}
}
``````

``````var groupWidth = 100; // do some experiments to find a suitable value
var rocketGroups = [];
var enemyGroups = [];

// initalize groups, not shown (array of array of rocket/enemy),
// but here are some other function examples...

groups[element.x / groupWidth].push(element);
}

function move(element, groups, distance) {
if (element.x / groupWidth != (element.x + distance) / groupWidth) {
// remove element from the old group and put it in the new one
}
element.x += distance;
}

// Note: this is only to show the idea, see comments about length
function checkCollisions() {
var i,j,k;
for (i = 0; i < rocketGroups.length; i++) {
for (j = 0; j < rocketGroups[i].length; j++) {
for (k = 0; k < enemyGroups[i].length; k++) {
// only compares elements in the same group
checkPossibleCollision(rocketGroups[i], enemyGroups[i], j, k);
}
}
}
}
``````
javascript  arrays  canvas