Search code examples
javascripthtmlcanvasgame-physics

Canvas remove Image on collision


I'm trying to remove an image when a collision occurs without success, I have the primary image which is the chopper and a secondary image called powerup. Basically when the two collide it stops the game from running, instead I would like it to delete or remove the powerup image (gemList). I'm getting a Object [object Array] has no method 'delete' in console.

My code:

function animateGems() {
gemCount++;
for(var i=0; i<gemList.length; i++) {
    if(gemList[i].x < 0-gemWidth) {
        gemList.splice(i, 1); //remove gem once its outside of the canvas
    } else {
        gemList[i].x = gemList[i].x - gemV
        ctx.drawImage(gemList[i].image, gemList[i].x, gemList[i].y, gemWidth, gemHeight)

        if(gemCount >= gemInterval) {
            addGem();
            gemCount = 0;
        }
    }
}
}

function gemCollision () {
var collideCount = 0;
 for(var i=0; i<gemList.length;) {
   var thisGem = gemList[i];
   //collision detection if the xposition of the chopper offset by its width 
   // and comparing it against the xposition of the gem then the collision detection
   // check Y values also
   if( (chopperX + chopperWidth ) >= thisGem.x && chopperX <= (thisGem.x + gemWidth ) && 
       (chopperY + chopperHeight) >= thisGem.y && chopperY <= (thisGem.y + gemHeight)) {
           collideCount++;
           gemList.splice(i,1);//removes the current collided gem
         score  += 5;
   } else i++; //close if  
}//close for on gemList
if (collidedCount !=0) collidedCount == gemList[i]-1;

}//close function

Solution

  • you are modifying the list at the same time you are iterating it. You can do it, but you have to do it in a sligthly different way, increasing the index only if the array did not just shrunk. :

    function gemCollision () {
       var collidedCount = 0;
       for(var i=0; i<gemList.length;) {
           var thisGem = gemList[i];
           //collision detection if the xposition of the chopper offset by its width 
           // and comparing it against the xposition of the gem then the collision detection
           // check Y values also
           if( (chopperX + chopperWidth ) >= thisGem.x && chopperX <= (thisGem.x + gemWidth ) && 
               (chopperY + chopperHeight) >= thisGem.y && chopperY <= (thisGem.y + gemHeight)) {
                   collidedCount++;
                   gemList.splice(i,1);
                   score  += 5;
           } else i++; //close if  
       }//close for on gemList
       if (collidedCount > 0) powerUpSound.play();
    }//close function*/
    

    (i assumed remove(i) was just removing the i-th element, but correct this if need be)
    (i corrected also for just one sound to play if several occurs at once. You might want to increase sound level in that case instead of playing several times a sound at the very same time... or not ! )

    Edit : it seems you are doing the same mistake in your animateGems code that you did in your collision code : you are iterating over a list (array) and changing it at the same time.
    For all those kind of pattern : either take care of indexes, either build a separate defferedRemove list that you will use afterwise.

    I changed your code a bit, so a gem is created in a random time (500 to 3500 ms) after one disapeared to avoid the -quite frustating- apparition of a gem as soon as one disapears.

     var wantedGemCount = 20;
    
    function animateGems() {
        // gemCount++; // i commented. gemCount is gemList.length, that's all.
        for(var i=0; i<gemList.length; /*  i++  nope !! */) {
             var thisGem = gemList[i] ;  
             if (thisGem.x < 0-gemWidth) {
               gemList.splice(i, 1); //remove gem once its outside of the canvas
             } else {
               thisGem.x = thisGem.x - gemV
               ctx.drawImage(thisGem.image, thisGem.x, thisGem.y, gemWidth, gemHeight)    
               i++; // here !!
            }         
         }
         // add gems only after the for loop if need be
         // i did not understood the logic, and changed it a bit
         if(gemList.length < wantedGemCount) {
                   addGemLater();
         }
         handleGemCreation();
    }
    
    var gemAddTime = [];
    function addGemLater() {
        gemAddTime.push(Date.now() +  500 + Math.random()*3000);
    }
    
    function handleGemCreation() {
       var now = Date.now();
       for (var i=0; i<gemAddTime?length; ) {
           var thisTime = gemAddTime[i];
           if (thisTime > now) {
              // push a new gem
              gemList.push( ????  );
              // remove add request
              gemAddTime.splice(i,1);
           } else i++;
       }
    }