Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (541)
Games in Android Showcase (133)
games submitted by our members
Games in WIP (603)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Rotating images, fast?  (Read 6526 times)
0 Members and 1 Guest are viewing this topic.
Offline Regenuluz
« Posted 2013-03-19 19:38:06 »

Hey,

So I'm revisiting the tower defense game I started making some time back, and decided to give it another whirl in Java2D, while waiting for LWJGL to hit 1.9.0 and be usable on OS X with Java 7.

The reason I stopped working on it, was that the rendering became horribly slow after placing ~110 towers. This time around I did a little digging and found out that it's because I rotate my tower images that it starts to get slow. I rotate them, so that they're always facing the nearest enemy they can reach.

I use the following code to render each tower:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
public void render(Graphics2D g2d) {
   // Turret base shadow
   g2d.drawImage(this.actor.getImage(1), this.pos.x - 16 + 1, this.pos.y - 16 + 1, null);

   // Turret base
   g2d.drawImage(this.actor.getImage(0), this.pos.x - 16, this.pos.y - 16, null);

   AffineTransform tx = new AffineTransform();
   tx.rotate(this.rotation, 16, 16);
   AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);

   // Turret shadow
   g2d.drawImage(op.filter(this.actor.getImage(5), null), this.pos.x - 16 + 2, this.pos.y - 16 + 2, null);

   // Turret
   g2d.drawImage(op.filter(this.actor.getImage(this.towerSprite), null), this.pos.x - 16, this.pos.y - 16, null);
}


When rendering 166 towers that way(Each tower renders itself, btw), the fps has gone from 60 to ~34, when I remove the rotating of the images, then it has no problem rendering the towers at 60fps.

Soo, golden question, how can I optimize this? Smiley
Offline theagentd

« JGO Bitwise Duke »


Medals: 366
Projects: 2
Exp: 8 years



« Reply #1 - Posted 2013-03-19 20:12:19 »

Disable bilinear filtering.

EDIT:
You're currently creating a rotated version of the image instance each time you render. It's incredibly inefficient. Instead, just call g2d.rotate(rotation). It'll be much faster to draw the original image rotated than to create a rotated version of the image and then drawing it (note the difference).

Myomyomyo.
Offline Regenuluz
« Reply #2 - Posted 2013-03-19 20:29:24 »

What should I use instead? AffineTransformOp.TYPE_NEAREST_NEIGHBOR makes the images all grainy. :/
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline cubemaster21
« Reply #3 - Posted 2013-03-19 20:31:33 »

I personally don't use any AffineTransformOp, and it looks fine.

Check out my game, Viking Supermarket Smash
http://www.java-gaming.org/topics/iconified/28984/view.html
Offline SimonH
« Reply #4 - Posted 2013-03-19 21:21:35 »

A trick you could use is to make a spritesheet of the turret image rotated in 10' steps and just draw the one closest to the true rotation value. (You could alternatively generate 36 rotated sprites at runtime and use them in the same way). Not perfect, but very fast!

People make games and games make people
Offline Regenuluz
« Reply #5 - Posted 2013-03-19 21:43:23 »

I personally don't use any AffineTransformOp, and it looks fine.

Then what do you use?

A trick you could use is to make a spritesheet of the turret image rotated in 10' steps and just draw the one closest to the true rotation value. (You could alternatively generate 36 rotated sprites at runtime and use them in the same way). Not perfect, but very fast!

I was considering that, if there isn't any faster way to rotate it "live."
Offline cubemaster21
« Reply #6 - Posted 2013-03-19 21:48:31 »

I just rotate it by the amount i need, draw the image, and rotate it back.
Sorta like this.
1  
2  
3  
4  
5  
public void draw(Graphics2D g){
     g.rotate(theta, x, y);
     g.drawImage(x,y);
     g.rotate(-theta,x,y);
}

Check out my game, Viking Supermarket Smash
http://www.java-gaming.org/topics/iconified/28984/view.html
Offline StumpyStrust
« Reply #7 - Posted 2013-03-20 07:36:17 »

The g.rotate is the fastest other then probably doing the sprite sheet. I can confirm that almost all computers will be able to do at least 2k objects changing rotation every frame at 60fps. So I do not think rotation is going to be a huge bottle neck in a TD game unless you have like a biggilion towers which would be silly.

Set RenderingHints on the graphics object.

I recommend setting them in the main graphics object passed around at the beginning of each render. If you find my old post that was a menu demo in java2D, there should also be a source link that shows how I did the rendering which I found to be fast but Java2D unreliable.

Edit: here. Look at the Window class

http://www.java-gaming.org/topics/game-menu-demo/26815/view.html

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
public void render( Graphics g )
   {
      Graphics2D g2d = (Graphics2D)g.create();
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) (fade)));
        g2d.setTransform(AffineTransform.getRotateInstance(rotation.x, loc.x, loc.y));//replace this bad line with the g.rotate
      if(image != null)
      {
         if(alive)//bad coding mixing logic and rendering bad bad
         {
            int x1 = (int) (loc.x - (size/2));
            int y1 = (int) (loc.y - (size/2));
            g2d.drawImage(image, x1, y1, (int)size, (int)size, null);
         }
      }
      else if(alive)//bad bad bad
      {
         int x1 = (int)size >> 1;
            int y1 = (int)size >> 1;
         g2d.setColor(color);
         g2d.fillRect((int)(loc.x - x1), (int)(loc.y - y1), (int)size, (int)size);
      }
      g2d.dispose();
   }


Offline Regenuluz
« Reply #8 - Posted 2013-03-20 21:27:14 »

I'm currently failing hard in getting that to work as intended xD I should probably give it another try, when I'm less tired.
Offline Regenuluz
« Reply #9 - Posted 2013-03-20 21:51:59 »

Alright, I got it working now. Smiley But it's still making jagged edges on my beautiful circles.. :/ But at least I can render lots more towers now, without it starting to drop fps, it's steady around 60 where it would've been ~25 with the above code.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline StumpyStrust
« Reply #10 - Posted 2013-03-21 01:33:14 »

If you are rendering primitives, then turn on anti aliasing. If you are not, then try bluring the edges of your tower sprites slightly as they will help with jagged edges.

Offline Regenuluz
« Reply #11 - Posted 2013-03-21 12:07:48 »

I'll try and blur the edges on my sprites and see how that looks. Smiley

And I think the performance now is good enough that it will be able to handle all the towers that I can throw at it(which is rather limited, because of the map and such)

Next up is implementing the A* algorithm I made for my AI class into this game so the mobs can actually do things, like moving around obstacles. Tongue
Offline Regenuluz
« Reply #12 - Posted 2013-03-21 12:27:46 »

I've actually got 1 last question.

I'm drawing both a shadow and the turret, but when rotating the image, the shadow get's offset wrong.

How do I translate my (x, y) coords, so that they match the new rotated image? (Such that the shadow stays in the same position, but get's rotated around (x, y))

Example of how it looks now:


I want the shadow to stay underneath the tower, offset down and to the right a few pixels, not rotating around as it's doing right now.
Offline StumpyStrust
« Reply #13 - Posted 2013-03-21 20:32:48 »

When you render images, I always have it so the location in the world (x,y) is the center of the sprite. If you do that, and then call g.rotate() with the x,y then you will not have that issue.

So if my sprite is 32x64 at 256,432

I will take 256-32/2 and 432-64/2 and draw with the width 32 and height 64. Then have the shadow and main sprite at the same location. If the shadow needs and offset, add it to the loc before rendering.

Offline Regenuluz
« Reply #14 - Posted 2013-03-21 21:07:07 »

I'm doing this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
      Graphics2D g2d = (Graphics2D) g.create();
      // Rotate
      g2d.rotate(this.rotation, this.pos.x, this.pos.y);

      // Turret shadow
      g2d.drawImage(this.actor.getImage(5), this.pos.x - 16 - 2, this.pos.y - 16 - 2, null);

      // Turret
      g2d.drawImage(this.actor.getImage(this.towerSprite), this.pos.x - 16, this.pos.y - 16, null);
      g2d.dispose();


the pos.x and pos.y coords is the center of the sprite, and the Turret itself behaves nicely, but the shadow does as you can see in the image :/
Offline StumpyStrust
« Reply #15 - Posted 2013-03-21 22:57:23 »

what is the size of your tower and shadow sprites? are they the same? I would almost always give the width and height even if they are the same. Scaling is rather cheap in java2D and basically free in opengl.

I nice way to draw things I think is to have the width and height already know in a class like sprite so you don't have to use magic constants. This will also allow you to easily change the size without have to do any extra coding.

Offline cubemaster21
« Reply #16 - Posted 2013-03-21 23:12:11 »

Ooh! ooh! I know this one! when you call g.rotate(....);,  you are providing the coordinates for the origin as the top right corner of the tower. You need to add half of the width to the x position and half of the height to the y position. So it would look like:
1  
g.rotate(this.rotation, this.pos.x + (this.actor.getImage(....).getWidth() / 2), this.pos.y + (this.actor.getImage(.....).getHeight() / 2)); 

Check out my game, Viking Supermarket Smash
http://www.java-gaming.org/topics/iconified/28984/view.html
Offline Regenuluz
« Reply #17 - Posted 2013-03-22 06:06:13 »

Uhm, I'm not sure I get what you guys are saying. xD

The tower and shadow sprite are the same size, 32x32 pixels. And as you can see, then the tower is rendering in the right spot, but the shadow isn't, and the only difference is the "-2" on each axis of the shadow. :/

(In the picture it was something like -5 to show how odd it behaves. If I don't use any offset, then it's rendered correctly, right underneath the tower)
Offline philfrei
« Reply #18 - Posted 2013-03-22 06:43:56 »

I can only see two solutions. Maybe there is a better one.

a) rotate based on the coordinates of the shadow, draw shadow, then rotate on the coordinates of the turret and draw the turret.

b) work out the trig to compensate for the angle of the rotation and add it to the draw position of the shadow (hurts my head at this late hour, but I know it is solvable). Don't know if it is faster or slower doing a bit of trig compared to a second rotate.

However, none of this matters if you are managing a pair of good sprite sheets for the turret and shadow.

"It's after the end of the world! Don't you know that yet?"
Offline relminator
« Reply #19 - Posted 2013-03-22 07:04:06 »

Don't apply the same transform to both your turret and its shadow.  Use a different transformation matrix to transform your shadow.
Offline Regenuluz
« Reply #20 - Posted 2013-03-22 07:12:48 »

I've fixed it by rotating first around the shadows center, and then around the towers center. And for now the performance seems to be fine enough for me to live with. Smiley

Thanks a lot for the help guys!
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Mr.CodeIt (24 views)
2014-12-23 03:34:11

rwatson462 (55 views)
2014-12-15 09:26:44

Mr.CodeIt (45 views)
2014-12-14 19:50:38

BurntPizza (89 views)
2014-12-09 22:41:13

BurntPizza (112 views)
2014-12-08 04:46:31

JscottyBieshaar (83 views)
2014-12-05 12:39:02

SHC (92 views)
2014-12-03 16:27:13

CopyableCougar4 (100 views)
2014-11-29 21:32:03

toopeicgaming1999 (160 views)
2014-11-26 15:22:04

toopeicgaming1999 (159 views)
2014-11-26 15:20:36
Resources for WIP games
by kpars
2014-12-18 10:26:14

Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!