1
votes

I'm currently working on creating 2d vector based movement in a game and I need some help figuring out my math. On each tick, I'm creating a base direction vector based on the x and y axis on a joystick. The values of the axis are pretty normal ranging from -1 to 1. The issue though is with calculating the magnitude. If my normal movement in a direction caps at a magnitude of 1, then when I create this new vector, the magnitude will usually be greater than 1. For a game, this creates an issue because I want walking in every direction to have the same speed.

One of my solutions for this is to just clip the magnitude at 1. This seems simple enough but I feel like I'm taking a shortcut around actually fixing this problem the right way. Am I approaching this wrong and allowing faster movement along a diagonal is actually the correct action? Thanks

1
Why is it a shortcut? Just normalize the vector. - vallentin

1 Answers

1
votes

If you want a constant speed then you should just normalize the vector

double dx = read_x();
double dy = read_y();
double L = sqrt(dx*dx + dy*dy);
dx /= L; dy =/ L;

if however you want a variable speed the problem is indeed that the joystick allows greater speed in diagonal.

Clamping the length to 1 (i.e. just protecting the normalization divisions behind a if (L > 1)) is probably ok, however only experimenting will tell.

Another option would be normalizing on the length of the direction by scaling the length with the extended length so that when the joystick in in a limit position then input will be of unitary length, but scaling from 0 to that value along the direction instead of just clamping:

enter image description here

In code:

double dx = read_x();
double dy = read_y();
double L = sqrt(dx*dx + dy*dy);

if (L > 0) {
    double angle = atan2(dy, dx);
    double kx = fabs(cos(angle));
    double ky = fabs(sin(angle));
    double k = std::max(kx, ky);
    kx /= k; ky /= k;
    double ext = sqrt(kx*kx + ky*ky);
    dx /= ext; dy /= ext;
}

You can see these formulas in action here.

Really only testing with your game can give the answer, but from a gut feeling I'd say that just clamping works better.