I am using paintComponent to make a fade-in opening. Though I can use transparent images to create this effect, I feel like drawing is both space conservative and efficient, but when I had tried to make code for it which is provided below
Graphics2D painter = (Graphics2D)g;
int paint = 0;
if (paint!=255) {
painter.setColor(new Color(0, 0, 0, paint));
paint+=17;
painter.drawImage(frm1,0,-16,768,576,null);
painter.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
The window starts with a white screen, later showing frm1
(the image that I want the opacity to overlay)
In the Frame's code, I tried typing the constructor (which contains the start to the game loop) after the frame.setVisible(true);
line of code, this affected the code in no way whatsoever. Even though I can use transparent images, I am trying to make the game more lightweight, therefore I would prefer paintComponent.
The code for the panel is provided below
package studios.masterpiece.pts.display;
//AWT
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
//IO
import java.io.IOException;
//ImageIO
import javax.imageio.ImageIO;
//Swing
import javax.swing.JPanel;
import javax.swing.Timer;
public class GameScene extends JPanel implements Runnable{
private static final long serialVersionUID = -1892599432299801189L;
Timer timer;
Graphics painter;
BufferedImage frm1;
Thread repeat;
//References
static int tileSize = 48;
static int rows = 16;
static int columns = 12;
public static int SCREEN_WIDTH = tileSize*rows; //768
public static int SCREEN_HEIGHT = tileSize*columns;
//GameScene Properties
public GameScene() {
this.setSize(SCREEN_WIDTH,SCREEN_HEIGHT);
this.setBackground(Color.BLACK);
this.setFocusable(true);
this.setDoubleBuffered(true);
startRepeat();
//Getting the image I want the opacity to overlay
try {
frm1 = ImageIO.read(getClass().getResourceAsStream("/studios/masterpiece/pts/animations/intro/Intro1.png"));
}
catch (IOException e) {e.printStackTrace();}
}
public void startRepeat() {
repeat = new Thread(this);
repeat.start();
//CURRENTLY DOES NOT WORK
timer = new Timer(250, new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
Timer timer = (Timer) event.getSource();
int opacity = this.getOpacity();
opacity += 15;
if (opacity < 255) {
this.setOpacity(opacity);
} else {
opacity = 255;
this.setOpacity(opacity);
timer.stop();
}
this.repaint();
}
});
timer.start();
//UNTIL HERE
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D painter = (Graphics2D)g;
this.painter=painter;
}
@Override
public void run() {
while (repeat!=null) {
repaint();
}
}
}
Here's an example of a fade-in GUI.
Here's the initial GUI:
Here's the GUI after the image is faded in:
So, How did I do this?
I created a JFrame
and a drawing JPanel
. I drew the background and the text using Color
instances with a specified opacity or alpha component.
I used a Swing Timer
to adjust the opacity every 250 milliseconds and repaint the drawing JPanel
.
Here's the complete runnable code. I made the additional class an inner class so I could post the code as one block.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class FadeInGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new FadeInGUI());
}
private final DrawingPanel drawingPanel;
public FadeInGUI() {
this.drawingPanel = new DrawingPanel();
}
@Override
public void run() {
JFrame frame = new JFrame("Fade In GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
Timer timer = new Timer(250, new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
Timer timer = (Timer) event.getSource();
int opacity = drawingPanel.getOpacity();
opacity += 15;
if (opacity < 255) {
drawingPanel.setOpacity(opacity);
} else {
opacity = 255;
drawingPanel.setOpacity(opacity);
timer.stop();
}
drawingPanel.repaint();
}
});
timer.start();
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private int opacity;
public DrawingPanel() {
this.opacity = 0;
this.setPreferredSize(new Dimension(640, 480));
}
public void setOpacity(int opacity) {
this.opacity = opacity;
}
public int getOpacity() {
return opacity;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Color backgroundColor = new Color(255, 255, 0, opacity);
Color textColor = new Color(0, 0, 255, opacity);
g.setColor(backgroundColor);
g.fillRect(0, 0, getWidth(), getHeight());
String text = "Amazing Game";
Font titleFont = getFont().deriveFont(Font.BOLD, 48f);
Rectangle r = new Rectangle(0, 0, getWidth(), getHeight() / 3);
drawCenteredString(g, text, r, textColor, titleFont);
text = "by Amazing Company";
Font subtitleFont = getFont().deriveFont(Font.BOLD, 32f);
r = new Rectangle(0, getHeight() * 2 / 3, getWidth(),
getHeight() / 3);
drawCenteredString(g, text, r, textColor, subtitleFont);
};
/**
* Draw a String centered in the middle of a Rectangle.
*
* @param g The Graphics instance.
* @param text The String to draw.
* @param rect The Rectangle to center the text in.
*/
private void drawCenteredString(Graphics g, String text, Rectangle rect,
Color color, Font font) {
FontMetrics metrics = g.getFontMetrics(font);
int x = rect.x + (rect.width - metrics.stringWidth(text)) / 2;
int y = rect.y + ((rect.height - metrics.getHeight()) / 2)
+ metrics.getAscent();
g.setFont(font);
g.setColor(color);
g.drawString(text, x, y);
}
}
}