How do I rotate a graphics object, without changing it's location? - java

I got the following code:
import java.awt.*;
import javax.swing.*;
public class GraphicPanel extends JPanel {
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setFont(new Font("Arial",Font.BOLD,24));
g2d.drawString("A",300,250);
g2d.rotate(45 * Math.PI/180);
g2d.drawString("B",300,250);
}
}
It should rotate B and put it in the same place A is, but for some reason, B apears at a totally different location.
Pretty sure I understand why that is. It's because the entire coordination system is manipulated when scaling, rotating etc (am I correct?)
Anyway, I'd like to know how to rotate or scale an object, and still have it appear where it was before. For example in a game that keeps updating and displaying itself every 10 milliseconds, where a sprite is being rotated, but still stays where it was 10 millisceonds before.
EDIT: Tried to search Google beforehand, guess the wording for this question is kind of tricky because I found nothing helpful.
Thanks a lot :)

When you call the rotate method on a Graphics2D object, you're rotating the entire canvas by that angle around the origin. So, drawing a shape at (300, 250) after the rotation will draw it at whatever that point maps to if you started at (300, 250) and then rotated it 45 degrees around (0, 0).
You should use the other form of rotate that takes the angle as well as the x- and y-coordinates of the rotation pivot point, and pass your point (300, 250) into it. (Although, if you want to rotate around the center of the character or string, you'll need to adjust that point a bit.)

The rotation is done around the origin, e.g. 0,0 of the coordinate system. If you want to rotate around a different point you need to translate the origin, rotate, and translate back, e.g.:
g2d.translate(300, 250);
g2d.rotate(45 * Math.PI/180);
g2d.translate(-300, -250);
g2d.drawString("B",300,250);
Of course you have to take the size of the object you want to rotate in account. This rotates around the point where drawString would paint, which is the left baseline of the string. Probably you would want to rotate around the center; then you have to measure the object before and add those values to the translation.

Related

Java rotated buffered image gets cut off

Firstly, I am trying to make a simple game in Java. I have a viewport that shows a tile map and I have a tank in the middle that moves by controlling the JScrollBars of the scrollpane in which the viewport resides in. So far everything has been going well, until I needed to rotate an image. Here is a picture of the game: Note: the tank body and tilemap are on seperate panels and do not share the same graphics.
Picture of non rotated tank body:
Essentially, I want to rotate a buffered image around its center (rotating in place) using arrow keys. I already have the code for the keys, and I also have a method to try and rotate the buffered image given a buffered image and angle in degrees (the angle is changed to radians in the method). This method will return a buffered image that is rotated correctly. Here is the code:
public static BufferedImage rotateImage(BufferedImage image, double angle) {
if(angle == 0)
return image;
else {
angle = Math.toRadians(angle);
double x = Math.abs(Math.cos(angle));
double y = Math.abs(Math.sin(angle));
int newWidth = (int) Math.floor(image.getWidth()*x + image.getHeight()*y);
int newHeight = (int) Math.floor(image.getHeight()*x + image.getWidth()*y);
BufferedImage rotated = new BufferedImage(newWidth, newHeight, image.getType());
Graphics2D tool = rotated.createGraphics();
AffineTransform transformer = new AffineTransform();
transformer.rotate(angle, image.getWidth()/2, image.getHeight()/2);
tool.drawImage(image, transformer, null);
tool.dispose();
return rotated;
}
}
However, as the title suggests, the image gets cut off at the top and left sides of the image when rotated as shown:
Picture of rotated tank body:
So I have looked at many different forums but I could not solve my problem. I could add whitespace around the image, but that interferes a lot with collision detection which I plan to do later on. I know that it has to do something with the original display being smaller than the display of the rotated image, and I have tried to translate accordingly in many ways. If I translate with this line of code specifically,
transformer.translate((newWidth - image.getWidth())/2, (newHeight - image.getHeight())/2);
Then the image (tank body) rotates without cutting, but bounces out of place as shown (I drew a rectangle to show where it was):
Picture of rotated tank with translation:
I also have tried negating the translations too but it only avails to funky movements.
So, I really have no clue how to solve this, and I have been spending too much time on this problem. I would really appreciate a helpful answer that directly edits my method if possible.
Answer
So here is the opening idea that I needed to realize to answer this problem.
The method to translate and rotate is meant so that the image is not cut off. However, it won't be around the center as intended as seen in the 3rd picture. But again, the method is not intended to recenter it. The painting code itself needs to account for this shift. I simply added variables to account for this:
xOffset = (newWidth - image.getWidth())/2;
yOffset = (newHeight - image.getHeight())/2
And simply subtracted these from where I was painting the tank's body.
Thanks to #camickr for the solution
When rotating a square sprite around the center point, the target image should be larger than the original image by a factor of the square root of 2 (approx. 1.41). For example, a sprite will not be clipped at a rotation angle of 45 °.
I hope this information helps you to solve your problem.

Rotate text present on JLabel without rotating border

I want to rotate the text present on my JComponent to vertical, JComponent also contains border painted in paintComponent method, I don't want to rotate that border, only text.
I already used graphics2D rotate function, but it rotate component border as well, which fails when my component is rectangle.
Please suggest me any approch to rotate only text.
This is currently my JComponent :
And what I want :
Actually it's not duplicate. I already used below code:
Graphics2D g2 = (Graphics2D) g;
g2.rotate(Math.PI / 4, bi.getWidth() / 2, bi.getHeight() / 2);
but problem is that, it also rotate border, I don't want that.
All the solutions given are not working, it rotate the border as well. I don't want to rotate the border, only text.
This is what I get after rotate with some angle:
Remember that the Graphics object has a lot of state in it. This includes the current transformation. Your current code modifies the state and does not restore it to the original situation.
After drawing your image, you should "undo" the rotation. This can be done either by rotating in the other the direction or by creating a new graphics object (g2.create()) specifically to draw the rotated content. If you do the latter, make sure to dispose() the temporary graphics object you created.

Android translated canvas collision of rectangles

im trying do develop a Zelda like game. So far i am using bitmaps and everything runs smooth. At this point the camera of the hero is fixed, meaning, that he can be anywhere on the screen.
The problem with that is scaling. Supporting every device and keeping every in perfect sized rects doesnt seem to be that easy :D
To prevent that i need a moving camera. Than i can scale everything to be equally sized on every device. The hero would than be in the middle of the screen for the first step.
The working solution for that is
xCam += hero.moveX;
yCam += hero.moveY;
canvas.translate(xCam,yCam);
drawRoom();
canvas.restore();
drawHero();
I do it like this, because i dont wand to rearrange every tile in the game. I guess that could be too much processing on some devices. As i said, this works just fine. the hero is in the middle of the screen, and the whole room is moving.
But the problem is collision detection.
Here a quick example:
wall.rect.intersects(hero.rect);
Assuming the wall was originally on (0/0) and the hero is on (screenWitdh/2 / screenHeight/2) they should collide on some point.
The problem is, that the x and y of the wall.rect never change. They are (0/0) at any point of the canvas translation, so they can never collide.
I know, that I can work with canvas.getClipBounds() and then use the coordinates of the returned rect to change every tile, but as I mentioned above, I am trying to avoid that plus, the returned rect only works with int values, and not float.
Do you guys know any solution for that problem, or has anyone ever fixed something like this?
Looking forward to your answers!
You can separate your model logic and view logic. Suppose your development dimension for the window is WxH. In this case if your sprite in the model is 100x100 and placed at 0,0, it will cover area from 0,0 to 100, 100. Let's add next sprite (same 100x100 dimension) at 105,0 (basically slightly to the right of the first one), which covers area from 105,0 to 205,100. It is obvious that in the model they are not colliding. Now, as for view if your target device happens to be WxH you just draw the model as it is. If your device has a screen with w = 2*W, h = 2*H, so twice as big in each direction. You just multiply the x and y by w / W and h / H respectively. Therefore we get 2x for x and y, which on screen becomes 1st object - from 0,0 to 200, 200, 2nd object - from 210,0 to 410, 200. As can be seen they are still not colliding. To sum up, separate your game logic from your drawing (rendering) logic.
I think you should have variables holding the player's position on the "map". So you can use this to determine the collision with the non changing wall. It should look something like (depensing on the rest of your code):
canvas.translate(-hero.rect.centerX(), -.rect.centerY());
drawRoom();
canvas.restore();
drawHero();
Generally you should do the calculations in map coordinates, not on screen. For rendering just use the (negative) player position for translation.

Java "zooming" Canvas?

I have a java.awt.canvas object and I draw stuff with the Graphics2D (which I get from the bufferStrategy) and I'd like to "zoom" in and out.
So if I zoom in (scaling it up by a factor of 1) such that a line I draw from (0,0) to (10,10) Would be in reality drawn from (0,0) to (20,20)
Is this possible, or do I have to implement this myself?
Take a look at Graphics2D: http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html
You apply a suitable transformation to the graphics to achieve many transformations, rotate, scale (aka zoom) and translation. Simplest way to zoom would probably be
graphics2d.scale(2.0, 2.0); // draw everything twice the original size

Drawing specific parts of Graphics2D

I have written a game, and now I would like to learn how to manipulate camera.
My drawing consists of this:
private void render()
{
// CREATE THE GRAPHICS
Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics();
// MAKE THE PICTURE WHERE WE WILL PAINT EVERYTHING AT ONCE
g.clearRect(0, 0, WIDTH, HEIGHT);
// PAINT ANYTHING WE NEED HERE
render(g);
g.dispose();
// SHOW THE WHOLE IMAGE RATHER THAN PAININT ONE OBJECT AT A TIME
bufferStrategy.show();
}
My BufferStrategy is created like so:
canvas = new Canvas();
// once again I add 1 because java is stupid that's why
canvas.setBounds(0, 0, WIDTH+1, HEIGHT+1);
//canvas.setBounds(bounds);
canvas.setIgnoreRepaint(true);
// SET GRAPHICS DEVICE
canvas.createBufferStrategy(2);
bufferStrategy = canvas.getBufferStrategy();
In the render function I draw my game world with all the platforms where they should be. Now if the game world is bigger than the window size, and I would like to be able to focus on the character and draw the part of the world where character is, how would I do that? So let's say my window is 300 x 300, and my game world is 900 x 900, and my character is located in the middle so that I would like to display the part of the graphics where x is 150 y is 150 and the width and height is 300 x 300.
So how would I go about taking that Graphics2D and shifting it over by specified values? I am very sorry if this question has been answered or is easy, but I am new to this and really would like some help.
Thanks for any help in advance.
I have tried all I know to no avail.
So how would I go about taking that Graphics2D and shifting it over by specified values?
Why must you shift the Graphics2D? Why not create an image that extends beyond the viewport and simply shift the viewport. Then if the user gets close to the edge of the viewport, add an image to the leading edge and lop off a portion on the trailing edge.
This is what affine transformations are for.
http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/geom/AffineTransform.html
Shift the character to the center of the screen by applying a shift.
In your paint component, save the current transformation.
Create a new transformation that will then shift the screen to where you would like it to be.
Set Graphics2D to use your new transformation.
Draw the character at the original coordinates
Set Graphics2D to use the original transformation.

Categories

Resources