1
\$\begingroup\$

This is the bullet I create when a player clicks to attack

var angInRadians = Math.atan2(data.y - playerArr[i].y, data.x - playerArr[i].x);//data.y & data.x is mouseY and mouseX
var temp = angInRadians * (180/Math.PI);
        function newBullet() {
          this.attack = temp;
          this.playerX = playerArr[i].x;
          this.playerY = playerArr[i].y;
          this.speed = 10;
          this.traveled = 0;
        }

Then in my game loop I do this

for(var j = 0;j<playerArr[i].bullets.length;j++)
    {
      playerArr[i].bullets[j].traveled += playerArr[i].bullets[j].speed;
    }

Then to draw the bullet I am doing this

ctx.translate(playerArr[i].bullets[j].playerX, playerArr[i].bullets[j].playerY);
        ctx.rotate(playerArr[i].bullets[j].attack * (Math.PI/180));
        ctx.fillStyle = 'black';
        ctx.fillRect(playerArr[i].bullets[j].traveled, 0, 4, 1);

Then for the players I just have a usual player X and Y and I can't figure out how to check if the bullet is within the area of the player, if you need any more code just ask/If you want to see how the game is working here.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

To check if the bullet is currently inside a player, you can test the distance between the player and the bullet. If they are closer together than the radius of the player circle, then the bullet is inside the player.

for each player
    for each bullet
        for each OTHER player
            if (distance between bullet and player < radius of player)
                // score a hit
                // destroy the bullet or note that it shouldn't damage this player again

I do not recommend that method, though. The bullet travels some distance, let's call that A, each update. If A is larger than the width of the target player at the point where the bullet's path crosses it, then the bullet could "tunnel" through the player between frames. Since a bullet could just clip a little sliver at the edge of a player, this is possible even with fairly slow-moving bullets and players.

Instead, I would check if the bullet's path has intersected the player object during the last frame. It's more complicated, but it is a fairly optimal process that shouldn't be noticeably slower than the less accurate method.

// for each player
    // for each bullet
        // set up some variables

        var x0 = bullet.playerX;
        var y0 = bullet.playerY;
        var radians = bullet.attack * Math.PI / 180;
        var dX = bullet.traveled * Math.Cos(radians);
        var dY = bullet.traveled * Math.Sin(radians);
        var sShotSqr = bullet.traveled * bullet.traveled;

        // you'll need to track the last bullet position, or integrate this code
        // into the bullet update code so you can use both the previous and
        // current 'traveled' values.

        var tMin = bullet.traveledPrev / bullet.traveled;

        // for each OTHER player
            var dXTarget = playerArr[k].x - x0;
            var dYTarget = playerArr[k].y - y0;
            var t = (dXTarget * dX + dYTarget * dY) / sShotSqr;
            // check for the bullet moving away from the player
            if (t < 0)
                continue;

            var radius = playerArr[k].radius;
            var deltaTMax = radius / bullet.traveled;
            // check coarsely for the player and bullet not crossing paths this frame
            if (t + deltaTMax < tMin || t - deltaTMax > 1)
                continue;

            var xSpoke = x0 + dX * t;
            var ySpoke = y0 + dY * t;
            var offsetSqr = radius * radius - xSpoke * xSpoke - ySpoke * ySpoke;
            // check for the bullet's path not touching the player
            if (offsetSqr < 0)
                continue;

            var deltaT = sqrt(offsetSqr / sShotSqr);
            // check for the bullet not yet reaching the player or the player
            // moving across the path after the bullet has passed
            if (t + deltaT < tMin || t - deltaT > 1)
                continue;

            // score a hit

Caveat: I wrote this up here on the site, so it probably contains syntax errors. There may be transcription errors also - x instead of y or something like that.

The process is pretty straightforward, though it's a bunch of code. It calculates the little segment of the player's circle that crosses the bullet's path, then checks whether the bullet has touched that segment during the time since the previous update.

\$\endgroup\$
5
  • \$\begingroup\$ I appreciate the long answer but I just can't get this to work. This is how I've tried to do it pastebin. I set bullettraveledPrev to traveled -10 because that's what the previous value would of been (sorry if I misunderstood) \$\endgroup\$
    – JohnT
    Commented May 1, 2017 at 17:45
  • \$\begingroup\$ You need to put parentheses around the playerArr[i].bullets[j].traveled-10. Right now, the math is "divide 10 by traveled, then subtract that from traveled". It needs to be "subtract 10 from traveled, then divide the result by traveled". \$\endgroup\$
    – Victor T.
    Commented May 1, 2017 at 17:57
  • \$\begingroup\$ I've added the parenthesis and still can't get it to work, anything else you can suggest? \$\endgroup\$
    – JohnT
    Commented May 1, 2017 at 18:18
  • \$\begingroup\$ Try printing out some other reports to the console log, between the different places where continue is used. If you can find out which of those tests is causing the collision to fail, it will be easier to figure out what's wrong. If you want to pastebin your code and let me know where the loop continuing, I'll be happy to take another look. \$\endgroup\$
    – Victor T.
    Commented May 1, 2017 at 19:17
  • \$\begingroup\$ I managed to get the basic solution working \$\endgroup\$
    – JohnT
    Commented May 3, 2017 at 18:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .