Search code examples
javascriptnode.jsmathtrigonometrycalculus

Calculate new circle offset based on angle of rotation?


I have a multiplayer Javascript game where the player is a circle, and is able shoot/"eject" circle bullets in the direction that the player is rotated. My code is working perfectly, except it shoots from the middle of the player. I would like it so that the circles are shot from the top right position of the player, where the gun is located. The issue is that when the players rotation changes, you cannot simply add (1, -1) to the position of the player.

Here is my code:

GameServer.prototype.ejectMass = function(client) {

    for (var i = 0; i < client.cells.length; i++) {
        var cell = client.cells[i]; // the player


        var angle = this.toRad(client.rotation); // rotation of the player

        var d = new Vec2(Math.sin(angle), Math.cos(-angle)).scale(-180);

        var sq = (~~d.sqDist(d));

        d.x = sq > 1 ? d.x / sq : 1;
        d.y = sq > 1 ? d.y / sq : 0;

        // cell.position is the players position
        var pos = new Vec2(
            cell.position.x + d.x * cell._size,
            cell.position.y + d.y * cell._size
        );

        var ejected = 0;

        // Create cell and add it to node list

        ejected = new Entity.EjectedMass(this, null, pos, this.config.ejectSize * cell.ejectSize); // the bullet being shot

        ejected.setBoostDefault(-this.config.ejectVelocity * cell.ejectSpeed, angle);

        ejected.ejectedOwner = cell; // set the person who shot the bullet 

        this.addNode(ejected); // add the bullet into the game

        if (typeof ejected !== 'undefined') {
            setTimeout(this.removeNode.bind(this, ejected), 1000); // remove the ejected bullet after 1 second
        }
    }
};

And here is an illustration of the current way it is working: eject illustration


Solution

  • Assuming that the player (circle) is at its own local origin then the position of the gun is relative to the player's origin. Assuming the coordinate system is that of the canvas with forward along the x axis from left to right, and clockwise 90deg (left of player) is the Y axis going down.

    enter image description here Image: C is local circle origin (0,0) with Forward along the red arrow from C, Gx and Gy are the local coordinates of the gun from the circle center C. Top left shows the canvas coordinate (world) system origin. In code below, The player position is relative to that world origin. The final gunPos is also give relative to the world coordinates. B vec is the bullets bullet.delta vector

    const bulletSpeed = 10;
    var gunPos = {x : 10, Y : 10} // ten units forward ten units left of circle center
    var player = {rotation : ?, x : ?, y : ?} // unknown player position and rotation
    
    
    
    // get the unit vector of the rotated x axis. Along player forward
    var xAx = Math.cos(player.rotation);
    var xAy = Math.sin(player.rotation);
    
    // transform the gunpos to absolute position (world coordinates) of rotated player 
    var rotatedGunPos = {};
    rotatedGunPos.x = gunPos.x * xAx - gunPos.y * xAy + player.x;
    rotatedGunPos.y = gunPos.x * xAy + gunPos.y * xAx + player.y;
    
    // and fire the bullet from 
    var bullet = {}
    bullet.x = rotatedGunPos.x;
    bullet.y = rotatedGunPos.y;
    
    // bullet vector is
    bullet.deltaX = xAx * BULLET_SPEED;
    bullet.deltaY = xAy * BULLET_SPEED;