In java how can you make a game fully realizable! But so logic and graphics can work with it? I have tried using SCALE methods. But this doesn't allow perfect full-screen for every computer. So I made this:
public void resize(int WIDTH, int HEIGHT, boolean UNDECORATED) {
frame.setPreferredSize(new Dimension(WIDTH, HEIGHT));
frame.setMaximumSize(new Dimension(WIDTH, HEIGHT));
frame.setMinimumSize(new Dimension(WIDTH, HEIGHT));
this.WIDTH = WIDTH;
this.HEIGHT = HEIGHT;
frame.setUndecorated(UNDECORATED);
frame.setSize(WIDTH, HEIGHT);
}
So you can set your screen size to whatever you want! It works but the graphics will not work with it? Is there a way in Graphics2D to stretch all the graphics so it fits? For example if there was a method that existed like:
G2D.resize(WIDTH, HEIGHT, Image.NEAREST_PARENT_RESCALE);
Any idea?
Things I have tried:
- Drawing all graphics to a Buffered-image then drawing that Image onto the screen size.
- Just using SCALE and doing WIDTH * SCALE etc.
- Lots of math
Things I do not mind
- If you have a WIDE-SCREEN it stretches graphic2D objects to the size.
- If you have a SQUARE-SCREEN it squishes graphics2D objects to the size.
So how can I make a perfectly resealable game using Graphics2D, JFrame.
If I understood you correctly all you want is to draw your graphics in different resolutions without removing or adding any content.
Well one of the "things you have tried" can do that.
Drawing to a fixed size
BufferedImage
will ensure that all your components are visible within thatBufferedImage
(assuming you draw them correctly and relative to it's fixed size) then you can just draw the image to your flexible size screen.Here's a full runnable code example that does that:
This is only a quick implementation there are things that can be done better in that code bu you get the picture. Hope this helps.
In the most generic form, one can consider this as a classical problem of graphics programming, namely, as the transformation from world coordinates to screen coordinates. You have an object that has a size of "1.0 x 1.0" in your world coordinate system (regardless of which unit this has). And this object should be painted so that it has a size of, for example, "600 pixels * 600 pixels" on the screen.
Broadly speaking, there are at least three options to achieve this in Swing:
Graphics2D
objectEach of this has possible advantages and disadvantages, and hidden caveats.
Drawing into an image, and drawing a scaled version of the image:
This might look like a simple solution, but has a potential drawback: The image itself has a certain resolution (size). If the image is too small, and you are scaling it up to fill the screen, it may appear blocky. If the image is too large, and you are scaling it down to fit into the screen, pixels of the image may be lost.
In both cases, there are several tuning parameters for the process of scaling the image. In fact, scaling an image is far more tricky than it looks at the first glance. For details, one may refer to the article The Perils of Image.getScaledInstance() by Chris Campbell.
Drawing into a scaled
Graphics2D
objectThe
Graphics2D
class already offers the full functionality that is necessary to create the transformation between the world coordinate system and the screen coordinate system. This is accomplished by theGraphics2D
class by internally storing anAffineTransform
, which describes this transformation. ThisAffineTransform
may be modified directly via theGraphics2D
object:Some care has to be taken to properly manage the transform that is stored in the
Graphics2D
object. In general, one should create a backup of the originalAffineTransform
before applying additional transformations, and restore this original transform afterwards:(Another advice for the last method: The
Graphics2D#setTransform
method should never be used to apply a new coordinate transform on top of an existing transform. It is solely intended for restoring an "old" transform, as shown in this example (and in the documentation of this method)).One potential drawback of scaling with the
Graphics2D
class is that afterwards, everything will be scaled. Particularly, this scaling will also affect line widths (that is, the width of the Stroke). For example, consider a sequence of calls like this one:The second call will cause a line to be drawn that is 10 pixels wide. This may not be desired in many cases. This effect can be avoided with the third alternative:
Drawing scaled objects
The transformation between the world coordinate system and the screen coordinate system can also be maintained manually. It is convenient to represent this as an
AffineTransform
. TheAffineTransform
class can be used to create transformed versions ofShape
object, that can then be drawn directly into an (un-transformed)Graphics2D
object. This is accomplished with theAffineTransform#createTransformedShape
method:This is probably the most versatile approach. The only potential drawback is that, when many small, simple shapes are drawn, this will cause many, small temporary transformed shapes to be created, which may cause reduced performance. (There are ways to alleviate this problem, but detailed performance considerations and optimizations are beyond the scope of this answer).
Summary
The follwing image shows the comparison of all approaches. Some example objects (represented as
Shape
objects) are drawn. Each row compares the three different scaling methods mentioned above. With their "default" size, the objects fill a rectangle in world coordinates that has a size of 100x100. In the first two rows, they are scaled up to fill an area on the screen of 190x190 pixels. In the last two rows, they are scaled down to fill an area on the screen of 60x60 pixels. (These sizes have been chosen in order to have some "odd" scaling factors of 1.9 and 0.6. Certain effects (artifacts) may not appear when the scaling factors are whole numbers, or exactly 0.5, for example).For the upscaling and the downscaling, there additionally is a comparison between the "standard" way of painting, and "high quality" painting (indicated by the "(HQ)" in the title of each panel). The "high quality" here simply means that the rendering hints
have been set:
Here is the corresponding program, as an MCVE:
This is actually quite easy in Java. In a
Graphics2d
environment, the logical coordinate system (the coordinates you use in the drawing routines) and the physical coordinate system (the coordinates as they appear) on the screen are completely unrelated. Every time you draw onto aGraphics2d
object, the logical coordinates are first translated to the physical coordinates by anAffineTransform
object, and thisAffineTransform
object can be modified. For this you can use theGraphics2D.scale(double,double)
,Graphics2D.rotate(double)
,Graphics2D.translate(double,double)
andGraphics2D.shear(double,double)
methods.So if you first call
then all your graphics that you subsequently draw will be twice as large in both directions.