Optimizing Java Graphics - java

I have a custom UI drawn for my java application. Right now I draw the entire UI from scratch. I know for a fact some parts of the UI are static. I know I could save these static parts to an image, but will this yield a improvement in performance (Since even an image must be drawn every frame)?
Is it plausible to save a reference to the Graphics2D object after the UI has been drawn and assign that to the new graphics object every frame (starting from a point where all the static components are drawn)?
Thanks in advance,
Alan

You don't need to redraw everything in every frame. So if you have static parts of your UI (or even dynamic parts that you know haven't changed since last frame) then you simply don't need to repaint them.
In my code (Swing games and simulations mostly) I usually try to follow the following rules:
Pre-prepare static images (e.g. BufferedImage textures for UI elements)
Override the paintComponent() method for each UI element individually to do the painting
Only call the repaint() method of any given UI element if I know that something has changed
Call repaint() in a timer-based loop for animation, but only call it on the portion of the UI that is being animated (e.g. a nested JPanel)
This approach seems to work and perform pretty well (though I'd welcome comments if there are ways to improve it!!)

There are two main optimizations you can do here. The first is to make sure that when you cause your UI to be repainted, usually done by calling repaint, make sure you call the version of repaint where you specify a rectangle that has changed. Only make the rectangle big enough to encompass the parts that actually have changed, not the static parts. For this to be effective you also have to pay attention to the clipRect in the Graphics2D object you are passed in paint(). That is used by the system to tell you exactly what needs to be repainted, in the above case usually the rectangle that you passed to repaint. Don't paint anything that lies entirely outside that rectangle.
You can also get significant performance improvements by caching the static parts of your interface in an image. Writing an image is by far the fastest way of getting things onto a screen. My measurements indicate that small images are faster than even a few simple drawing primitives. However you need to make sure the image characteristics match the screen, by using createCompatibleImage().
Of course you may be using a lot of memory to get this speedup. I would recommend testing to see if you need to do image caching before implementing it.

if some parts of the screen is completely static, then never redraw that part. Don't do a full-screen/window clear, just clear the part of the screen/window that changes all the time.
This way, you don't unnecessarily redraw the static image.

Related

Java Game moving real time(AP CS Final)

I'm taking the AP computer science class at my school. They never taught us about GUIs because the AP test didn't require you to know how to make one.
For our final project we wanted to make something like tron (game where bikes move around an are creating walls of light behind them in an attempt to crash the other player). Before we continue i just want to make sure we are going in the right direction. Should we use ImageIcon for the players or maybe something else?
We still have a lot to learn, but i thought this would be a good thing to start with. The reason why i'm asking is because i'm not sure if we would be able to move them without opening another window every time we want to move something.
This is probably a matter of opinion, but personally, I would use BufferedImage's as the primary image container.
The main reasons are:
They are easy to paint and easy to manipulate, you can actually draw onto them if you need to.
Loading a BufferedImage is done through ImageIO.read, it guarantees that the entire image is loaded before the read method returns and will throw an IOException if it can't read the image for some reason, which is better than ImageIcon which loads the image in a background thread and doesn't report errors if the image failed to load
Movement or placement of the images would be done, typically, by painting them onto an output Graphics context. This is (typically) done by overriding the paintComponent method of something that extends JComponent and using the passed Graphics context and Graphics#drawImage
Have a look at Performing Custom Painting, 2D Graphics and Reading/Loading an Image for more details

What is a good approach of to draw graphics with swing?

I am a complete novice when it comes to any kind of graphics. So, I want to create a method in a class Creature that would be able to draw lines on a screen (turtle graphics style). I have no idea what would be a good way of doing this. I mean I could store all lines drawn by user in a container or whatever and every time the repaint() method is called I would redraw all lines but it looks bothersome. Or perhaps it's the best way and I am just being silly? As I said, I don't have any experience with this and everything is starting to look like black magic to me. I would appreciate any help or suggestions. Thanks!
See Custom Painting Approaches for two common ways to do this:
Keep a List of objects to be painted and repaint them every time
Paint to a BufferedImage and just display the image
Updating what to draw and actually drawing it should be separate, because you can't control when repaint() is called. You usually want to control how often the updating is done so it's always a good idea to separate. This also reduces the time it takes to draw so it increases performance as well.

Taking advantage of Swing double-buffering

I am writing a program that involves overriding a JPanel to do some graphics work. Basically this JPanel is displaying a field of hexagons and the user can interact with individual cells. This field is composed potentially of hundreds or thousands of hexagons, and most of the time when changes occur, only a tiny portion of the screen is affected. But at the same time, it uses multiple layers (there's a "main" layer that shows what the cells contain, and an overlay that shows which cells are selected and ready to be modified)
In order to avoid the cost of rendering each and every cell any time a repaint is needed, my app as it currently exists holds a BufferedImage for each layer. When paintComponent() is called, the app checks to see if any changes have been made that need to be drawn (for example, a user clicked on the screen so the overlay needs to show that some cell is selected), and if so, renders the modified layers to their bufferedimages. In either case, the the repaint just blits both of the BufferedImages to the screen.
It works just fine, but this is basically a home-spun version of double buffering, which Swing is supposed to support internally. However, for the life of me I can't seem to find where to get access to the component's backing buffer so that I can modify it... If I call "getGraphics()" on the JPanel, I get null pointer exceptions -- So that's a no-go.
I am looking for a more elegant elegant way to do this which hopefully takes advantage of the built-in double buffering offered by swing, in order to avoid blitting the entire screen just for one tiny change (and to avoid having to reinvent clipping).
Any ideas?

Working my way arround repaint() in Java

I'm planning to write a simple spaceshooter. I have read that the repaint() method is only a request, and it doesn't execute every time it's called. I believe I'm noticing the effects of this, as my spaceship tends to lag ever so slightly when I'm moving it. Currently I'm simply drawing my ship in a a JPanel's paintComponent() method, and keep calling repaint() on regular intervals (my panel's also Runnable). Seeing as repaint() may potentially screw me over, I'm trying to find a way to work arround it, however I've ran out of ideas. The code I have so far:
private void renderGraphics() {
if (MyImage == null) {
MyImage = new BufferedImage(getPreferredSize().width,
getPreferredSize().height, BufferedImage.TYPE_INT_RGB);
}
MyGraphics = MyImage.getGraphics();
MyGraphics.setColor(Color.BLACK);
MyGraphics.fillRect(0, 0, getPreferredSize().width, getPreferredSize().height);
MyGraphics.drawImage(ship.getImage(), ship.getCurrentX(), ship.getCurrentY(), null);
}
The idea was to create my own graphics, and then make the JPanel draw it, and keep calling this instead of repaint() in my run() method, however I have no idea how to do that. I'd appriciate any input on the matter.
There are multiple ways to approach this.
The best is probably to use BufferStrategy and draw to that, of which I have included a code snippet that should work for you.
You can take this one step further and abandon Swing altogether, just using Frame/BufferStrategy. There is a fully working example (from which the code snippet was taken and adapted) in my question here:
AWT custom rendering - capture smooth resizes and eliminate resize flicker
Anyway, here is an implementation BufferStrategy that you should be able to just drop in:
// you should be extending JFrame
public void addNotify() {
super.addNotify();
createBufferStrategy(2);
}
private synchronized void render() {
BufferStrategy strategy = getBufferStrategy();
if (strategy==null) return;
sizeChanged = false;
// Render single frame
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
MyGraphics draw = strategy.getDrawGraphics();
draw.setColor(Color.BLACK);
draw.fillRect(0, 0, getPreferredSize().width, getPreferredSize().height);
draw.drawImage(ship.getImage(), ship.getCurrentX(), ship.getCurrentY(), null);
draw.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (strategy.contentsRestored());
// Display the buffer
strategy.show();
// Repeat the rendering if the drawing buffer was lost
} while (strategy.contentsLost());
}
any drawing will still be performed in the Swing Thread, so no matter what you try work around, it wont help.
Make sure you are not doing any lengthy calculations in the swing thread, this may be stopping repaint from being executed as soon as it needs to be executed
Separate all the logic into 2 parts. Static and Dynamic. (e.g. sea and moving ship. Ship changes shape/location on a static image of sea)
Draw static content in an image once and use the image in your paintComponent(). Call dynamic parts painting after the static image.
Use setClip() to restrict repainting areas.
Calling repaint without any arguments means that the whole panel is repainted.
If you need to repaint parts of the screen (the spaceship has moved to a different location) you should make shure that only those parts of the screen are repainted. The areas that stay the same should not be touched.
Repaint takes coordinates of a rectangle that should be repainted. When moving the ship you should know the old coordinates of the ship and the coordinates the ship should move to.
repaint( oldShipCoordinateX, oldShipCoordinateY, shipWidth, shipLength );
repaint( newShipCoordinateX, newShipCoordinateY, shipWidth, shipLength );
This is usually much faster than calling repaint() without arguments. However you have extra effort to remember the last position of the ship and must be able to calculate the new position of the ship.
See also: http://download.oracle.com/javase/tutorial/uiswing/painting/index.html - especially step 3
Just for code that you post here:
1/ if you want to display Image/ImageIcon, then the best and easiest way is to Use Labels
2/ as you mentioned Runnable{...}.start(); Swing is simple threaded and all output to GUI must be done on EDT; you have to look at Concurrency in Swing, result is that all output from BackGround Task(s) must be wrapped into invokeLater(), and if is there problem with perfomancie then into invokeAndWait()
3/ if you be switch (between JComponents)/add/delete/change Layout then you have to call revalidate() + repaint() as last lines in concrete code block
EDIT:
dirty hack would be paintImmediately()
I have read that the repaint() method is only a request, and it doesn't execute every time it's called
It consolidates multiple repaint() requests into one to be more efficient.
I believe I'm noticing the effects of this, as my spaceship tends to lag ever so slightly when I'm moving it.
Then post your SSCCE that demonstrates this problem. I suspect the problem is your code.
Regarding the solution you accepted, take a look at Charles last posting: Swing/JFrame vs AWT/Frame for rendering outside the EDT comparing Swing vs AWT solutions.

How can I split up paint swing method in java?

I'm developing a fair sized hospital simulation game in java.
Right now, my pain method is starting to look a little big, and I need a way to split it up into different sections...
I have an idea, but I'm not sure if this is the best way.
It starts by painting the grass, then the hospital building, then any buildings, then people, then any building previews when building. The grass and hospital building will not change, so I only need to paint this once. The buildings themselves won't change very often, only when new ones are built.
I was thinking, use boolean values to determine which sections need repainting?
Ideal, id like to be able to split up the paint method, and then call each one when needed, but I'm unsure how to physically split it up.
I am still quite new to java, and learning on the go.
Thanks in advance.
Rel
Another idea is to create a super class or interface for all items that must be drawn on the screen. Lets cvall this class ScreenObject. You can then have a draw(Graphics2d g) method specified in the ScreenObject class. Next, each object that must be drawn implements the draw() method and is only concerned about drawing itself. You can even consider creating a variable that determines whether this draw method should be run at all.
In the main class that paints the screen you can have a reference to all ScreenObjects in an ArrayList and your paint() method will simply iterate over this calling draw() on each object.
I'm assuming from your description that your scene is split up into tiles. Keeping an array of booleans is a good way to keep track of which tiles need redrawn on the next update. A LinkedList might perform a little better in some situations. (I'm thinking of a Game of Life simulation where there are tons of tiles to redraw and you need to check each neighbor, so you may not need to go this route.)
Without seeing your code I can't give very specific advice on splitting up your paint method. I can tell you that in sprite animations, each sprite object typically has its own draw method that takes the main Graphics object (or more likely a buffer) as a parameter. Since the sprite should know its own image and location, it can then draw itself into the main image. Your paint method can then just loop through your list of sprites that need to be redrawn and call their draw method.
You might look to Killer Game Programming in Java for more detailed information.
Well I am not really an expert at programming but to split up my paint method Ive always just made a new method that takes a Graphics object and call that from paint, it has always helped me to keep my code organized but I have never had a big project like it sounds you are working on so it might not work for your situation.

Categories