Rotating Sprite Around A Point Without Messing Its Drawing Point

Started by
11 comments, last by lifesuxtr 4 years, 4 months ago

UPDATE:

I solved my problem guys trick was to use

powerIndicator.setOrigin(powerIndicator.width/2,0f)

THANKS EVERYONE


I am trying to draw and rotate an arrow sprite based on a point,around a static circle body without messing its drawing starting point. Arrow should be directed to the same direction with user touch point,static body center vector.

Let me explain it with an example.

arrowquestion.png

This is how i calculate arrow drawing point:

fun powerIndicatorDownPointCalculator(playerPosition: Vector2,touchPosition: Vector2,distanceBetweenTouchPointAndPlayer:Float):Vector2{
  // player position is static body center,touch position is touch point.

    val playerPositionHolder = playerPosition.cpy()



    val abVector = playerPosition.sub(touchPosition);

    val normalizedAbVector = Vector2(abVector.x/distanceBetweenFingerAndPlayer,abVector.y/distanceBetweenFingerAndPlayer)


    Gdx.app.log("normalized ab vector",normalizedAbVector.toString())

    var pointToAddX  = 90*normalizedAbVector.x
    var pointToAddY  = 90*normalizedAbVector.y


    var newPointX  = playerPositionHolder.x + pointToAddX
    var newPointY = playerPositionHolder.y + pointToAddY
    Gdx.app.log("NEW POINT", Vector2(newPointX,newPointY).toString())

    return Vector2(newPointX,newPointY)

}

Here is a simple video showing it:

MNML-November19-041320-AM.gif

This is how i calculate C point to use later on rotation(?)

  fun calculateAimingPoint(playerPosition: Vector2,touchPosition: Vector2):Vector2{
//playerPosition is staticbody centerval abVector = playerPosition.sub(touchPosition);

        val secondPos = blackBody.position.cpy()
        val cPointPosition  = secondPos.add(abVector)
        return cPointPosition



}

This is what i wrote for rotation but for sure it is wrong since not working as i wanted:

  var angle = atan2(aimingPoint.y - blackBody.position.y, aimingPoint.x - blackBody.position.x ) *180/ PI ;
//aiming point is C point, blackBody is static body
  if (angle > 90)
  {
      angle = 450 - angle;
  }
  else
  {
      angle = 90 - angle;
  }

// powerIndicator.setOrigin(????) // setOrigin is for rotation but i dont now what to write here.

  angle = angle*-1
  powerIndicator.rotation = angle.toFloat()

What i actually wanna achieve is this:

MNML-November19-042729-AM-2.gif

As zakwayda suggested first i am trying to solve rotation problem. I fixed arrows position to central bodies center and trying to rotate to face with aim point.

I have decided to work on rotation first.I fixed position of arrow to center of circular body and i am trying to face arrow towards aiming point.

(shooter is central body)

var xDownPoint = shooter.body.position.x-powerIndicator.width/2  
var yDownPoint = shooter.body.position.y  
powerIndicator.setPosition(xDownPoint,yDownPoint)  
var degrees = (Math.atan2((aimingPoint.x - xDownPoint).toDouble(), -(aimingPoint.y - yDownPoint).toDouble()) * 180.0 / Math.PI - 180.0f).toFloat()     powerIndicator.setOrigin(xDownPoint,yDownPoint) 
powerIndicator.rotation = degrees

This is the result:

https://im4.ezgif.com/tmp/ezgif-4-21ee1394147e.gif

As you see starting position of arrow is messed up but i guess its rotation degree is correct


Advertisement

I couldn't quite follow everything in your post, but I'll just ask this to begin with. In the first video it looks like the orientation of the arrow (which I assume is the power indicator) is fixed, but you posted some code where you seem to be assigning a varying value to it. So I'm wondering why the orientation of the arrow isn't changing. Or is that code not being applied in the video you posted?

In any case, it seems like you have the right idea. I'm assuming 'powerIndicator.rotation' expects degrees and not radians (a degree-radian mismatch would be a possible source of error). Also, what's causing the arrow to move around if you're not setting its origin? (Apologies if the answer is obvious from what you posted.)

I get the impression you want the back end of the arrow to 'stick' to the circle, with the rest of the arrow scaling to indicate distance/power. For that I'd recommend putting the arrow 'hot spot' or pivot point right at the back end. How to set the hot spot depends on what you're using for rendering (some graphics libraries support this directly, while in other cases you may have to do it yourself).

If that doesn't help, maybe you could clarify exactly what code is and isn't being applied in the first video.

@Zakwayda

in first video, rotation code is not applied.It just calculates coordinates of down left corner of arrow(position)according to touch point and redraws it. Origin is not position , its a point to rotate around.

I don't know enough about the API you're using to answer your question specifically (are you using LibGDX?). But, is there any particular reason you're using the back-left corner of the arrow as a reference point? It seems like you'd want to use the back center (that is, the point halfway between the back left and right corners).

@Zakwayda

yes i am using libgdx.no since back left is calculated i can get back center too.

It seems like you'd want to use back-center and not back-left.

I don't think I can provide a detailed answer without digging into the LibGDX API. One thing you could do would be to post another video with the rotation code applied so we can see in what way that's not working.

I do think it's likely that the origin should be set to the back-center, in the local space of the arrow (again though, I can't say for sure without investigating the API). It seems like you probably want scaling to be relative to the back center. I saw a couple things online that suggest the origin applies to both scaling and rotation. Rotating around the back center (or any point along the midline) should work, I think.

One thing that might help you is to tackle each of the subproblems individually. It seems there are at least three elements involved: scaling, rotating, and positioning. Maybe just start with getting rotation working. Just draw the arrow at the 'center' position (where the circle-shaped object is), and see if you can get it to rotate correctly. Once you have that working, you can move on to the other issues.

Hi,

I'm no expert on GDX either. However I might help with the basics.

Let's say you have:
T - touch point
P - the origin, which you call "static body center" on the figure
A - the starting point of the arrow
C - the end point of the arrow where it's pointing to

It seems that you calculate T,P,A correctly, and you only missing C. Let's think out of the box. P is a fixed point, and the angle you have with P, A is the same you need for A, C. Also we can notice that the length of T, P is the same as P, C. Therefore:
1. get the distance of T and P, let's say d
2. multiply the P, A vector by d to get C (I believe your code calls P, A "normalizedAbVector" I think)
3. if d is bigger than the length of P, A vector, draw an arrow between A and C points

For the step 3, I'd suggest to use a vector based arrow with 7 points (1 top which is at C, 4 at head's end and 2 at top, the midpoint of these two is A), calculate those points and simply connect them with a 2D line. but you could use a rotated and scratched bitmap as well. For the latter, you should resize the bitmap's height to length(P, C)-length(P,A), rotate it by the angle of (P, A) and place it at A. I don't know if GDX can manipulate bitmaps like that, but pixman surely can, and it is also very fast.

Cheers,
bzt

Why not do a simple 2d rotation matrix and do it like this

construct a 2d translation matrix using negated vector of rotation origin point-A

construct a 2d rotaion matrix around world space origin-B

construct a 2d translation matrix using not negated vactor of rotation origin point-C

Apply A*B*C*(ball sprite world space vectors) and apply A*B*C (arrow sprite world space vectors)

 

I guess because what you describe, that "simple 2d rotation matrix" is actually 3 matrices, and the number of required calculations are tenfold at least?

You can skip the generate a rotation matrix part altogether, because the OP already has a normal vector pointing in the right direction. It's enough to multiply that with a scalar distance to get C. One translation matrix could be useful, yes, If they want to use a vector-based arrow, but I'm guessing they'd prefer a nicely drawn image arrow. (Correct me if I'm mistaken.)

And for that, the bitmap rotation and scaling, it's better to use a hardware optimized image rotation algorithm (like the one offered by pixman), because it is simpler to use and much faster than any rotation or transformation matrix multiplication on each pixel.
Just for the records, you can also rotate an image by a degree with vanilla GDX functions according to this: https://stackoverflow.com/questions/9445035/rotate-image-clockwise-using-libgdx so this might be even simpler than I first thought.

Cheers,
bzt

8 minutes ago, bzt said:

I guess because what you describe, that "simple 2d rotation matrix" is actually 3 matrices, and the number of required calculations are tenfold at least?

why do you compete a single 3x2 matrix multiplication of a 2d vector with normalization and funcy stuff OP does?

This topic is closed to new replies.

Advertisement