I need to have an array of backgrounds? - java

In my side-scroller, I want to have 3 backgrounds that keep looping. Whenever you get through a stage it calls the function nextStage() that sends you to the next background. In the class:
package com.erikbalen.game.rpg;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class World extends JPanel implements ActionListener{
/**
*
*/
private static final long serialVersionUID = 2834816426699432121L;
Player p1;
Image background;
Timer time;
public World() {
p1 = new Dps();
addKeyListener(new AL());
setFocusable(true);
ImageIcon icon = new ImageIcon("C:\\Program Files (x86)\\EriksRPG\\Images\\Backgrounds\\background.png");
background = icon.getImage();
time = new Timer(5, this);
time.start();
}
public void actionPerformed(ActionEvent e) {
p1.move();
repaint();
}
public void paint(Graphics g) {
super.paint(g);
Graphics g2d = (Graphics2D) g;
g2d.drawImage(background, 0, 0, null);
g2d.drawImage(p1.getImage(), p1.getX(), p1.getY(), null);
}
private class AL extends KeyAdapter {
public void keyReleased(KeyEvent e) {
p1.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
p1.keyPressed(e);
}
}
}
Basically I want to know how I can make an array of images called backgrounds, load those three files, and make a method called nextStage() that loads background[stage] and if stage > 2 stage = 0

one possible solution:
make "background" an array of 3 elements
Image[] background = new Image[3];
load the three background images one at a time into background[0], background[1] and background[2].
create a new private variable, perhaps called stage, and increment when advancing:
private int stage = 0;
public void nextStage() { stage++; }
finally, in paint(), draw the background you want, according to the value of stage:
g2d.drawImage(background[stage % 3], 0, 0, null);

Related

How to refresh graphics of a Window class in Java

I'm trying to draw over a vlcj (java binding of the VLC library) panel so that I can play a video and draw over it. And I have encounter some issues. Here is the full base code:
Code-listing 1: AppOverlay.java
package app;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.HeadlessException;
import java.awt.Window;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import com.sun.jna.platform.WindowUtils;
#SuppressWarnings("serial")
public class AppOverlay extends Window implements Runnable {
private final boolean isRunning;
private final int fps;
private BufferedImage graphics;
private BufferedImage img;
private int x, y;
private boolean ltr;
public AppOverlay(Window owner) {
super(owner, WindowUtils.getAlphaCompatibleGraphicsConfiguration());
setBackground(new Color(0,0,0,0));
graphics = new BufferedImage(1280,800, BufferedImage.TYPE_INT_ARGB);
isRunning = true;
img = null;
ltr = true;
fps = 60;
x = 0;
y = 0;
}
#Override
public void run(){
while(isRunning){
try{
Thread.sleep(1000/fps);
} catch(InterruptedException e){
e.printStackTrace();
}
if(ltr) {
if(x < 1280) x++;
else ltr = false;
} else {
if(x < 0) ltr = true;
else x--;
}
repaint();
}
}
public void createAndShowGUI() {
setVisible(true);
Thread thread = new Thread(this);
thread.start();
String path = "Drive:\\path\\to\\image.png";
try {
img = ImageIO.read(new java.io.FileInputStream(path));
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
Graphics2D gfx = graphics.createGraphics();
gfx.setColor(new Color(255,255,255,0));
gfx.clearRect(0, 0, 1280, 800);
if(img != null) gfx.drawImage(img, x, y, null);
gfx.dispose();
g2d.drawImage(graphics, 0, 0, null);
}
}
Code-listing 2: AppPlayer.java
package app;
import uk.co.caprica.vlcj.player.component.EmbeddedMediaPlayerComponent;
#SuppressWarnings("serial")
public class AppPlayer extends EmbeddedMediaPlayerComponent {
}
Code-listing 3: AppFrame.java
package app;
import java.awt.Dimension;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class AppFrame extends JFrame {
private AppPlayer appPlayer;
private AppOverlay overlay;
public AppFrame(){
super();
}
public void createAndShowGUI() {
appPlayer = new AppPlayer();
appPlayer.setPreferredSize(new Dimension(1280,800));
getContentPane().add(appPlayer);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("App");
setVisible(true);
pack();
overlay = new AppOverlay(this);
appPlayer.mediaPlayer().overlay().set(overlay);
appPlayer.mediaPlayer().overlay().enable(true);
overlay.createAndShowGUI();
}
}
Code-listing 4: Main.java
package main;
import javax.swing.SwingUtilities;
import app.AppFrame;
public class Main {
public static void main(String[] args) {
final AppFrame app = new AppFrame();
SwingUtilities.invokeLater( new Runnable() {
#Override
public void run() {
app.createAndShowGUI();
}
});
}
}
with that and the vlcj-4 library you should be able to test my code yourself. My issue is that the Overlay (AppOverlay class that extends the Window class) doesn't display or refresh the animation unless I deselect the window (I click on another window or on the desktop or the OS toolbar) so that the window (application) is inactive then select the window (the application) again. It will only load one frame and that's it. I have to deselect and reselect the window again for it to load another frame (this is only the case for the Overlay i.e. if I play a video in the AppPlayer class the video will be playing just fine.
What I want is to be able to draw some animated graphics on the overlay. I know that with the JPanel class there is the paintComponent() method but the Window class doesn't have that method (only the paint() and repaint() methods are available).
What should I do to fix this?
EDIT:
I tried adding a JPanel on which I draw instead of drawing directly on the AppOverlay
Code-listing 5: AppPanel.java
package app;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class AppPanel extends JPanel implements Runnable {
private int x, y;
private boolean ltr;
public AppPanel() {
x = 0;
y = 0;
ltr = true;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(new Color(0,0,0,0));
g.clearRect(0, 0, 1280, 800);
g.setColor(Color.RED);
g.fillRect(x, y, 100, 100);
}
#Override
public void run() {
while(true){
try{
Thread.sleep(1000/60);
} catch(InterruptedException e){
e.printStackTrace();
}
if(ltr) {
if(x < 1280) x++;
else ltr = false;
} else {
if(x < 0) ltr = true;
else x--;
}
repaint();
}
}
}
then adding it to the AppOverlay.
Code-listing 6: AppOverlay.java with partial modification
public class AppOverlay extends Window implements Runnable {
//previous field declaration above ...
AppPanel panel;
AppPlayer player = null;
public AppOverlay(Window owner) {
//previous constructor instructions above...
panel = new AppPanel();
add(panel);
}
public void createAndShowGUI(AppPlayer player) {
setVisible(true);
/*
Thread thread = new Thread(this);
thread.start();
String path = "Drive:\\path\\to\\image.png";
try {
img = ImageIO.read(new java.io.FileInputStream(path));
} catch (IOException e) {
e.printStackTrace();
}
*/
Thread panelThread = new Thread(panel);
panelThread.start();
}
}
Doing this will display the graphics of the JPanel and animate them as needed.
If you know a way to make the JPanel background transparent (so that we can see through it) while still letting it display its graphics. That would solve the issue for sure.
I played around a bit with your example and came up with something working, but I wouldn't call it a nice solution.
The main issue seems to be that there is no way to tell the overlay to refresh (or I just have not found it). Just repainting the overlay does not update it on screen, so the workaround I used is to hide and show it again.
For the timeing of the update interval I used a javax.swing.Timer.
(In a real version you probably want to start and stop the timer via the MediaPlayerEventListener).
As a side effect the repaint method is called and the x coordinate is adjusted to move the image around the screen.
In the simplified example below (use your main to run it), I moved a red rectangle with the x coordinate instead of some unknown image.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.Timer;
import com.sun.jna.platform.WindowUtils;
import uk.co.caprica.vlcj.player.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.player.embedded.OverlayApi;
public class AppFrame extends JFrame {
private static final long serialVersionUID = -1569823648323129877L;
public class Overlay extends Window {
private static final long serialVersionUID = 8337750467830040964L;
private int x, y;
private boolean ltr = true;
public Overlay(Window owner) throws HeadlessException {
super(owner, WindowUtils.getAlphaCompatibleGraphicsConfiguration());
setBackground(new Color(0,0,0,0));
}
#Override
public void paint(Graphics g) {
super.paint(g);
if (ltr) {
if (x < 1180)
x += 1;
else
ltr = false;
} else {
if (x < 0)
ltr = true;
else
x -= 1;
}
g.setColor(Color.RED);
g.fillRect(x, y, 100, 100);
String s = Integer.toString(x);
g.setColor(Color.WHITE);
g.drawChars(s.toCharArray(), 0, s.length(), x+10, y+50);
}
}
private EmbeddedMediaPlayerComponent appPlayer;
public void createAndShowGUI() {
appPlayer = new EmbeddedMediaPlayerComponent();
appPlayer.setPreferredSize(new Dimension(1280, 800));
getContentPane().add(appPlayer);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("App");
setVisible(true);
pack();
Overlay overlay = new Overlay(this);
OverlayApi api = appPlayer.mediaPlayer().overlay();
api.set(overlay);
api.enable(true);
//appPlayer.mediaPlayer().media().play(" ... ");
Timer timer = new Timer(0, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
api.enable(false);
api.enable(true);
}
});
timer.setRepeats(true);
timer.setDelay(200);
timer.start();
}
}
If that is an option for you, it might be far easier to use an animated gif instead. At least that is working on its own (no need for the Timer).
Update:
As you figured out using a JPanel seems to work better.
Just use setOpaque(false) to make it transparent.
Here an adjusted example.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import uk.co.caprica.vlcj.player.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.player.embedded.OverlayApi;
public class AppFrame2 extends JFrame {
private static final long serialVersionUID = -1569823648323129877L;
public class OverlayPanel extends JPanel {
private static final long serialVersionUID = 8070414617530302145L;
private int x, y;
private boolean ltr = true;
public OverlayPanel() {
this.setOpaque(false);
}
#Override
public void paint(Graphics g) {
super.paint(g);
if (ltr) {
if (x < 1180)
x += 1;
else
ltr = false;
} else {
if (x < 0)
ltr = true;
else
x -= 1;
}
g.setColor(Color.RED);
g.fillRect(x, y, 100, 100);
String s = Integer.toString(x);
g.setColor(Color.WHITE);
g.drawChars(s.toCharArray(), 0, s.length(), x+10, y+50);
}
}
public class Overlay extends Window {
private static final long serialVersionUID = 8337750467830040964L;
OverlayPanel panel;
public Overlay(Window owner) throws HeadlessException {
super(owner);
setBackground(new Color(0,0,0,0));
panel = new OverlayPanel();
this.add(panel);
}
}
private EmbeddedMediaPlayerComponent appPlayer;
public void createAndShowGUI() {
appPlayer = new EmbeddedMediaPlayerComponent();
appPlayer.setPreferredSize(new Dimension(1280, 800));
getContentPane().add(appPlayer);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("App");
setVisible(true);
pack();
Overlay overlay = new Overlay(this);
OverlayApi api = appPlayer.mediaPlayer().overlay();
api.set(overlay);
api.enable(true);
//appPlayer.mediaPlayer().media().play(" ... ");
Timer timer = new Timer(0, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
overlay.panel.repaint();
}
});
timer.setRepeats(true);
timer.setDelay(17);
timer.start();
}
}
You have already done the bulk of the work. Simply repaint the frame every time you draw over it by calling app.repaint();
You can use the following methods from JComponent: ( http://download.oracle.com/javase/6/docs/api/javax/swing/JComponent.html )
void repaint(long tm, int x, int y, int width, int height)
//**Adds the specified region to the dirty region list if the component is showing.*//
void repaint(Rectangle r)
/**Adds the specified region to the dirty region list if the component is showing.*//
You can call those before redraw()

BufferStrategy cleans Frame background

I have tried to make a simple GUI in Java Using graphics2D and JFrame.
I have added a background-color on JFrame typing this.setBackground(new Color(54, 71, 99)) inside initWindow() method. It turned out that backBuffer was clearing that background and not repainting the line that causes this is in render() method, last line backBuffer.show().
How Do I make it NOT clear the main background?
package asteroids;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
public class Main extends Canvas implements KeyListener {
private boolean gameOver;
private BufferStrategy backBuffer;
private Dimension dimension = new Dimension(Config.WINDOW_WH[0], Config.WINDOW_WH[1]);
private List<Star> stars = new ArrayList<Star>();
private HashMap<Integer,Boolean> keyDownMap = new HashMap<Integer, Boolean>();
public Main() {
// Initialize Window
initWindow();
addKeyListener(this);
this.setBackground(new Color(54, 71, 99));
this.createBufferStrategy(2);
backBuffer = this.getBufferStrategy();
// init variables
gameOver = false;
// Generating stars
generateStars();
// Init loop
gameLoop();
}
public void initWindow(){
JFrame window = new JFrame("Asteroids");
setPreferredSize(dimension);
window.add(this);
window.pack();
window.setResizable(false);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBackground(new Color(54, 71, 99));
window.requestFocus();
}
public void update() {
if(keyDownMap.containsKey(KeyEvent.VK_ESCAPE)){
gameOver = false;
System.exit(0);
}
}
public void render(){
Graphics2D g = (Graphics2D) backBuffer.getDrawGraphics();
g.setColor(Color.WHITE);
for(Star s: stars) {
g.fillOval(s.posx - (s.width/2), s.posy - (s.height/2), s.width, s.height);
}
g.dispose();
backBuffer.show();
}
public void generateStars() {
for(int i = 0;i < 20;i++) {
int starX = new Random().nextInt(Config.WINDOW_WH[0]-10)+5;
int starY = new Random().nextInt(Config.WINDOW_WH[1]-10)+5;
stars.add(new Star(starX, starY));
}
}
public void gameLoop(){
while(!gameOver){
update();
render();
try{ Thread.sleep(20);}catch(Exception e){};
}
}
public static void main(String[] args) {
new Main();
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
keyDownMap.put(e.getKeyCode(), true);
}
#Override
public void keyReleased(KeyEvent e) {
keyDownMap.remove(e.getKeyCode());
}
}
How Do I make it NOT clear the main background?
You can't. Apart from Canvas been non-transparent (which can't be changed), BufferStrategy also has more then one page onto which it paints it's content (thus allowing to perform page flipping). Combined, this would make it impossible to maintain the background of the parent container.
Instead, you should (in fact, you must) clear the Graphics context of the buffer you painting to do, every time render is called, otherwise you will be painting onto what ever was previously painted on to it.
One technique might be to generate a BufferedImage with the "static" content and simply paint that to the buffer first

Java issues with all my color changing and the drawing not starting when I click

I am having an issue figuring out why my code isn't working for when I click to turn the drawing on/off. It should start as off initially but it doesn't. I also have an issue with my arraylist where I am not sure how to make it so that all the colors don't change when I click on a new color. This is my code so far, any help would be much appreciated.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import java.awt.event.MouseMotionAdapter;
public class Draw extends JPanel {
private Point startPoint, endPoint;
private ArrayList<Point> pointList;
private JButton clear;
private JRadioButton red, yellow, blue, eraser;
private boolean clicked;
private final static int SIZE = 30;
public Draw() {
// set the background color
setBackground(Color.WHITE);
// set starting point and end point of mouse click
startPoint = null;
endPoint = null;
this.addMouseListener(new MyMouseListener());
this.addMouseMotionListener(new MyMouseListener());
clicked = false;
pointList = new ArrayList<Point>();
this.addMouseMotionListener(new MyMouseListener());
clear = new JButton("Clear Drawing");
this.add(clear);
clear.addActionListener(new ButtonListener());
red = new JRadioButton("Red", true);
this.add(red);
red.addActionListener(new OptionListener());
yellow = new JRadioButton("Yellow", false);
this.add(yellow);
yellow.addActionListener(new OptionListener());
blue = new JRadioButton("Blue", false);
this.add(blue);
blue.addActionListener(new OptionListener());
eraser = new JRadioButton("Eraser",false);
this.add(eraser);
eraser.addActionListener(new OptionListener());
ButtonGroup group = new ButtonGroup();
group.add(red);
group.add(yellow);
group.add(blue);
group.add(eraser);
}
private class OptionListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
repaint();
}
}
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
if (event.getSource() == clear) {
pointList.clear();
repaint();
} else {
repaint();
}
}
}
private class MyMouseListener extends MouseAdapter {
#Override
public void mouseClicked(MouseEvent event) {
if (clicked) {
pointList = new ArrayList<Point>();
pointList.add(event.getPoint());
endPoint = null;
} else {
endPoint = event.getPoint();
startPoint = null;
}
clicked = !clicked;
repaint();
}
#Override
public void mouseMoved(MouseEvent event) {
pointList.add(event.getPoint());
repaint();
}
}
#Override
public void paintComponent(Graphics pen) {
super.paintComponent(pen);
Graphics2D g2 = (Graphics2D) pen;
for (Point p : pointList) {
if (red.isSelected()) {
g2.setColor(Color.RED);
g2.fill(new Ellipse2D.Double(p.getX(), p.getY(), SIZE, SIZE));
} else if (yellow.isSelected()) {
g2.setColor(Color.YELLOW);
g2.fill(new Ellipse2D.Double(p.getX(), p.getY(), SIZE, SIZE));
} else if (blue.isSelected()) {
g2.setColor(Color.BLUE);
g2.fill(new Ellipse2D.Double(p.getX(), p.getY(), SIZE, SIZE));
} else {
}
}
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Drawing Time");
frame.setSize(500, 500);
// create an object of your class
Draw panel = new Draw();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
I also have an issue with my arraylist where I am not sure how to make it so that all the colors dont change when I click on a new color
There are two ways to do custom painting:
paint to a BufferedImage. Using this approach the object is painted and the currently selected color will be used to paint the object
(the approach you are using) - store the object you want to paint in an ArrayList. The problem is you are only storing the Point objects in the list so all Points get repainted with the same color. If you want each Point to have a different Color, then you need to store a custom Object that contains both the Color and the Point.
Check out Custom Painting Approaches for working examples of both of these approaches.
You need to associate the Color with each individual object that you paint.

java pick random images

English is not my native language, sorry for any mistakes. I have to make a Bubble Shooter game in Java. I want to use images for the bubbles and I want the images to be picked randomly. I used Random and ImageIcon classes. My program doesn't show anything when I compile it and I don't know where the problem is. I'm a beginner in Java.
This is the code for my Game class:
import java.awt.Graphics;
import java.awt.Image;
import java.util.Vector;
import javax.swing.JPanel;
public class Game extends JPanel{
private static final long serialVersionUID = 1L;
//what the balls are like
public final static int START_BALLS=40;
public static Vector<Ball> balls = new Vector<Ball>();
private Image img;
private Graphics graphics;
public Game() {
for(int i=0; i<START_BALLS; i++) {
balls.add(new Ball());
}
}
public void paint(Graphics g) {
img = createImage(null);
graphics = img.getGraphics();
paintComponent(graphics);
g.drawImage(img, 0, 0, null);
repaint();
}
public void paintComponet(Graphics g) {
for(int i=0; i<balls.size(); i++) {
Ball b=(Ball)balls.get(i);
b.draw(g);
}
}
public static void main(String [] args) {
new Frame();
Game game = new Game();
new Game();
Window.window.add(game);
}
}
and the class for the bubbles:
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.util.Random;
import javax.swing.ImageIcon;
public class Ball {
Random random = new Random();
final String[] image_paths = new String[] {"balls/peg_0.png",
"balls/peg_1.png","balls/peg_2.png","balls/peg_3.png",
"balls/peg_4.png","balls/peg_5.png"};
String randomBalls;
public Image image;
public Ball(){
randomBalls = image_paths[random.nextInt(image_paths.length)];
ImageIcon poza = new ImageIcon(randomBalls);
image=poza.getImage();
}
public void draw(Graphics g){
g.drawImage(image, 0, 0, null, null);
}
}
What is wrong with my program?
Look over my comments, look carefully at the comments in the code, see how I rearranged the organization of the classes.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.Random;
import java.util.Vector;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.imageio.ImageIO;
import java.net.URL;
public class Game extends JPanel {
Random random = new Random();
final String[] image_path = new String[]{
"http://i.stack.imgur.com/gJmeJ.png",
"http://i.stack.imgur.com/IHARa.png",
"http://i.stack.imgur.com/wCF8S.png",
"http://i.stack.imgur.com/T5uTa.png"
};
private static final long serialVersionUID = 1L;
//what the balls are like
public final static int START_BALLS = 40;
public static Vector<Ball> balls = new Vector<Ball>();
private Image img;
// A Graphics instance is typically transient.
// There is rarely, if ever, a need to store them
//private Graphics graphics;
public Game() {
for (int i = 0; i < image_path.length; i++) {
balls.add(new Ball(image_path[i]));
}
//I have no idea what you were trying to achieve here, but it fails horribly
// img = createImage(null);
img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
// graphics = img.getGraphics();
ActionListener al = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
};
Timer timer = new Timer(400, al);
timer.start();
}
#Override // very handy!
public void paintComponent(Graphics g) {
super.paintComponent(g);
// g.drawImage(img, 0, 0, null); A JPanel IS A ImageObserver
g.drawImage(img, 0, 0, this);
Ball b = (Ball) balls.get(random.nextInt(4));
b.draw(g);
}
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("Game");
f.add(new Game());
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See https://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
class Ball {
String randomBalls;
public Image image;
public Ball(String url) {
try {
image = ImageIO.read(new URL(url));
} catch (Exception e) {
e.printStackTrace();
}
}
public void draw(Graphics g) {
g.drawImage(image, 0, 0, null, null);
}
}
Tips
Exception in thread "AWT-EventQueue-0" java.lang.UnsupportedOperationException: getGraphics() not valid for images created with createImage(producer) at img = createImage(null); I have no idea what you thought that code statement does, but ..nothing good.
When doing custom painting in a JPanel, we should override only paintComponent(Graphics) and leave the paint(Graphics) method as it is. When overriding the former, immediately call the super method.
Adding a call to repaint() inside paint(Graphics) will cause an infinite loop.. If the code needs to loop, establish a Swing Timer to call repaint()
paintComponet(Graphics g) should be paintComponent(Graphics g) Use #Override notation when appropriate. It would have warned you of the incorrectly spelled method name.
More general tips
For better help sooner, post an MCVE.
One way to get image(s) for an example is to hot-link to the images seen in this answer.
By the time of deployment, those images will likely become an embedded-resource. That being the case, they must be accessed by URL instead of File. See the info page for the tag, for a way to form an URL.

Cannot draw transparent Component backgrounds

I have tried several tutorials and searches to figure out how to accomplish what I am trying to do. Basically I have a JLayeredPane with two Jpanels inside it. One for my game's drawing surface and one for my gui, like a pause menu. I have a png file with transparencies that I want to be the background of my gui panel that popups when the user hits escape. No matter what I do, the background of the panel (even tried making it just a component) is always grey with my png file drawn over it.
I have tried what others have recommended such as the following.
setBackground(new Color(0,0,0,0));
and
setOpaque(false);
Neither of these has seemed to help and perhaps I am failing to do something else after these. I have traditionally done them after the constructor or within the constructor of a class that extends jpanel.
I am almost to the point where I am going to have one panel and draw everything myself but I would much rather use the built in java functions like boxlayouts, etc.
Edit Adding Working Example:
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
public class Example {
private MyWindow gWindow;
public static void main(String argv[]) {
Example g = new Example();
g.gameLoop();
}
public Example() {
gWindow = new MyWindow();
// Initialize the keyboard listener
gWindow.frame().addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ESCAPE) // escape key, show menu
{
System.exit(0);
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
});
}
public void gameLoop() {
long lastLoopTime = System.currentTimeMillis();
while(true) {
// Used to calculate movement of sprites
long delta = System.currentTimeMillis() - lastLoopTime;
lastLoopTime = System.currentTimeMillis();
// Clear the canvas
Graphics2D g = (Graphics2D) gWindow.getBufferStrategy().getDrawGraphics();
g.setColor(Color.black);
g.fillRect(0,0,gWindow.frame().getWidth(), gWindow.frame().getHeight());
// Clean up graphics and flip buffer
g.dispose();
gWindow.getBufferStrategy().show();
// Small delay before next cycle
try { Thread.sleep(10); } catch (Exception e) {}
}
}
public class MyWindow {
private JFrame frame;
private JLayeredPane container;
private MyPanel gui;
private JPanel surface;
private Canvas canvas;
private GraphicsDevice vc;
private Dimension dm;
BufferedImage menuImg = null;
BufferedImage menuImgHighlight = null;
BufferedImage gSettings = null;
Font font = null;
public MyWindow() {
frame = new JFrame("Jumper");
vc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
DisplayMode display = vc.getDisplayMode();
dm = new Dimension(display.getWidth(), display.getHeight());
container = new JLayeredPane();
gui = new MyPanel();
gui.setLayout(new BoxLayout(gui, BoxLayout.Y_AXIS));
surface = new JPanel(new BorderLayout(0,0));
frame.add(container, BorderLayout.CENTER);
container.add(surface, new Integer(0), 0);
container.add(gui, new Integer(1), 0);
init_resources();
canvas = new Canvas();
surface.add(canvas);
gui.setBackground(new Color(0,0,0,0));
gui.setVisible(true);
gui.setOpaque(false);
surface.setVisible(true);
setFullScreen(display);
frame.setResizable(false);
frame.setVisible(true);
frame.pack();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
setScreen(new Dimension(frame.getWidth(), frame.getHeight()));
frame.repaint();
}
});
canvas.setIgnoreRepaint(true);
canvas.createBufferStrategy(2);
canvas.setFocusable(false);
}
public JFrame frame() {
return frame;
}
public BufferStrategy getBufferStrategy () {
return canvas.getBufferStrategy();
}
public void setScreen(Dimension dim) {
int width = (int) dim.getWidth();
int height = (int) dim.getHeight();
this.dm = dim;
container.setPreferredSize(dm);
gui.setPreferredSize(dm);
surface.setPreferredSize(dm);
canvas.setBounds(0,0,width,height);
if(gSettings == null) {
gui.setBounds((int) ((dm.getWidth() - 200) / 2),
(int) ((dm.getHeight() - 200) / 2),
200,
200);
}
else {
gui.setBounds((int) ((dm.getWidth() - gSettings.getWidth()) / 2),
(int) ((dm.getHeight() - gSettings.getHeight()) / 2),
gSettings.getWidth(),
gSettings.getHeight());
}
gui.setBackground(gSettings);
surface.setBounds(0,0,width,height);
container.setBounds(0,0,width,height);
frame.validate();
}
public void setFullScreen(DisplayMode display) {
setScreen( Toolkit.getDefaultToolkit().getScreenSize());
frame.setUndecorated(true);
vc.setFullScreenWindow(frame);
if(dm != null && vc.isDisplayChangeSupported()) {
try {
vc.setDisplayMode(display);
}
catch(Exception e) {}
}
frame.validate();
}
private void init_resources() {
try {
gSettings = ImageIO.read(getClass().getResourceAsStream("/gui/settingsWindow.png"));
}
catch(Exception e)
{
System.out.print("Failed to load resources");
System.out.println();
}
}
}
public class MyPanel extends JPanel {
BufferedImage img = null;
public MyPanel() {
super();
setOpaque(false);
}
public void setBackground(BufferedImage img) {
this.img = img;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(img != null) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(img, 0, 0, null);
}
}
}
}
I've not tested this, but, instead of calling super.paintComponent at the end of you paint method, try calling at the start....
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(img != null) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(img, 0, 0, null);
}
}
The reasoning for this, is one of the jobs of paintComponent is clear the graphics context and ready it to be painted on. Event if the component is transparent, it must still clear/wipe the graphics context of anything that has previously been painted on it. The graphics context is a shared resource, meaning that all the components within a given window may share the same graphics context, so it gets a little dirty if it's not "wiped" first ;)
You may also have issues with mixing heavy and light weight components, but seen as you adding the light weight components to the heavy weight component, it may not be an issue, but it's worth putting in the back of your mind... ;)
JComponent is transparent by default ;)
Try to apply some Physics over here...
The visible white color is combination of RGB max values...
If you are keeping RGB values to Minimum it will give you dark color (Black) and not the transparent one..
try to implement below methods..
(your component).setOpaque(false);
(your component).setContentAreaFilled(false);
(your component).setBorderPainted(false);
Hope so this will help you...

Categories