Is this bad practice? Multiple Graphics2D Objects - java

I've created a JPanel canvas that holds all graphics; namely JLabel. To get animated sprites to work you have to over ride the paintComponent of the extended JLabel class. I've successfully implemented animated sprites this way.
Is it bad practice to have a Graphics2D canvas and then have multiple 'images' in their own Graphics2D?

I don't think it will be too much heavyweight since the Graphics2D of your JPanel should be the same one that is passed to the JLabel but with different bounds and offsets.
What I mean is that Swing doesn't allocate a new graphics context on which you can display for every element inside a hierarchy of objects but it uses the same with different capabilities. This doesn't mean that panel.getGraphics() == label.getGraphics() but neither they are completely different obects.
In any case, if you need to do much animated work I would suggest you to have your own sprite class
class Sprite
{
Point2D position;
Rectangle2D size;
float rotation;
}
and handle everything at the same paintComponent level. Or at least I've always did that way since Java2D is not like CoreAnimation that is made to be used on a per-layer basis for moving/animated content.

Related

JPanel repaint does not work

I am developing a graphic project in java using swing and awt libraries. I am looking for a method that allow me to draw very fast on my JPanel. I tried various methods: overriding paintComponent, calling repaint(x, y, width, heigth).. But in all cases i have to repaint ALL the screen! I have a background and a small image in front of it that changes every few time. i am looking for a method that allow me to paint on the screen only the small image, i don't need to repaint the background too, because it is always the same, and the small image is always at the same coords. for example in C++ i painted the background and then i only painted the small images in front of it using putimage (graphics.h), so that it was very very fast. Do someone have some tips?
I've had some experience with game programming and usually a JPanel is used as canvas. Now to paint on it you would write a simple loop which continuously buffers an image and later paints it to the screen. So on initialisation you create a Graphics or Graphics2D object which is passed to a buffer() method. After painting a BufferedImage with the Instance of Graphics, some paint() method paints the BufferedImage to the screen.
When only painting the background once, previously drawn images will still be visible. If all your images are the same size, you don't have to bother but I still recommend repainting your background as well.
Have a look at the book Killer Game Programming In Java for further information, it's a great reference.
Tips:
Paint static images to a BufferedImage and then draw that within the paintComponent using Graphics#drawImage(...)
You do know that the repaint(...) method is overloaded and that one overload can accept a Rectangle parameter, limiting the area of repainting.

Relationship between BufferedImage, Graphics, and Canvas for games

I am a fairly new programmer and I am trying to make a very basic game using Java where you just move a sprite around the screen. What I have accomplished so far is make a SpriteSheet class that loads in my sprite sheet and saves a BufferedImage of the spritesheet as a field of that class and a Sprite class that will get a subimage(the sprite itself) from this field and saves it as a field in the Sprite class. I've tested this and it all works like it should. I understand this may not all be typical or the "correct", efficient way of doing things. I'm ok with figuring that out on my own but my problem now is understanding the relationship between BufferedImage, Graphics, and Canvas. I saw a tutorial where a guy saved his sprite as a BufferedImage and used this to create a Graphic. He then painted this Graphic onto a Canvas and added the Canvas to his JFrame. He also fit a BufferStrategy in there somehow connected to his Graphics, and I don't understand that at all. Whenever I try to adapt his method for my purposes, it never works. I've looked over the javadocs countless times for these things and I get them individually, but I just can't seem to understand how they fit together to accomplish my goals.
So in short: can anyone explain how BufferedImage, Graphics, and Canvas all fit together in the context of displaying a sprite for a 2D game, and how is a BufferStrategy used? Appropriate and relevant methods? Will this method be appropriate for rendering moving sprites around 15 fps? etc... My problem does not come from a lack of research or lack of knlowedge necessarily but more from a lack of understanding.
Thank you very much and any advice is greatly appreciated!
BufferedImage is a Image type, which has the capacity to be modified from within the code, but, it has no means by which it can paint it self to the screen.
Canvas is a AWT (heavy weight) container which is typically used for providing activate painting access via it's BufferStrategy. This is displayed to the screen.
Graphics is a abstract graphical library designed to make it easier to perform cross platform renderering.
The Canvas, via it's BufferStragegy provides access to a Graphics instance, which allows you to paint to the Canvas (and by extension, the screen). You use this Graphics context to paint the BufferedImage
A Canvas by itself can't be displayed on the screen, it must be first contained within a window of some type, like java.awt.Frame.
Essentially, the frame shows the user the Canvas, the Canvas provides access to the graphics hardware via the BufferStrategy and Graphics context and the BufferedImage provides a generalised representation of an image/image data which can be painted to the Graphics context (of the Canvas)
Maybe you should start by having a look at the JavaDocs for Canvas, BufferStrategy, BufferStrategy and BufferCapabilities and 2D Graphics for some examples

Swing graphics in multithreaded program

I'm coding a game; something like this: http://i.stack.imgur.com/HBrEE.png
I have a class named Canvas which extends JLabel and in overriden paintComponent(), put an image of gridlines as background, then paint the player and obstacles (walls).
By using createGraphics() , I get a Graphics2D object. I need this to paint weapons and bullets from their classes, too. (As you see, there are several weapons that shoot bullets in specific time intervals.)
For implementing all these, using SwingUtilities.invokeLater() I paint the gridlines, player and walls in Canvas class. I thought of creating a thread per weapon and one per bullet; I know, it's an overkill but since I'm new to multithreading I have no other ideas!
And another problem is with Graphics2D object: I need to share this object between threads so I thought of using final keyword; but it's not possible because the value of Graphics2D object will be determined in paintComponent().
Thanks in advance for any help you are able to provide.
You shouldn't use multi-threaded rendering threads ever (well, in 99% of the cases at least). Most graphics programs keep the full scene state in some object tree that only one thread renders every so often (1/60th of a second). The rendering thread goes through each object in the render tree and invoke .paint or whatever else will get the object to be drawn. Rinse and repeat and you're done.

java 2D and swing

I have trouble understanding a fundamental concept in Java 2D.
To give a specific example:
One can customize a swing component via implementing it's own version of the method paintComponent(Graphics g)
Graphics is available to the body of the method.
Question:
What is exactly this Graphics object, I mean how it is related to the object that has the method paintComponent? Ok, I understand that you can do something like:
g.setColor(Color.GRAY);
g.fillOval(0, 0, getWidth(), getHeight());
To get a gray oval painted. What I can not understand is how is the Graphics object related to the component and the canvas. How is this drawing actually done?
Another example:
public class MyComponent extends JComponent {
protected void paintComponent(Graphics g) {
System.out.println("Width:"+getWidth()+", Height:"+getHeight());
}
public static void main(String args[]) {
JFrame f = new JFrame("Some frame");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(200, 90);
MyComponent component = new MyComponent ();
f.add(component);
f.setVisible(true);
}
}
This prints
Width:184, Height:52
What does this size mean? I have not added anything to the frame of size(200,90).
UPDATE:
I understand that I must override paint to give in the Graphics g object the hints required to do the repaint and that I do not have to create a Graphics object as one will be given by platform.
What happens after that is what I can not understand.
E.g. does Graphics represent the screen and the object is painted accordingly on screen as soon as I start calling the various g.setXXX methods?
Does it get stored in a queue and there is a 1-1 association among g and each component? So the framework uses each g of each component to paint it one at a time?
How does this work?
Any help on this is highly welcome
Thanks
I understand your problem as I struggled with it for some time when I was learning Java graphics. It's not just Java 2D graphics - it is part of AWT.
When you create a JFrame or some other top-level object, it does a lot of work "behind the scenes" - part of which is creating a Graphics object. (There is not explicit notification of this, though if you stepped through the code with a debugger you may see classes which create the Graphics).
You then create components which you add, or register with, the top-level object. These all have to implement a call-back method, including
paint(Graphics g);
You will then #Override these methods so that when the component is rendered it uses YOUR paint method.
Do not try to save the Graphic or create a new one. Think of it as the framework taking the responsibility off you.
The size of components is often taken out of your hands. If you use a layout manager then it may decide to resize your component.
If you are coming from a procedural imperative background you may well have problems (I came from FORTRAN). My advice would be to try a number of tutorials and - at some stage - enlightenment will start to come.
The general documentation for Java graphics is poor. There are many concepts which are opaque (see How does Java Graphics.drawImage() work and what is the role of ImageObserver ). The early implementation was rushed through and had many bugs. Even now it is often unclear whether and in what order you should call methods such as setPack() and setVisible().
This doesn't mean you shouldn't use it! Just that the learning curve is a bit longer than IMO it should be.
MORE:
Also YOU don't decide when something is painted, the framework does. paint(g) really means "The framweork is repainting its components. What to you want this component to provide at this stage".
Maybe providePaintingInstructionsWhenRequiredForComponentGraphics(Graphics g) would be a useful name.
Similarly repaint() does not repaint at your orders, but when the system thinks it should. I haven't found it useful.
If you (say) resize a component interactively every slight change will normally trigger a paint(g). try putting a LOG.debug() in the paint code and seeing when it gets called.
What does this size mean? I have not added anything to the frame of size(200,90).
You added your component to the frame and set the size of the frame to be (200, 90). The default layout manager for the content pane of the frame is the BorderLayout, which means the component you added gets all the available space. The frame needs some space for the title bar and borders, so your component gets the remaining space.
The component does not create a static Graphics object association.
The graphics object is the wrapper for a platform handle giving access to a physical device, like the screen. It's valid for the time when "paint" is executed only, you can't store it and reuse it later. It is a resource managed by the "toolkit".
The component itself is an abstraction on top of the windowing system, that gets asociated shortly with this device for getting rendered.
EDIT
You can force such an association calling "getGraphics" if you feel the need to paint out of the "paint" callback. This should be a very rare case and you ALWAYS should dispose the Graphics afterwards.
Think of a Graphics like a piece of paper which you draw on to show how the Component looks like at that moment. After you've drawn it, the framework toolkit will trim off the edges and show what you've drawn to display the component. Moreover, the next time you draw the component, you'll be drawing on a different piece of paper, so don't keep the old Graphics around.

How to draw a JPanel on a canvas?

is there a possibility to draw a JPanel on a specific location op a Graphics (or Graphics2D) object?
I override the paint method of my canvas, and call panel.paint(g) in there, but it does not work the way I woul hope.
#Override
public void paint(Graphics g){
Dimension size = panel.getPreferredSize();
panel.setBounds(pos.x, pos.y, size.width, size.height);
panel.paint(g);
}
the size object is correctly defined as I would wish, so that's not the problem. Also, the pos contains a correct x and y on the screen.
You should probably be using paintComponent instead of paint, since the latter is the AWT method, and the former is the Swing method.
One nice thing about Swing's paintComponent is that the Graphics passed is actually always going to be a Graphics2D, so you can:
Graphics2D g = (Graphics2D)lg;
Now you can use the getTransform to save the old transform, then modify the transform of the Graphics2D using either setTranform or the scale, translate and rotate methods. Don't forget to restore the old transform, or you'll likely fudge the next thing being drawn by that context.
I'll throw in that, depending on the circumstance, drawing to a BufferedImage might be appropriate. You can get a Graphics context using BufferedImage.getGraphics(). Then you can draw the BufferedImage's context by whatever means suit you.

Categories

Resources