I am making a Java game, and the game lags a lot when I paint out the graphics.
The way I am currently painting out the graphics is to make a BufferedImage, get the Graphics2D from it, then do a whole bunch of:
g2d.drawImage(loadedImages.getImage(),x,y,null);
After I print all of the images to the BufferedImage, I paint the BufferedImage to the screen.
There are a lot of images I paint to the BufferedImage. Is there a better way to do this that would speed up the painting time?
I do not know much about graphics and graphic cards. Should I use a graphics card? Should I paint directly to the screen? Should I use something entirely different than drawImage()?
The performance should be good if you're drawing a reasonable amount of images.
Make sure you're not creating new BufferedImages every time you draw to the screen. For example, you might have a Resources singleton in which you manage all of your images so that you only load and unload each image once.
If you really want more performance, you'll want to use OpenGL. See LWJGL, libgdx, or JOGL. You may also want to consider 2D graphics libraries like Slick.
I've found it useful to extend java.awt.Canvas and use
BufferStrategy bs;
void init() {
createBufferStrategy(2);// or 3 for triple-buffering
bs = getBufferStrategy();
}
and then the actual draw() method looks like
void draw() {
Graphics g = bs.getDrawGraphics();
g.drawImage(image, x, y, w, h, null);
// Draw more things here...
// You can also make calls like `myObject.draw(g)` and whatever
// you draw onto `g` within those calls will show up.
bs.show();
g.dispose();
}
This is what I use for drawing a lot of things. And then within each myObject.draw(g) call, there are sometimes multiple other similar calls all chained up. Most often my main draw() method has one or two for loops in it that just say for(Entity e: entities) e.draw(g); or something similar. Then the whole drawing chain is kicked off from there.
Related
so im doing a game using custom repaint on a jpanel, with the following implementation
public synchronized void paintComp(Graphics g) {
//Buffer is a BufferedImage and it Graphics object
EnumMap<Layer,Buffer> buffers = new EnumMap<>(Layer.class);
for (Layer layer : Layer.values()) {
buffers.put(layer, new Buffer(fsize.x, fsize.y));
}
this.ltime = System.currentTimeMillis();
//there i draw all the game content on buffers' g
this.scene.render(this, buffers, ltime, 0, 0);
//then i draw all layers in the right order
for (Buffer buf : buffers.values()) {
buf.g.finalize();
g.drawImage(buf.img, offset.x, offset.y, null);
}
}
basically, because the game content is organised as a tree, i wanted to draw content on layers then draw those layers on the screen in order to have a better ordering
issue is, i only know how to do that by instantiating 1 bufferedimage per layer each time that function is called, which considering the game is around 60fps and i have 18 layers, i create 1000 bufferedImage per second... is quite suboptimal :')
How could i implement that idea of buffers in a more proper way? i've heard of Rasters, VolatileImage and BufferStrategy but i just couldnt find the infos i needed nor work my way through the javadoc
Well, i bypassed that problem by doing lists of things to draw instead of bufferedimages
Here are some ideas (not tested):
Use a CardLayout put each panels not opaque
Use the BetterGlassPane and in the paintComponent method use a for loop for paint all the layers using the Graphics object. https://github.com/kristian/better-glass-pane/blob/master/src/main/java/lc/kra/swing/BetterGlassPane.java
Use JLayeredPane https://docs.oracle.com/en/java/javase/14/docs/api/java.desktop/javax/swing/JLayeredPane.html
Use JLayer https://docs.oracle.com/en/java/javase/14/docs/api/java.desktop/javax/swing/JLayer.html
I would like to know how can I rotate a texture paint with image in java.
Normally it is easy to rotate the Graphics2D g2 object, but I don't want to do that. I also don't want to rotate my shape and do some crazy rotation scales, etc. It will be easy to normally do the drawing and fills with paint while paint itself is scaled, rotated, etc.
I also don't want to create a rotated image and then texturepaint it.
There is a createContext inside the texturepaint class but I don't know how can I use it to rotate the original image.
I hope you understand what I mean by rotating the texture itself nwo :) ?
Thank you.
Edit:
I was playing with Java custom Paint implementation performance issue but there is an issue I cannot handle. When there is an offset to where tiling will be started, it does not start correctly.
Sorry for mixing up the problem.
I decided to create a second shape before transform the canvas, and then rotate it back to match the inverse of the trnsform.
This solved my problem.
try {
this.shape = new Path2D.Double(bx.createInverse().createTransformedShape(shape));
} catch (NoninvertibleTransformException ex) {
}
It is possible to draw from one Graphics2D to another Graphics2D?
Let me explain.
I have printing issues, when i display a JTextArea or JTextPanel in screen, internaly its used sun.java2d.SunGraphics2D, but when im printing its used sun.print.PeekGraphics and sun.awt.windows.WPathGraphics.
The problem is with some kind of Fonts, like Arial. In some sizes lines are cut.
I have tryed a lot of ways to render the text in printing, Graphics2D.drawString, SwingUtilities2.drawString, TextLayout.drawString, but in some cases lines are still cut, or lines are not cut but some kind of justification makes disapear white spaces.
So my idea is try to render components with sun.java2d.SunGraphics2D and "copy" the surface to the printer via sun.print.PeekGraphics or sun.awt.windows.WPathGraphics.
Thanks in advance.
Yes its possible, thats how double buffering is achieved in a lot of Java Games. What you need is the Graphics2D's drawImage() method which takes in another Graphics2D object to draw in. E.g. from a small game of mine:
private Main(){
...
/* Create the backbuffer as a BufferedImage object */
this.doubleBuffer = new BufferedImage(this.WIDTH, this.HEIGHT, BufferedImage.TYPE_INT_RGB);
/* create a Graphics 2D object to draw INTO this backbuffer */
this.doubleBufferG2D = (Graphics2D) doubleBuffer.createGraphics();
...
}
Somewhere else:
/*Now lets draw the backbuffer INTO the screen */
g2d.drawImage(doubleBuffer, null , 0, 0);
Edit: heh I realized its not exactly as above...lemme think on it.
Edit2: Alright the above can still be used a sample, but the sequence of steps to draw from one Graphics2D to another should be as such:
1. From a Graphics2D object to an Image/BufferedImage object using drawGraphics().
2. From the Image/BufferedImage above, extract its member Graphics2D object by using itscreateGraphics().
Looks like you can do one of two things:
create a Graphics2D on an image, do your rendering, then draw the image into another Graphics2D
or create Graphics2D from original Graphics2D using Graphics.create() methods and then do you rendering.
I'm Basically programming a simple game engine but I'm having problems with my sprites/images not appearing when they should... or at all!
I'll try and keep this as simple as possible. I have a Sprite, GameEngine and Display class. In the gameloop, I have a method that sets the new position of my Sprite (so it just sets the x and y variables). Next I call a transform method which does the following:
public void transform() {
affineTransform.setToIdentity();
affineTransform.translate(x, y);
}
Following that, I then call a draw method in the Sprite:
public void draw() {
graphics2D.drawImage(image, affineTransform, jFrame);
}
Finally, in my thread I then call repaint() on the JFrame (the Display class). My paint method for that class is as follows:
public void paint(Graphics g) {
g.drawImage(backbuffer, insets.left, insets.top, this);
}
But nothing is appearing, apart from a black screen!
I'm also getting confused between Graphics g, and Graphics2D and when to use either. (The overridden paint method uses Graphics g). For the record, I do have a Graphics2D variable in the class that is created by calling backbuffer.createGraphics();
Another thing that is confusing me is this AffineTransform... I've read the documentation but I'm still utterly confused on how and when to use it - and what exactly it seems to do. Is there any explanation in relatively simple terms?
Surely this should be working... am I missing something out here?
To answer part of your question:
From the Graphics2D JavaDoc
This Graphics2D class extends the Graphics class to provide more sophisticated control over geometry, coordinate transformations, color management, and text layout. This is the fundamental class for rendering 2-dimensional shapes, text and images on the Java(tm) platform.
Essentially, with Graphics2D you can do much more than you can with Graphics. And with a Sun JVM 1.5+, it should be safe to cast the Graphics object you get in paint() to Graphics2D
I just noticed this: For the record, I do have a Graphics2D variable in the class that is created by calling backbuffer.createGraphics();
You should make sure you're not drawing on a Graphics[2D] canvas (I'll use this term to refer to the drawable area that the Graphics[2D] object provides) that you later throw away. If you're drawing your image on a separate canvas, you should ensure that you then draw that image onto your actual display canvas.
I don't really have a good explanation of AffineTransform but maybe these will help?
http://www.javalobby.org/java/forums/t19387.html
https://secure.wikimedia.org/wikipedia/en/wiki/Affine_transformation
From Wikipedia - In general, an affine transformation is composed of linear transformations (rotation, scaling or shear) and a translation (or "shift"). Several linear transformations can be combined into a single one. Basically, you use this class to perform operations such as rotation, translation, zoom etc.
I want to create a number of straight lines connecting small circle shapes. then I want to change the color and width of the lines from within my program. I was thinking of using Canvas to do this but there does not seem to be a way to access individual shapes drawn on canvas to change their attributes after they are drawn. What would be an easy way to implement this?
First of all, what version of Java and which UI toolkit? AWT's Canvas is very dumb, it will not even "remember" what you have painted; when you minimize and restore the window, it will send a paint() event because it wants to be repainted.
The easiest way (if you are using AWT and stuck to Canvas) is to have a List of your shapes (either one list for all or one for circles and one for lines, or whatever you like) and make your paint method draw all of them. Then update the objects in your list. When you are done updating, call repaint() on your canvas and it will call paint() for you again.
You don't paint shapes onto a Canvas if you're using Graphics and Graphics2D functions like drawRect, drawPolygon, drawOval, etc. Once they're drawn, they don't exist as shapes anymore. You just have an image with filled-in pixels.
As mihi said, you may have to keep track of the shapes you're trying to draw, then regenerate your image if it changes. Perhaps you could also "unpaint" a shape you're trying to change by painting over it in the background color and repainting the changed shape.