How to rotate sprite via draw method - java

I have not found answer for this question anywhere, so let's go.
What i expect:
I want to render rocket. Rocket is flying from given start point with evaluated angle. I'm evaluating angle like this:
getVelocity().angle() - 90f
My problem is to calibrate rocket position on top of the rocket. Image below shows how should it work:
In the top picture is how libgdx render not rotated texture region. In the bottom picture is what i expect: I want to move and rotate texture region with given angle to have (x,y) coordinate on the top of rocket.
What i have:
I tired to write method to draw sprite how i expect but i failed. I think it is caused due to fact that i don't understand documentation of this method.
Following manual:
void com.badlogic.gdx.graphics.g2d.SpriteBatch.draw(TextureRegion region, float x, float y, float originX, float originY, float width, float height, float scaleX, float scaleY, float rotation)
Draws a rectangle with the bottom left corner at x,y and stretching the region to cover the given width and height. The rectangle is offset by originX, originY relative to the origin. Scale specifies the scaling factor by which the rectangle should be scaled around originX, originY. Rotation specifies the angle of counter clockwise rotation of the rectangle around originX, originY.
My code:
public static void drawRotatedTex(SpriteBatch pmRenderer, TextureRegion pmTex, float pmPosX, float pmPosY, float pmAngle)
{
pmRenderer.begin();
pmRenderer.draw(
pmTex, pmPosX, pmPosY, -pmTex.getRegionWidth()/2, pmTex.getRegionHeight(), pmTex.getRegionWidth(), pmTex.getRegionHeight(), 1f, 1f, pmAngle);
pmRenderer.end();
}
Results:
It is moment of collision. As we can see coordinates are offset in relation to rocket.
I don't ask about full solution. For me will be sufficient if someone explain me (on drawing or something) like this method works.
EDIT
Moderation suggested that this question is duplicate of:
libgdx: Rotate a texture when drawing it with spritebatch
I read this topic, but it is not my solution. I know how to rotate my sprite by i don't have idea why coordinates of rocket are offset in relation to rocket top.
EDIT
Invocation of my drawRotatedTex from rocket class:
#Override
public void render(Renderer pmRenderer, float pmX, float pmY) {
SpriteBatch lvSpritebatch = pmRenderer.getSpriteBatch();
Sprite lvSprite = null;
if(mIsExploding)
{
if((lvSprite = mExplosion.getTexture()) != null)
{
lvSpritebatch.begin();
lvSpritebatch.draw(lvSprite, pmX + lvSprite.getWidth()/2, pmY - lvSprite.getHeight()/2);
lvSpritebatch.end();
}
}
else
{
lvSprite = mAnimation.getTexture();
RendererTools.drawRotatedTex(lvSpritebatch,lvSprite,pmX,pmY,getVelocity().angle() - 90f);
}
}

It is not very clear what you are asking, if it's only about moving the origin you would not need that much text. Anyway, I will take a shot at it.
If you want to accomplish what you have in your picture you setup your sprite like this:
sprite.setOrigin(s.getWidth()/2, s.getHeight()); //Centers sprite on top of image.
If I now rotate it in the draw method it rotates around the top center.
sprite.rotate(5);
sprite.draw(batch);
Despite being rotated around the center top of itself it remains position remains the same. If I would set the origin far away from the image and rotate it then the image would travel very far but the position remains the same. Still if you would move it's position 10 pixels to the right the image (wherever it may be) will be moved to the right.
Hope this helps.

Related

Why is a Pixmap circle off by 1?

I'm trying to draw a circle using Pixmap. To make the problem clearer, I'm filling the entire Pixmap area in white, then drawing the circle in a different color. Here is the code that I feel should work.
I'm setting the width/height of the Pixmap to twice the size of the radius of the circle.
Then I'm drawing a circle in the middle of the Pixmap at (radius, radius).
public static Texture circle(int radius, Color color) {
Pixmap pixmap = new Pixmap(radius * 2, radius * 2, Pixmap.Format.RGBA4444);
pixmap.setColor(Color.WHITE);
pixmap.fill();
pixmap.setColor(color);
pixmap.fillCircle(radius, radius, radius);
Texture texture = new Texture(pixmap);
pixmap.dispose();
}
Unfortunately, the Pixmap cuts off the circle on the right and bottom sides. For example:
If I increase the size of the Pixmap by 1 in both the width and height, then it looks fine:
I can just arbitrarily add an extra pixel but I'd like to understand why this is necessary. Why does setting the radius of the circle to X result in a diameter that is actually X + 1?
To get the result you want, the location of the circle's center would have to fall between two pixels, so that there are a similar number of whole pixels on either side of that location. My guess is that the Pixmap code defines a pixel's location to mean the center of a pixel. So the point (radius, radius) is closer to the right edge than the left, and (radius-1, radius-1) is closer to the left edge than the right. With this definition of location, the center of your circle should be at location (radius-.5, radius-.5).
If you have to put the center of the circle in the middle of a pixel, then it makes sense that you'd use the location (radius, radius) for the circle and that you'd need the width and height of the Pixmap to be (2*radius + 1, 2*radius+1). This way, there are the same number of pixels, radius+.5 pixels, on either side of the center of the circle. You might at that point want to draw a circle of radius radius + .5 if the library will take that.
Because it draws a circle centered on a pixel, not between pixels.
So the actual radius of the circle drawn is one more than passed in, a circle with radius 1 is drawn as (numbers are coordinates in this example):
012
0 X
1XCX
2 X
This technically has a radius of 1.5, but now it's centered on a pixel (C).
I am guessing this is to allow you to place it accurately, as if it actually had a radius of 2, you wouldn't be able to place the center on a pixel.

Drawing rectangle and shape-rendered rectangle at mouse position

I'm trying to draw a bounding box that follows the mouse and is positioned beneath it but the rectangle doesn't move with it, it moves too fast or too slow and not at the right place.
I've tried getting the mouse coordinates and passing them in to a rectangle, then I draw a rectangle at its position so I can see where it is.
mouseRect is a rectangle drawn at the mouse's position:
mouseRect.set((float)Gdx.input.getX(), (float)Gdx.input.getY(), 32, 32);
This is my render method that is meant to draw a rectangle at mouseRect's position:
shapeRenderer.setProjectionMatrix(cam.combined);
shapeRenderer.begin(ShapeType.Filled);
shapeRenderer.setColor(Color.BLUE);
shapeRenderer.rect(mouseRect.x, mouseRect.y, mouseRect.width, mouseRect.height);
shapeRenderer.end();
The box does move when the mouse moves but it's far too fast and it's not positioned under the mouse as should be expected (there's a giant offset and seems to be inverted but when I make it negative it still doesn't work).
I think you should read about coordinate systems. The mouse system is y-down and screen dependent, while (if I remember correctly), the camera is y-up, centered, and uses the viewport size.
I would suggest using a Stage with a listener for mouseMoved or touchDragged events, which have stage coordinates. Add an actor drawing a rectangle to the stage. You could then move the actor accordingly. You wouldn't have to handle coordinate system changes.
It could look like this:
Actor rectangleActor = new RectangleActor();
stage.addActor(rectangleActor);
stage.addListener(new InputListener() {
public boolean mouseMoved(InputEvent event, float x, float y) {
rectangleActor.setPosition(event.getStageX(), event.getStageY());
return false;
}
})
See this answer for how to draw a rectangle in an actor.

How can I rotate Rectangles in Libgdx?

I rotated my sprite 90 degrees and I want to do the same with my rectangle to be able to use them for collision, but the rotate() method is not available on rectangles.
This is what I did:
treeSpr=new Sprite(new Texture(Gdx.files.internal("tree.png")));
treeSpr.setPosition(250,700);
treeSpr.rotate(90f);
//Rectangle
treeRect=new Rectangle(treeSpr.getX(),treeSpr.getHeight(),
treeSpr.getWidth(),treeSpr.getHeight());
The other answer is basically correct; however, I had some issues with the positioning of the polygons using that method. Just some clarification:
LibGDX does not support rotated Rectangles when using the Intersector for collision dectection. If you need rotated rectangles, you should use the Polygon for collision detection instead.
Building a Rectangular Polygon:
polygon = new Polygon(new float[]{0,0,bounds.width,0,bounds.width,bounds.height,0,bounds.height});
Don't forget to set the origin of the Polygon if you are going to rotate it:
polygon.setOrigin(bounds.width/2, bounds.height/2);
Now you can rotate the collision polygon:
polygon.setRotation(degrees);
Also, somewhere in your code, you will likely want to update the position of the collision polygon to match your sprite:
polygon.setPosition(x, y);
We can even draw our polygon on screen (for debug purposes):
drawDebug(ShapeRenderer shapeRenderer) {
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.polygon(polygon.getTransformedVertices());
shapeRenderer.end();
}
Collision Detection:
The overlapConvexPolygons() of the Intersector:
boolean collision = Intersector.overlapConvexPolygons(polygon1, polygon2)
As mentioned in the other answer, this method only works if:
using convex polygons, which the rectangle is
performing polygon to polygon checks, e.g.: you cannot mix rectangles and
polygons
Rotation
You could create a Polygon from the rectangle or from the sprite (supplying the vertices in order for the polygon constructor) and use it's rotate(float degrees) method:
treePoly = new Polygon(new float[] {
treeRect.x, treeRect.y,
treeRect.x, treeRect.y + treeRect.height,
treeRect.x + treeRect.width, treeRect.y + treeRect.height,
treeRect.x + treeRect.width, treeRect.y
});
treePoly.rotate(45f);
Collision Detection
Collision checks then could be done via the Intersector class:
Intersector.overlapConvexPolygons(polygon1, polygon2)
Keep in mind though, this method only works if:
you use convex polygons, which the rectangle is
you do polygon to polygon checks, e.g.: you cannot mix rectangles and polygons
I think something like it can help, I can not test now,
//Rectangle
treeRect=new Rectangle(treeSpr.getX(),
treeSpr.getY(),
treeSpr.getHeight(), //now is change width by height
treeSpr.getWidth()); //now is change height by width
Note: may You need to adjust the origin of the rotation for both
you can use a render ShapeRenderer to see if the result is as expected:
add for test in variable class
private ShapeRenderer sRDebugRectangel = new ShapeRenderer();
add for test in update or draw
sRDebugRectangel.begin(ShapeType.Filled);
sRDebugRectangel.identity();
sRDebugRectangel.rect(yourRectangle.getX(),
yourRectangle.getY(),
yourRectangle.getWidth(),
yourRectangle.getHeight());
sRDebugRectangel.end();
can look at my answer to this question to use a shaperrender otherwise known as:
Libgdx, how can I create a rectangle from coordinates?

libGDX rotate about object

In my 3d application I wish to have an object (a tree, for example), and my camera to look at this object. Then, I want the camera to rotate about the object, in a circle, while looking at the tree the whole time. Imagine walking around a tree, while constantly changing your angle so that you are still looking at it. I know this requires both rotation of my camera, and translation of my camera, but the math is far beyond the level I have been taught in schooling thusfar. Can anyone point me in the right direction?
Here is one way with very simple math. First, you need a constant for the distance the camera is from the center of the tree (the radius of the circle path it travels on). Also, you need some variable to track it's angle around the circle.
static final float CAM_PATH_RADIUS = 5f;
static final float CAM_HEIGHT = 2f;
float camPathAngle = 0;
Now you can change the camPathAngle to anything you want from 0 to 360 degrees. 0 degrees corresponds with the location on the circle that is in the same direction as the world's X-axis from the tree's center.
On each frame, after you've update camPathAngle, you can do this to update the camera position.
void updateTreeCamera(){
Vector3 camPosition = camera.getPosition();
camPosition.set(CAM_PATH_RADIUS, CAM_HEIGHT, 0); //Move camera to default location on circle centered at origin
camPosition.rotate(Vector3.Y, camPathAngle); //Rotate the position to the angle you want. Rotating this vector about the Y axis is like walking along the circle in a counter-clockwise direction.
camPosition.add(treeCenterPosition); //translate the circle from origin to tree center
camera.up.set(Vector3.Y); //Make sure camera is still upright, in case a previous calculation caused it to roll or pitch
camera.lookAt(treeCenterPosition);
camera.update(); //Register the changes to the camera position and direction
}
I did it like that for the sake of commenting it. It's actually shorter than the above if you chain commands:
void updateTreeCamera(){
camera.getPosition().set(CAM_PATH_RADIUS, CAM_HEIGHT, 0)
.rotate(Vector3.Y, camPathAngle).add(treeCenterPosition);
camera.up.set(Vector3.Y);
camera.lookAt(treeCenterPosition);
camera.update();
}

Java Slick2d - How to translate mouse coordinates to world coordinates

I am translating in my main class' render. How do I get the mouse position based on the translation?
public void render(GameContainer gc, Graphics g)
throws SlickException
{
float centerX = 800/2;
float centerY = 600/2;
g.translate(centerX, centerY);
g.translate(-player.playerX, -player.playerY);
gen.render(g);
player.render(g);
}
playerX = 800 /2 - sprite.getWidth();
playerY = 600 /2 - sprite.getHeight();
I update the player position on keydown by .2f * delta
Picture to help with explanation
i92.photobucket.com/albums/l22/occ31191/Untitled-4.png
World coordinates = camera position + mouse position
Camera position is calculated/explained in my answer to this question: Slick2D and JBox2D. How to draw
You're making a tile-based game, where each tile seems to have the same size. For this case, you don't need a generalized unprojection.
Imagine the complete map. The viewport shows only a portion of it; somewhere you need to store the (x,y) offets of the viewport into the complete map. Since the mouse coordinates are relative to the viewport, you need to add this offset to the mouse coordinates. Now, you can easily get the tile coordinates by using modulo operations on the shifted mouse coordinates with the tile's width and height.
Effectively, this is a coordinate transformation of window coordinates to tile coordinates.

Categories