1
\$\begingroup\$

I used to play this game on Kongregate called Death vs Monstars.

A tl;dp (too long; didn't play) explanation of the mechanics is that the character you control follows your mouse cursor. Your charcter fires projectiles endlessly in the direction opposite of that in which you just moved (basically out of your back). This game offers a fairly smooth experience in that you can be fairly sure that the projectiles will fire in the opposite direction that you move your mouse in.

I recently tried to recreate this idea in Godot 3.0.6 Mono. It's not the same game, but the idea is that the character controlled by your mouse has an object that is always pointing in the opposite direction of the character. The problem I faced is that the capturing the direction in which the player moves every frame is limited to the very discrete grid of pixels which Godot (and presumably most other engines) uses to interpret the cursor position. Essentially I just get the angle of rotation from the old position vector to the new position vector, and rotate the character accordingly before updating the position. The result is that the direction in which the character is facing, and thus the object behind it, is very unpredictable. For example, you may move your mouse at a 60 degree angle, but the character ends up pointing in a 45 degree angle depending on what pixel your cursor ends up in.

Is there a less discrete way to approach this problem? Instead of reading the integer-vector position of the mouse cursor, could one somehow get the velocity of the mouse movement?

Any other methods of doing this are also appreciated. I am not asking this question for Godot specifically, but generally, in case there is a common "right" way to do this.

\$\endgroup\$
  • \$\begingroup\$ Did you look at the source code of the game (open source?) how they do it? \$\endgroup\$ – Trilarion Jun 3 at 11:10
0
\$\begingroup\$

The trick to do it is to have another object for the cross-hair that is different from the character object (a position would suffice but by having an object you can render the cross-hair and debug more easily), and after moving the character you can update the position of the cross-hair keeping it no further than a pre-specified distance from the character.

Here it is in psuedo-code:

// somewhere in the update cycle:
character.UpdatePosition(mousePosition);

if (DistanceBetween(character.position, crosshair.position) > MAX_DISTANCE) {
    crosshair.position = character.position +
                         Normalize(crosshair.position - character.position) * MAX_DISTANCE;
}

shootingDirection = Normalize(crosshair.position - character.position);

Please note that this code is not optimized for performance, normalization is happening multiple times and it can be avoided but I kept it this way for readability.

Another caveat is if the cross-hair and the character ended up in the same position (which is VERY rare occurrence) the direction vector ends up undefined, but tbh I wouldn't worry about it, it's practically impossible.

\$\endgroup\$
0
\$\begingroup\$

Velocity is just a measure of distance over time, so if you want to capture the velocity of the mouse, you would need to capture the amount of time passed as well. In Godot 2, I believe this is delta - I'm not sure what differences there are between 2 and 3:

func getVelocity(delta):
    velocity = mouseMoveDifference / timeSinceLastDeltaCheck

As for your issue with imprecise mouse coordinates, could you give more details? I've never run into that issue personally, and am using

mousePos = get_global_mouse_pos()

In a Godot 2 project that tracks mouse position without any issues. You might want to add some debug logs to confirm it is a problem with your mouse coordinates, and not an issue with your math.

\$\endgroup\$
  • \$\begingroup\$ It's not that the coordinates are imprecise; in fact they are entirely accurate. The problem is that coordinate readings are limited to the resolution of the pixels of my screen, which is very discrete and results in very jittery rotations at 60 fps, usually in the order of 45° or a product thereof. \$\endgroup\$ – JSON Brody May 3 at 14:33
  • \$\begingroup\$ You could just place a check on the rotation call to only rotate when the difference is greater than a set amount of degrees - maybe detect the resolution and adjust accordingly \$\endgroup\$ – Christian Boler May 3 at 14:56
0
\$\begingroup\$

Compute the firing direction as a linear combination of the old firing direction and the new mouse movement direction. Thus you get more smooth (but somewhat time lagging) evolution of the firing direction vector.

I assume you always update at equal time intervals and you have stored the old firing direction (as a 2D direction vector).

Ordinary you would replace the firing direction with the inverse of the mouse movement direction. That can be very erratic.

Instead compute the new firing direction as: f times old firing direction + (1-f) times inverse mouse movement direction with a chosen constant f between 0 and 1. For f close to 1 you get a very smooth, but somewhat lagging behind behavior. Choose the value you like most. It may depend on the time between updates of the firing direction.

\$\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.