0

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:

https://i.stack.imgur.com/IqeEA.png

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:

https://i.stack.imgur.com/HUpyL.png

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:

https://i.stack.imgur.com/ZJ4UC.png

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.

camickr
  • 321,443
  • 19
  • 166
  • 288
LuckyBandit74
  • 417
  • 1
  • 4
  • 10
  • *and angle in degrees* - the angle should be in radians. Use `Math.toRadians(...)` to convert. See: https://stackoverflow.com/questions/28755136/how-to-rotate-a-non-square-image-in-java/28755981#28755981 for a working example. The `Rotation` example rotates a BufferedImage. – camickr Mar 21 '21 at 21:37
  • @camickr , Thanks for the reply, but I have looked at that answer and implemented it and it was not rotating in place sadly (at this point I have implemented many answers from different forums and they have not worked for me). Also, my method has the line angle = Math.toRadians(angle) so the angle is indeed in radians. – LuckyBandit74 Mar 21 '21 at 21:43
  • It is not designed to rotate in place. Your method is designed to return a BufferedImage. It is then up to your painting code to center the image based on its new dimensions. Check out the `Rotation2` example. It demonstrates how to do the rotation in place of your original image (without creating a rotated BufferedImage) – camickr Mar 21 '21 at 21:53
  • It is not really related to your question. But you know that it is pretty easy to implement a keylistene, right? I just don´t get why you would use JScrollBars to control the tank. I can´t imagine smooth controlling with them. – Lasnik Mar 21 '21 at 21:56
  • *I would really appreciate a helpful answer that directly edits my method if possible.* - this is only possible if you post an [mre]. The links I gave you above are examples of an MRE. You can copy/paste/compile and test the code from a single class. – camickr Mar 21 '21 at 21:56
  • 1
    @camickr So I just want to say thank you because this was really frustrating me. The second comment you posted just helped me solve my problem. I made variables to account for the offsets and accounted them when repainting. I guess I need to be a little more creative... Thanks again. – LuckyBandit74 Mar 21 '21 at 21:59
  • @Lasnik So my tilemap isnt actaully as large as shown in the pictures, it is larger than that. This is why I need a scrollpane. I want the tank to stay in the middle, and when I move the tank, I am essentially revealing new parts of the tilemap by scrolling. I think your interpretation was just a misunderstanding as I did not clarify this. Also, the scrollbars smoothness is enough for me so it really isnt that big of a deal. Thanks for your input. – LuckyBandit74 Mar 21 '21 at 22:02
  • Please post a full answer to this question if you've solved it. You can accept it if you haven't gotten a better one by then. – NomadMaker Mar 21 '21 at 22:04
  • @LuckyBandit74 I would just adapt an KeyListener and translate my Tilemap based on Keystrokes. That would have the same effect but would be much more controlable. But as you said. If it is enough for you just leave it as it is. :) – Lasnik Mar 21 '21 at 22:06

2 Answers2

0

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

LuckyBandit74
  • 417
  • 1
  • 4
  • 10
0

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.

  • Thanks for the reply, and though that seems like a great answer to try and implement, I have already solved the problem and I think I will stick to it. See my answer for details if you want :) – LuckyBandit74 Mar 21 '21 at 22:34