简体   繁体   中英

How to make an object point at mouse

I have a simple sword image (drawn pointing up) that is in an 'open world' game setting, so the player can move around the world to all coordinates. I would like the sword to point at the mouse.

My issue (I think) is that the world coordinates and webpage coordinates do not match up. For example, the player could be at location (6000, 6000), while the mouse coordinates would only be between 0 and 1600 (or whatever the width of the screen is). On top of that, the webpage won't always exist in the same place.

Thoughts so far:

So I need to calculate the position of the mouse relative to the canvas, or vice versa.

Formula I was using. This worked in an older project of mine for XNA:

var xdir = mouse.x - swordcenter.x;
var ydir = mouse.y - swordcenter.y;

var theta = (Math.atan2( ydir, xdir ) - Math.PI/2.0) * (180.0/Math.PI);

I feel like the solution should be simpler than what I'm thinking, but no formula has been working so far. Any ideas?

So the question I suppose is why isn't this working? And my best guess is because of the difference in coordinates. I can't figure out how to factor it in.

Edit: I have figured out how to factor it in. With the following code, the mouse position is put in to game coordinates. So if the mouse hovers over the player, then the mouse pos and player pos are equal. However, the image still spins rapidly with the mouse movement.

document.addEventListener('mousemove', function(e){ 

    mouse.x = e.clientX || e.pageX; 
    mouse.y = e.clientY || e.pageY; 

    var view = document.getElementById('viewport');
    var rect = view.getBoundingClientRect();

    mouse.x -=  rect.left;
    mouse.y -=  rect.top;

    var camX = clamp(x - canvas.width/2, -1000, 1000 - canvas.width);
    var camY = clamp(y - canvas.height/2, -1000, 1000 - canvas.height);

    mouse.x += camX;
    mouse.y += camY;

}, false);

Edit 2: Here is how I get the angle:

var getAngle = function() {

    var xdir = mouse.x - x;//where x and y are the sword center
    var ydir = mouse.y - y;

    var theta = Math.atan2( ydir, xdir  ) * (180.0/Math.PI);     

    return theta;
}

Edit 3: Here is how I draw the image:

var draw = function(ctx) {

    ctx.fillRect(x-15, y-15, 30, 30);//background player rect

    ctx.save();
    ctx.translate(x, y);//x and y is the center of the sword/player     
    ctx.rotate(getAngle());     

    //this correctly draws the sword on top of the player rect, except for rotation
    ctx.drawImage(stanceTexture, -stanceTexture.width/2, -stanceTexture.height/2);

    ctx.restore();
};

You don't need trigonometry for that. Basic vector calculus is enough:

const sword_length = 10;

var sword_x_start = 0; 
var sword_y_start = 0;

var mouse_x = ...;  // current mouse position
var mouse_y = ...;

var dx = (mouse_x - sword_x_start); 
var dy = (mouse_y - sword_y_start);

// sword to mouse distance 
var length = Math.sqrt( dx*dx + dy*dy );

// unit vector, see: http://en.wikipedia.org/wiki/Unit_vector 
// in sword to mouse direction: 
var unit_v_x = dx / length;
var unit_v_y = dy / length;

// and now coordinates of the sword pointing to mouse:
var sword_x_end = sword_x_start + unit_v_x * sword_length ;
var sword_y_end = sword_y_start + unit_v_y * sword_length ;

After all the additional math done to compute the correct "in-game" mouse location, it turns out that my canvas context wanted radians as well. Much confuse. Every other post I found regarding this turns the value back into degrees ( WRONG ) so I hope this helps someone else out. So here is the complete answer,

document.addEventListener('mousemove', function(e){ 

    mouse.x = e.clientX || e.pageX; 
    mouse.y = e.clientY || e.pageY; 

    var view = document.getElementById('viewport');
    var rect = view.getBoundingClientRect();

    mouse.x -=  rect.left;
    mouse.y -=  rect.top;

    var camX = clamp(x - canvas.width/2, world.minX, world.maxX - canvas.width);
    var camY = clamp(y - canvas.height/2, world.minY, world.maxX - canvas.height);

    mouse.x += camX;
    mouse.y += camY;

}, false);


var getAngle = function() {

    var xdir = mouse.x - x;//where x and y are the sword center
    var ydir = mouse.y - y;

    //Note: I only subtract Math.PI/2 to flip the image 180 degrees.
    //      The value to subtract will depend on the original angle of your image
    var theta = Math.atan2( ydir, xdir  ) - Math.PI/2.0;     

    return theta;
}

var draw = function(ctx) {

    ctx.fillRect(x-15, y-15, 30, 30);//background player rect

    ctx.save();
    ctx.translate(x, y);//x and y is the center of the sword/player     
    ctx.rotate(getAngle());     

    //this correctly draws the sword on top of the player rect, except for rotation
    ctx.drawImage(stanceTexture, -stanceTexture.width/2, -stanceTexture.height/2);

    ctx.restore();
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM