I'm currently making Mario as a school graphics project.
I have most of the collisions done, but I just want the land and bricks to actually look like land and bricks instead of just colored rectangles. I have an ImageIcon for the "land" in my graphics project. The problem is that it is only 16x16 pixels large. In order to make enough land by just making each part of the land one 16x16 pixel, it would essentially be horribly inefficient.
I was wondering if I could get the ImageIcon or possibly buffered image and use it as the "color" for a rectangle to make the chunks of land easier. If that's not possible, can you offer other suggestions on how to go about this problem?
Using a background of tiled images, a texture:
private BufferedImage image;
URL url = getClass().getResource("/mytexture.png");
assert url != null;
image = ImageIO.read(url);
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Rectangle rect = new Rectangle(0, 0, width, height);
Rectangle textureRect = new Rectangle(0, 0, image.getWidth(), image.getHeight());
TexturePaint paint = new TexturePaint(image, textureRect);
g2.setPaint(paint);
g2.fill(rect);
}
In general create your own JPanel.
Gimp and other tools allow to create a tilable image by ensuring that a line running to a border will enter at the opposite border.
So in this block of code, a 40x40 square can move across a window by calling directional methods, and I'm trying to get a spaceship to appear instead of the square. No matter what I try, it just isn't working.
public void paintComponent (Graphics g) {
ImageIcon wallpaper = new ImageIcon("images/JGalagawallpaper.png");
image = wallpaper.getImage();
g.drawImage(image, 400, 400, null);
ImageIcon ship = new ImageIcon("images/galaga.png");
galaga = ship.getImage();
super.paintComponent(g);
Graphics2D graphic = (Graphics2D) g;
graphic.fill(new Rectangle.Double(x, y, 40, 40));
//graphic.drawImage(galaga, x, y, 40, 40);
}
My question is, how do I get that thing to appear? I already tried tinkering with graphic.drawImage, however that didn't really work out as well as I hoped. That's what the commented out code is.
g.drawImage(image, 400, 400, null);
First you draw the image.
super.paintComponent(g);
Then you invoke the above code which is used to pint the background color of the panel, thus overwriting the image. The above statement should be the first statement of the painting method.
ImageIcon wallpaper = new ImageIcon("images/JGalagawallpaper.png");
A painting method is for painting only. Don't do I/O in the method. The image should be read in the constructor of your class so that it is only read once, not every time the component is repainted.
You also need to look at the coordinates of where you paint the image. Maybe the panel is not that big?
Did you verify that the image was read properly by display its size?
I have a method that creates shadows based on where things are on the screen and the final product of that method is an Area, which I then draw onto the screen and it contains all shadows on screen in the same Area. This is because the drawn shadows are a low opacity so if it is not all one thing they will overlap and the opacity will make it look weird.
The issue that I want the shadows to look like they fade out, but I have absolutely no idea how, or if that would even be possible. Is there a way to soften the edges of the Area or make them gradient fade out? I tried to do graphics2D.setPaint(new GradientPaint[a gradient effect]) but it did nothing.
Thanks in advance
EDIT: Here is a screenshot of the program making a shadow around a 'building' rectangle. The green rectangle is to show the effect of the shadow. The end result I want is instead of the shadow abruptly ending, it should fade out.
i guess you have problems setting up the proper colors for the gradient:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(30, 30, 50, 20);
Graphics2D g2d = (Graphics2D) g;
Polygon p = new Polygon(new int[]{10,20,50,50,40,10}, new int[]{10,10,40,50,50,20}, 6);
Area a = new Area(p);
Color b = new Color(0xFF000000, true); //using colors with transparency!!!
Color w = new Color(0x00FFFFFF, true); //using colors with transparency!!!
//try to use proper values for the x/y values - both, start and end
GradientPaint gradient = new GradientPaint(0, 0, b, 40, 40, w);
g2d.setPaint(gradient);
g2d.fill(a); // fill your area!
}
result is a gradient with alpha (Transparency) ...
Area drawn in red <==> Area drawn with Gradient
don't forget to set the alpha value 0xAARRGGBB to FF for 100% opaque (0xFF000000 is black 100%opaque) to 0 (0x00FFFFFF white, 100% transparent)
I have an off-screen BufferedImage, constructed with the type BufferedImage.TYPE_INT_ARGB. It can contain anything, and I'm looking for a way to (fairly efficiently) completely overwrite the image with transparent pixels, resulting in an 'invisible' image.
Using something like this:
(bufimg.getGraphics()).setColor(new Color(10, 10, 100, 0));
(bufimg.getGraphics()).fillRect (0, 0, x, y);
Has no effect. One possible method might be just to write over every pixel in the BufferedImage, but I'm not sure this is the best solution. How would you do it?
[edit]
The Graphics documentation advises against using clearRect for off-screen images, but I have tried it with the same results as above.
[edit2]
After experimenting with MeBigFatGuy's code (thanks!), it does clear an image. But it also stops further painting to that image (or appears to). This code for example:
BufferedImage img = new BufferedImage (600, 600, BufferedImage.TYPE_INT_ARGB);
Graphics g = img.createGraphics ()
g.drawLine (100, 100, 500, 500);
AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f);
g.setComposite(composite);
g.setColor(new Color(0, 0, 0, 0));
g.fillRect(0, 0, 600, 600);
graphicsAI.setColor(new Color (10, 10, 10, 255));
graphicsAI.drawLine (100, 100, 500, 500);
Results in nothing seen on the image (I'm drawing the image to a JPanel). Is this something to do with the addition of alpha values?
After you clear the background with the CLEAR composite, you need to set it back to SRC_OVER to draw normally again. ex:
//clear
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
g2.fillRect(0,0,256,256);
//reset composite
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
//draw
g2.setPaint(Color.RED);
g2.fillOval(50,50,100,100);
You could get the underlying int[] array of your BufferedImage (make sure to use a compatible format: that is, one that is backed by an int[]).
Then fill the int[] with ints whose alpha value are 0 (0 will do ; )
A System.arraycopy will be very fast.
You have to know that directly writing in the int[] is a lot faster than using setRGB.
Now BufferedImage are a bit of a black art in Java: depending on what you're doing and on which platform/JVM you're doing it, you may lose hardware acceleration (which may never have been there in the first place anyway). In addition to that, you may very well not care at all about hardware acceleration anyway because you may not be working on, say, a game requiring 60+ FPS to be playable etc.
This is a very complicated topic and there's more than one way to skin the BufferedImage cat. As far as I'm concerned I work directly in the int[] when I've got to mess at the pixel level because I think it makes much more sense than trying to use higher-level drawing primitives and I do really don't care about the potential lost of hardware acceleration.
If you cast the Graphics object to a Graphics2D object, you can set a Composite object thru
AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setComposite(composite);
g2d.setColor(new Color(0, 0, 0, 0));
g2d.fillRect(0, 0, 10, 10);
For the sake of completeness, here is a working, testing, and fast function that is cross-platform compliant.
static public BufferedImage createTransparentBufferedImage(int width, int height) {
// BufferedImage is actually already transparent on my system, but that isn't
// guaranteed across platforms.
BufferedImage bufferedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = bufferedImage.createGraphics();
// To be sure, we use clearRect, which will (unlike fillRect) totally replace
// the current pixels with the desired color, even if it's fully transparent.
graphics.setBackground(new Color(0, true));
graphics.clearRect(0, 0, width, height);
graphics.dispose();
return bufferedImage;
}
Despite you saying it doesn't work, I used clearRect quite fine.
Clears the specified rectangle by filling it with the background color
of the current drawing surface. This operation does not use the
current paint mode.
Beginning with Java 1.1, the background color of offscreen images may
be system dependent. Applications should use setColor followed by
fillRect to ensure that an offscreen image is cleared to a specific
color.
Fills the specified rectangle. The left and right edges of the
rectangle are at x and x + width - 1. The top and bottom edges are at
y and y + height - 1. The resulting rectangle covers an area width
pixels wide by height pixels tall. The rectangle is filled using the
graphics context's current color.
It is not clearly stated here that one will set the rectangle to the background color, while the other will paint with the foreground color on top of the current colors, but it's what it seems to do.
This is pure speculation, but I think the note about offscreen images relates to Graphics objects obtained from offscreen AWT components, as they are native. I can hardly imagine how the background color of a BufferedImage could be system dependent. As the API doc is for Graphics, this could be a generalization not applying to the BufferedImage case.
My testing code:
JFrame jf = new JFrame();
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BufferedImage img = new BufferedImage(200, 300, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = img.createGraphics();
//fill right half with opaque white
g.setColor(Color.WHITE);
g.fillRect(100, 0, 100, 300);
//leave top third as it is
//fill middle third with transparent color
g.setColor(new Color(0, true));
g.fillRect(0, 100, 200, 100);
//clear bottom third with transparent color
g.setBackground(new Color(0, true));
g.clearRect(0, 200, 200, 100);
g.dispose();
jf.add(new JLabel(new ImageIcon(img)));
jf.pack();
jf.setVisible(true);
the result is two white squares, top right. Where no white was painted, or clearRect was used to overwrite the white, the result is a light gray, the frame's default background color.
Performance-wise, it's regular drawing. arraycopy might well be faster, I don't know, but at least this is likely hardware accelerated just as any other drawing operation.
A plus point versus the array solution is a) no additional memory and b) independence from the color model; this should work no matter how the image was set up.
A minus point versus the Composite solution is that it only allows clearing rectangles; setting the composite allows you to clear any kind of shape.
Setting the background of the graphics Object seems to do the job:
g.setBackground(new Color(0, 0, 0, 0));
(at least when drawing images for scaling purposes)
I have a String and I want to paint it onto an image. I am able to paint points and draw lines, however, even after reading the Text part of the 2D Graphics tutorial, I can't figure out how I can take a String and paint it onto my drawing.
Unless I'm looking at the wrong tutorial (but it's the one I get whenever I search for anything about Java and painting Strings using Graphics or Graphics2D), I'm still stumped.
Check out the following method.
g.drawString();
The drawString() method will do what you need.
An example use:
protected void paintComponent(Graphics g){
g.setColor(Color.BLACK);
g.drawString(5, 40, "Hello World!");
}
Just remember, the coordinates are regarding the bottom left of the String you are drawing.
if you want to play with the shape of your string (eg: fill:red and stroke:blue):
Graphics2D yourGraphicsContext=(...);
Font f= new Font("Dialog",Font.PLAIN,14);
FontRenderContext frc = yourGraphicsContext.getFontRenderContext();
TextLayout tl = new TextLayout(e.getTextContent(), f, frc);
Shape shape= tl.getOutline(null);
//here, you can move your shape with AffineTransform (...)
yourGraphicsContext.setColor(Color.RED);
yourGraphicsContext.fill(shape);
yourGraphicsContext.setColor(Color.BLUE);
yourGraphicsContext.draw(shape);