1
\$\begingroup\$

I try to create a 2D game with a big map and multiple objects. The player is always in the middle of the screen and all the other objects is moving around so it feels like a big map.

I want the player to always move after the mouse location. I have modified the mouse location to (0,0) by this:

                var mouseX = 0;
                var mouseY = 0;
                if (e.pageX < window.innerWidth/2) {
                    mouseX = -(window.innerWidth/2-e.pageX);
                }else{
                    mouseX = e.pageX-window.innerWidth/2;
                }
                if (e.pageY < window.innerHeight/2) {
                    mouseY = -(window.innerHeight/2-e.pageY);
                }else{
                    mouseY = e.pageY-window.innerHeight/2;
                }

That is working just fine. When it comes to the moving part i can't relly get it to move with the same "speed". I have made some animations to explain how it is now and how i want it to be.

How it is now: enter image description here

DC is the speed that my player would go and as you can see it is moving the most when its closest to x=0 and y=0, i have done it like this so far:

            var all = mouseX + mouseY;
            clientsID[key]['x'] += mouseX / all * speed;
            clientsID[key]['y'] += mouseY / all * speed;

But as i know it is not working well. Here is a animation to show how i want it to be:

enter image description here

DA would be the speed and it's always 1 because it's radius of the circle. But as i don't know how far the mouse is from the center (mouse is E on the last animation) i have to scale it down somehow.

Does anyone know how to get how much i have to add x and y so the speed always will be the same?

Thank you

EDIT: See the solution under here

\$\endgroup\$
3
\$\begingroup\$

I'm happy you figured it out, and I find it really cool that you managed to do it in your own way. But yours is a specific solution for a specific occurrence of a very general problem.

I would like to explain what exactly happened and why it happened. Just in case others stumble upon this answer, sooner or later, with their own specific occurrence of the same problem.


We're working on a game with a top-down view of the world. The player character is positioned firmly in the centre of the game screen. The player moves around the world at a constant speed. The player's direction of movement is determined from the mouse's position relative to player's own position - or the centre of the game screen. We can think of the mouse position as a vector which points in the direction the player moves in.

Naively, we attempt to direct the player with the mouse by adding the mouse coordinates, multiplied by the player's velocity, to the player's current world position.

player.x += mouse.x * player.velocity;
player.y += mouse.y * player.velocity;

But it doesn't work as expected - the player starts moving very, very fast if we move the mouse too far away from the centre of the game screen. What did we do wrong?

Well, the mouse x and y values can get pretty large. The former has a range of [-screenWidth / 2, screenWidth / 2] and the latter [-screenHeight / 2, screenHeight / 2], providing we move the mouse from one end of the screen to the other in both directions. Multiply any value in those ranges with the player's velocity and you can see how quickly things can go wrong.

Let's limit the mouse x and y values to a [-1, 1] range. This way the player can't exceed his preset velocity when it's multiplied by the mouse position values.

mouse.x /= (screenWidth / 2);
mouse.y /= (screenHeight / 2);

But, again, it doesn't completely work the way we want it to. The player can now moves slower than before, but still doesn't move at a constant velocity. What could be the problem this time?


Let's take a couple of steps back and look at the problem from a different perspective.

The player's position, direction, and velocity have two components: a horizontal component, and a vertical component.

For the player's position to update according to a constant velocity, the sum of the two direction components must equal 1. In other words, the direction vector (again, mouse position relative to game screen centre) must be a unit vector.

Turning any old vector into a unit vector is called normalisation. Normalisation is the process of dividing each vector component by the vector's magnitude (length). The vector's magnitude is the hypotenuse of the triangle formed by each of the vector components, and the 'arrow' connecting them. It is calculated from the Pythagorean theorem.

With that in mind, let's rewrite the code:

var magnitude = Math.sqrt(mouse.x * mouse.x + mouse.y * mouse.y);
var unitX = mouse.x / magnitude;
var unitY = mouse.y / magnitude;
player.x += unitX * player.velocity;
player.y += unitY * player.velocity;

The player should now always move at a constant velocity, no matter how the mouse is positioned!


I recommend checking out the links below for more information. They contain interactive demos, illustrations, and great coverage of the subject matter.

\$\endgroup\$
  • \$\begingroup\$ You're very welcome! \$\endgroup\$ – Domagoj Jul 28 '16 at 13:28
1
\$\begingroup\$

I got the solution, it's simple.

This is my animatin for it:

enter image description here

I saw that it make a square out of the lines and then i could get the diagnol in the square. In that way i could get how much i had to scale the mouse x and y to match where it needed to go.

The code would look this this:

            if (mouseX >= 0 && mouseY >= 0) {
            var diagonal = Math.sqrt((mouseX*mouseX)+(mouseY*mouseY));
            clientsID[key]['x'] += mouseX/diagonal * speed;
            clientsID[key]['y'] += mouseY/diagonal * speed;
        }
        if (mouseX >= 0 && mouseY <= 0) {
            var diagonal = Math.sqrt((mouseX*mouseX)+(-mouseY*-mouseY));
            clientsID[key]['x'] += mouseX/diagonal * speed;
            clientsID[key]['y'] -= -mouseY/diagonal * speed;
        }
        if (mouseX <= 0 && mouseY >= 0) {
            var diagonal = Math.sqrt((-mouseX*-mouseX)+(mouseY*mouseY));
            clientsID[key]['x'] -= -mouseX/diagonal * speed;
            clientsID[key]['y'] += mouseY/diagonal * speed;
        }
        if (mouseX <= 0 && mouseY <= 0) {
            var diagonal = Math.sqrt((-mouseX*-mouseX)+(-mouseY*-mouseY));
            clientsID[key]['x'] -= -mouseX/diagonal * speed;
            clientsID[key]['y'] -= -mouseY/diagonal * speed;
        }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.