Quillraven / MysticWoods

A small RPG example for a YouTube tutorial series using Kotlin, LibGDX, LibKTX and GDX-AI.
https://quillraven.github.io/MysticWoods/
45 stars 4 forks source link

BUG: Increased movement speed when running diagonally #2

Closed blaxphoenix closed 1 year ago

blaxphoenix commented 1 year ago

The player (and I think all entities that have a MoveComponent) goes faster when going diagonally because the force is bigger.

Let's say the player's speed is 1 m/s, if the player presses both UP and RIGHT, the player will go diagonally, but with an increased speed, and more precisely with 1.41m/s, vector total force (sin = 1, cos = 1, total force = sqrt(1^2+1^2) ).

To fix this I modified the MovementSystem, when we set the impulse I also normalize the vector components, to have a maximum of allowed speed:

val force = sqrt(moveCmp.sin.pow(2) + moveCmp.cos.pow(2))
val normal = 1 / force
phCmp.impulse.set(
    mass * (moveCmp.speed * slowFactor * moveCmp.cos * normal - velX),
    mass * (moveCmp.speed * slowFactor * moveCmp.sin * normal - velY)
)

Hope this helps 😄

Also if you @Quillraven have a better solution please inform me too. Not sure if my solution is the best, or the most optimal, but it works for me.

Quillraven commented 1 year ago

Interesting find but I wouldn't really call it a bug. Isn't it the same in old RPGs like Secret of Mana or Chronotrigger that you move faster when going diagonal? Because you get the horizontal and vertical movement at the same time.

Nevertheless, I will have a look at this topic in more detail and will come back to you. Maybe your solution is already ideal 😉

Thanks for reporting!

Quillraven commented 1 year ago

I think I found a related article: https://gamedev.stackexchange.com/questions/189967/2d-diagonally-velocity-greater-than-straight-line-velocity-how-to-fix

blaxphoenix commented 1 year ago

Indeed, it may be considered as just a "working as intended", but I just wanted to raise this to your attention. Maybe it helps in the future 😄

Quillraven commented 1 year ago

Reading the article I think our MoveSystem is actually correct but the way we set cos/sin in PlayerInputProcessor is not ideal. Since both cos and sin can be 1, we get the behavior that you described.

Therefore it would be better to either store an angle in which direction we want to move or set cos/sin to the correct values when moving diagonal.

This would be very easy when we use a Joystick from scene2d as movement input since it provides the correct cos/sin values.

But we use the keyboard as input so it is a little trickier.

Anyway, I think your solution is short and fine but as a rule of thumb try to avoid sqrt because it is a slow operation.

I will mention this in the next part of the tutorial series 🙂

Quillraven commented 1 year ago

Okay, I read some more about it and your solution seems to be the way to go but I'd do it slightly different.

1) change MoveComponent and store cos and sin in a Vector2. Maybe call it velocity or direction 2) Update PlayerInputProcessor to set the new vector now instead of cos/sin. Whenever the vector gets updated, call the norm method to normalize it

That should be it and it has the advantage that the slow sqrt operation is only done rarely when a move Input is happening. Also the norm method has a safety to avoid division by zero.

I cannot try it out right now but I think it should solve the problem in an efficient way. What do you think?

blaxphoenix commented 1 year ago

Sounds perfect! I will try to find some time to fix it in my project. Appreciate the help, suggestions, and all your time!

Quillraven commented 1 year ago

this is now fixed in master and fleks-2.0 branch. There were a few other places where minor code adjustments were needed. The AI entity movement was working correctly imo because there I used the angle to calculate cos/sin. So it should've been only a problem with the player, which is fixed by normalizing the cos/sin vector as you pointed out :)