Search code examples
javascripthtmlcanvasjavascript-objects

Array.forEach Updating each Item in Array on click


When the program runs the mouse is clicked creating a projectile from the center of the screen moving with every frame in the direction it was fired (mouse position on click).

When N+1 projectiles have fired all projectiles on-screen move to the new clicked location instead of continuing their path.

I am can not figure out why the current projectiles change direction when the New projectile's velocity should have no effect on prior projectiles.

index.html

<canvas></canvas>
<script src="./guns.js"></script>
<script src="./indexh.js"></script>
<script src="./runh.js"></script>

runh.html

const projectilesArray = [];
let frameCount = 0;

function animate() {
    animationID = requestAnimationFrame(animate);
    c.fillStyle = "rgba(0, 0, 0, 1)";
    c.fillRect(0, 0, canvas.width, canvas.height);

    projectilesArray.forEach((Projectile, pIndex) => {
        Projectile.update();
        console.log(Projectile)
  
        if (
          Projectile.x + Projectile.radius < 0 ||
          Projectile.x - Projectile.radius > canvas.width ||
          Projectile.y + Projectile.radius < 0 ||
          Projectile.y - Projectile.radius > canvas.height
        ) {
          setTimeout(() => {
            projectilesArray.splice(pIndex, 1);
          }, 0);
        }
      });
    
    frameCount++;
    if (frameCount > 150) {
        
    }
}
var fire = 1;
let fireRate = 1;
const mouse = {
    x: 0,
    y: 0,
    click: true,
  };

canvas.addEventListener('mousedown', (event) => {

    if (fire % fireRate == 0) {
      if (mouse.click == true) {
        mouse.x = event.x;
        mouse.y = event.y;

        const angle = Math.atan2(mouse.y - (canvas.height / 2), mouse.x - (canvas.width / 2));
        const fireY = Math.sin(angle);
        const fireX = Math.cos(angle);
        //score -= 0;
        //scoreL.innerHTML = score;
        var weapon = new Projectile(cannon);
        weapon.velocity.x = fireX * 9;
        weapon.velocity.y = fireY * 9;
       
        projectilesArray.push(weapon);
     

        //var gun = object.constructor()
      }
    }
  });

  animate();

indexh.js

const canvas = document.querySelector("canvas");
const c = canvas.getContext("2d");

canvas.width = innerWidth;
canvas.height = innerHeight;



class Projectile {
    constructor(config) {
        this.color = config.color || "rgb(60, 179, 113)";
        this.radius = config.radius || 1;
        this.speed = config.speed || 5;
        this.rounds = config.rounds || 2;
        this.x = config.x || canvas.width / 2;
        this.y = config.y || canvas.height /2;
        this.velocity = config.velocity;
    }
    draw() {
        c.beginPath();
        c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
        c.fillStyle = this.color;
        c.fill();
    }
    update() {
        this.draw();
        this.x = this.x + this.velocity.x * this.speed;
        this.y = this.y + this.velocity.y * this.speed;
    }
}

gums.js

let pistol = {
    color : "rgb(255, 0, 0)",
    radius : 10,
    speed : 1,
    rounds : 1,

    velocity : {
        x: 1,
        y: 1
    }
}

let cannon = {
    color : "rgb(0, 0, 255)",
    radius : 30,
    speed : .5,
    rounds : 1,

    velocity : {
        x: 1,
        y: 1
    }
}

Thanks


Solution

  • The issue is that you have this cannon object used as a configuration object:

    let cannon = {
        color : "rgb(0, 0, 255)",
        radius : 30,
        speed : .5,
        rounds : 1,
    
        velocity : {
            x: 1,
            y: 1
        }
    }
    

    And in your Projectile constructor you assign this.velocity = config.velocity; You are assigning this.velocity to be the same object instance for all Projectiles. To fix it, try copying the object, like:

    this.velocity = {...config.velocity};
    

    That will make a copy of the object rather than sharing the same object instance.

    Also note that you have a bug that you didn't ask about in this line:

    projectilesArray.splice(pIndex, 1);
    

    If two timeouts are queued in the same loop, the array will shift when the first timeout fires, and the second timeout will be operating on the wrong index.