1
\$\begingroup\$

So, now I've got into my second problem of implementing the arrow. The rotation works fine from this link but I have to calculate the angle from a touch point to the middle of the arrow placement.

I've already calculated that angle, well if I'm not mistaken. I used a vertical distance that is just the touch points y coordinate since the center y coordinate is 0. For the x coordinate I subtracted the touch point minus the texture regions x coordinate in draw function.

Then to calculate the angle I used arcus tangent inside divided the vertical length by the horizontal length, then multiplied by 180 / PI to get the angle in degrees.

The thing is that this worked a bit like I wanted, but not exactly. Because when taking the touch points coordinates and bottom center coordinates the invisible triangle that is created will be created as a mirrored triangle on the half side of the screen. Meaning when going over to the other side with a finger the angle was negative. Tried using a the math absolute function but then the arrow bounced back when it reached the angle limit.

Draw function:

    @Override
    public void draw(SpriteBatch spriteBatch) {
        spriteBatch.setProjectionMatrix(EtherSky.camera.combined);
        spriteBatch.begin();
        spriteBatch.draw(textureRegion,
            x - textureRegion.getRegionWidth() / 2, y,
            textureRegion.getRegionWidth() / 2, 0, 
            textureRegion.getRegionWidth(), 
            textureRegion.getRegionHeight(), 
            1.0f, 1.0f, degrees);
        spriteBatch.end();
     }

Input function:

    @Override
    public void input() {

    /*
    if (Gdx.input.getAccelerometerX() > 3 && degrees < 90) {
        degrees++;
    }
    else if (Gdx.input.getAccelerometerX() < -3 && degrees > -90) {
        degrees--;
    }*/

    // Distance from arrow bottom center point to touch point
    float distance = (float)Math.sqrt(
                      Math.pow((inputManager.touchPoint.x - (x - textureRegion.getRegionWidth() / 2)), 2) +
                      Math.pow((inputManager.touchPoint.y - 0), 2));

    float verticalDistance = inputManager.touchPoint.y;
    float horizontalDistance = inputManager.touchPoint.x - (x - textureRegion.getRegionWidth() / 2);
    float angle = (float)Math.abs(Math.atan(verticalDistance / horizontalDistance) * 180 / Math.PI);

    if (Gdx.input.isTouched()) {
        degrees = angle;
    }
    System.out.println("Player (" + Gdx.input.getX() + ", " + Gdx.input.getY() + ")");
    System.out.println("Degrees: " + degrees + " Angle: " + angle);
    }

The black dots on the image represents touch points and this is what the invisible triangles would look like if I'm not imagining wrongly. Example image: enter image description here

UPDATED CODE

    float verticalDistance = inputManager.touchPoint.y;
    float horizontalDistance = inputManager.touchPoint.x - x; // (x - textureRegion.getRegionWidth() / 2)
    float angle = (float)Math.toDegrees(Math.atan2(verticalDistance, horizontalDistance)) - 90;

    if (Gdx.input.isTouched()) {
            degrees = angle;

            if (degrees < 90)
                degrees = 89;
    }

I tried to do this but it doesn't work because then I get the arrow stuck at 89 degrees forever. Notice that this is not the arrow pointing straight up, it's the arrow pointing to the left.

I am aware why the code doesn't work but I don't know how to get it to work.

UPDATED CODE FOR FUTURE READERS (ANSWER)

private void inputFollowFinger() {
        float verticalDistance = inputManager.touchPoint.y;
        float horizontalDistance = inputManager.touchPoint.x - x;
        float angle = (float)Math.toDegrees(Math.atan2(verticalDistance, horizontalDistance)) - 90;

        if (Gdx.input.isTouched()) {
            degrees = angle;
            arrowStayAt90Degrees();
        }
    }

private void arrowStayAt90Degrees() {
    final int stayAtDeg = 90;
    final int adjustDeg = 180;
    if (degrees < -adjustDeg) {
        degrees = stayAtDeg;
    }
    else if (degrees < -stayAtDeg) {
        degrees = -stayAtDeg;
    }
}
\$\endgroup\$
  • \$\begingroup\$ I've already realized that but the arrow either: 1. Moves like a limit was not set or 2. Sets the limit forever and I can't move the arrow anymore I don't see what I'm missing \$\endgroup\$ – kevvex Jul 17 '18 at 2:03
  • \$\begingroup\$ Sorry for the late response. As the bottom half of the circle in my answer only contain negative values, and also taking into consideration the -90, the test should be: if(degrees < -180) { degrees = 90; } else if(degrees < -90) { degrees = -90; } \$\endgroup\$ – ibrahim mahrir Jul 17 '18 at 23:37
0
\$\begingroup\$

I had the same problem once. Here is how I approach it.

figure

The left side shows how angles are represented in Java (or at least how I see them represented). The Math.* functions work like that and give results like that.

With that being said we just calculate the angle this way:

angle = atan2(dy, dx)

Where dy is the vertical distance and dx is the horizontal one. Using atan2 is better, so that you won't get an error when dx is 0.

Now, we have to take into account that the arrow in its neutral state is already rotated by 90° as shown on the right side from the image above. So the actual angle should be (substracting 90°):

angle = atan2(dy, dx) - 90

Java code:

public void input() {
    float dy = inputManager.touchPoint.y;
    float dx = inputManager.touchPoint.x - x;

    float angle = (float) Math.toDegrees(Math.atan2(dy, dx)) - 90;

    if (Gdx.input.isTouched()) {
        degrees = angle;
    }
}

Notes:

  • The horizontal distance dx should be inputManager.touchPoint.x - x. We dont care about the origin here, it is only needed in the rendering process.
  • It's better to cache the values textureRegion.getRegionWidth() and textureRegion.getRegionHeight() as properties width and height, respectively. That will make the code much concise (thus readable) and reduce the overhead caused by ..
\$\endgroup\$
  • \$\begingroup\$ Thanks again, but how did you solve so that the arrow stays laying down at 90 degrees (180 degrees in your image). Sure, it's not that big of a deal since the user can't put a finger beneath the screen, but my arrow doesn't stop at 90. It points downwards a little bit. I have done an if statement checking the angle from 90 to -90, but when I reach that limit the arrow doesn't come back up again, of course. So that's the part I wonder about. \$\endgroup\$ – kevvex Jul 17 '18 at 1:24
  • \$\begingroup\$ @kevvex I'm not sure I understand your comment. Can you explain it more? \$\endgroup\$ – ibrahim mahrir Jul 17 '18 at 1:28
  • \$\begingroup\$ I wrote an if statement so that the arrow would stop at 90 degrees pointing straight to the right and -90 pointing straight to the left, but to do so I have to set an interval from 90 to -90 and then I set the degrees/angle to 90. And that is why the arrow gets stuck there. I post the code in updated version. For some reason the arrow points downwards a little. \$\endgroup\$ – kevvex Jul 17 '18 at 1:38
  • \$\begingroup\$ @kevvex Can you post that code (add it to the question)? \$\endgroup\$ – ibrahim mahrir Jul 17 '18 at 1:41
  • \$\begingroup\$ It have already been posted. \$\endgroup\$ – kevvex Jul 17 '18 at 1:48

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.