So, for a personal project, I've been trying to create a program in Java that can make a rudimentary animation appear on a Swing application. As far as I know, I've done everything right, and as far as I know it's working, but when I run the application, it does not let me close the application without Task Manager, and when I force quit the app IntelliJ tells me "process finished with exit code 1". It's also not displaying my animation on the screen despite displaying normal Graphics things such as lines.
Here is my JFrame code:
package animtest;
import javax.swing.*;
public class AnimTest extends JFrame {
public void addComponents() {
AnimPanel panel = new AnimPanel();
setContentPane(panel);
}
public AnimTest(String string) {
super(string);
}
public static void main(String[] args) {
AnimTest frame = new AnimTest("Animation Test");
frame.addComponents();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Here is my JPanel code:
package animtest;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class AnimPanel extends JPanel {
Image[] marsExploding = new Image[3];
public AnimPanel() {
try {
marsExploding[0] = ImageIO.read(new File("res/MarsExploding.png"));
marsExploding[1] = ImageIO.read(new File("res/MarsExploding2.png"));
marsExploding[2] = ImageIO.read(new File("res/MarsExploding3.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public void paintComponent(Graphics g2) {
Graphics2D g = (Graphics2D) g2.create();
g.setColor(Color.white);
for (int i = 0; i < marsExploding.length; i++) {
g.drawImage(marsExploding[i], (getWidth() / 2) - 128, (getHeight() / 2) - 128, 256, 256, null);
try {
TimeUnit.SECONDS.sleep(500);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
g.fillRect(0, 0, getWidth(), getHeight());
}
g.dispose();
repaint();
}
}
Any help is greatly appreciated, thank you!
EDIT 1
OK, so this is my new panel code, which should honor Swing's contract and concurrency:
package animtest;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
public class AnimPanel extends JPanel {
Image[] marsExploding = new Image[3];
Graphics2D g;
int currentFrame = 0;
public AnimPanel() {
try {
marsExploding[0] = ImageIO.read(new File("res/MarsExploding.png"));
marsExploding[1] = ImageIO.read(new File("res/MarsExploding2.png"));
marsExploding[2] = ImageIO.read(new File("res/MarsExploding3.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
Timer timer = new Timer(500, null);
timer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
displayNewFrame(currentFrame);
if (currentFrame < 2) {
currentFrame++;
} else {
currentFrame = 0;
}
}
});
timer.start();
}
#Override
public void paintComponent(Graphics g2) {
super.paintComponent(g2);
g = (Graphics2D) g2.create();
}
public void displayNewFrame(int frame) {
g.fillRect(0, 0, getWidth(), getHeight());
g.drawImage(marsExploding[frame], (getWidth() / 2) - 128, (getHeight() / 2) - 128, 256, 256, null);
}
}
However this doesn't actually display anything to the screen.
Swing is a single threaded framework, this means, that any call which is long running or blocking made from within the context of the Event Dispatching Thread will prevent the UI from been updated or allow the user to interact with it, making your UI appear as if it's hung (because it essentially has).
See Concurrency in Swing for more details.
Instead of trying to use TimeUnit.SECONDS.sleep(500); inside a paint method, you should have some background thread which ticks at a regular interval and allows you to update the UI accordingly. The problem is, Swing is also not thread safe, meaning that you should never try and create or update the UI from outside the context of the Event Dispatching Thread.
For a basic solution, you can, however, use a Swing Timer, which will trigger a ActionListener on a regular bases within the context of the EDT, making it safe to use with the UI.
See How to use Swing Timers for more details.
Painting in Swing is performed by a series of chained method calls, custom painting requires you to insert your code within on of these links, paintComponent been the most preferred.
However, you are expected to honor the contract of these links by calling the super paint method you are overriding.
See Painting in AWT and Swing and Performing Custom Painting for more details
Related
when I call a repaint method its flickering, I was searching on the internet about doubleBuffered but its stil flickering all of objects on the same time,
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Random;
public class GuiGame extends JFrame implements ActionListener {
private final Flower flower;
private final ArrayList<MyObjects> objekty;
private Image dbImage;
private Graphics dbGraphics;
public GuiGame() {
this.setFocusable(true);
Timer timer = new Timer(40, this);
timer.start();
this.setVisible(true);
/*
public void paint(Graphics g) {
this.dbImage = this.createImage(this.getWidth(), this.getHeight());
this.dbGraphics = this.dbImage.getGraphics();
this.paintComponents(g);
g.drawImage(this.dbImage, 0 ,0, this);
}
*/
public void paint(Graphics g) {
//when i use doubleBuffering this method was called paintComponents
g.drawImage(background.getImage(), 0, 0, this);
g.drawImage(flower.getImage(), flower.getPozX(), flower.getPozY(), this);
String skore = "Score: " + player.getScore() ;
g.drawString(skore, 20, 50);
this.paintObjects(g);
}
public void paintObjects(Graphics g) {
if (this.objekty != null) {
for (objekty o : this.objekty) {
o.move();
g.drawImage(o.getImage(), o.getPozX(), o.getPozY(), this);
}
}
}
when I used doubleBuffering I tried to slow down a timer e.g. to 1000, it was blank page for most of the time and my objects was there only for moment.
when I do not used it, only last objects which i draw were flickering.
how can I avoid?
I would recommend you start by taking a look at Painting in AWT and Swing and Performing Custom Painting.
Swing components, when used correctly, are double buffered by default.
Painting is very complex, there's a lot of work that goes into a paint pass. When you override a "paint" method, you either need to honour the existing workflow (ie, call the super.paintXxx method) or be prepared to take over the full responsibility of the method. Your code has circumvented whole sections of the paint workflow, this is never a good idea.
It's not generally recommend that you extend from top level containers like JFrame, you're not adding any new functionality and they are generally complex components to start with. JFrame for example, is actually a composite component, that is, it has a number of child components added to it that form it's core functionality
By overriding paint (of JFrame), you start competing with these components, and because a child component can be painted without the parent been involved, this can lead to any number of issues.
Instead, start with a JPanel and override it's paintComponent method, this guarantees that you will be operating in a double buffered workflow.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class MainPane extends JPanel {
private int xDelta = 1;
private int xPos = 0;
private BufferedImage ufo;
public MainPane() throws IOException {
ufo = ImageIO.read(getClass().getResource("/images/ufo.png"));
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
xPos += xDelta;
if (xPos + ufo.getWidth() > getWidth()) {
xPos = getWidth() - ufo.getWidth();
xDelta *= -1;
} else if (xPos < 0) {
xPos = 0;
xDelta *= -1;
}
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
paintUFO(g2d);
g2d.dispose();
}
protected void paintUFO(Graphics2D g2d) {
int y = (getHeight() - ufo.getHeight()) / 2;
g2d.drawImage(ufo, xPos, y, this);
}
}
}
So basically I'm trying to create countdown when my code is run,
which is fine and working the only problem I have is that instead of the
numbers disappearing and being replaced by the new value of i, they stay the new value overlaps the existing number. I tried to use repaint () to fix this but it's not working. I'm wondering if there's something I'm missing or if I should try a different way altogether.
here's the code for the timer:
public void timer (Graphics g,int x){
x=550;
for (int i = time;i>0;i--){
g.setColor(deepPlum);
g.setFont(new Font("Monospaced", Font.PLAIN, 25));
g.drawString("time: "+i, x, 650);
repaint();
}
}
At a "guess"
I don't like guessing, but it seems we're not going to get a runnable example which would provide a clear understand of how the problem is been generated.
Evidence...
I do call the super paint method but in the paint method. I know that is fine because all of my other graphics are working fine.
This "suggests" that timer is been called as part of the normal Swing "paint" cycle. If that's true, it explains the reason for the issue.
This...
public void timer (Graphics g,int x){
x=550;
for (int i = time;i>0;i--){
g.setColor(deepPlum);
g.setFont(new Font("Monospaced", Font.PLAIN, 25));
g.drawString("time: "+i, x, 650);
repaint();
}
}
is simply painting all the numbers over each other, each time a paint cycle occurs, which really isn't how a count down timer should be painted.
Instead, it should simply be painting the remaining time, a single value, and not try and paint all of them.
You can think of a "paint cycle" as a "frame", it paints a snap-shot of the current state of the component. You need to paint a number of these "frames" in order to animate the changes from one point in time to another.
I would, again, strongly, recommend that you take the time to read through Performing Custom Painting and Painting in AWT and Swing to better understand how painting actually works.
Without more evidence, I would suggest, a Swing Timer would be a better solution. This could be used to calculate the remaining time and schedule a repaint on a regular bases.
Because I seem to do this kind of thing a lot, I wrapped up the core functionality into a simple Counter class, which has a "duration" (or runtime) and can calculate the duration it's been running, the remaining time and the progress as a percentage of the duration and runTime, probably more then you need, but it gives you the basics from which to start.
Because painting is a imprecise art (the time between paint cycles is variable, even when using a Timer), I've used a "time" based approach, rather then a simple "counter". This gives you a much higher level of precision when dealing with these type of scenarios
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
// The following two lines just set up the
// "default" size of the frame
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JComponent {
private Counter counter;
public TestPane() {
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (counter == null) {
counter = new Counter(Duration.of(10, ChronoUnit.SECONDS));
counter.start();
}
repaint();
}
});
timer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (counter != null) {
Graphics2D g2d = (Graphics2D) g.create();
FontMetrics fm = g2d.getFontMetrics();
long time = counter.getRemaining().getSeconds();
int x = (getWidth() - fm.stringWidth(Long.toString(time))) / 2;
int y = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
g2d.drawString(Long.toString(time), x, y);
g2d.dispose();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public static class Counter {
private Duration length;
private LocalDateTime startedAt;
public Counter(Duration length) {
this.length = length;
}
public Duration getLength() {
return length;
}
public void start() {
startedAt = LocalDateTime.now();
}
public void stop() {
startedAt = null;
}
public Duration getDuration() {
if (startedAt == null) {
return null;
}
Duration duration = Duration.between(startedAt, LocalDateTime.now());
if (duration.compareTo(getLength()) > 0) {
duration = getLength();
}
return duration;
}
public Double getProgress() {
if (startedAt == null) {
return null;
}
Duration duration = getDuration();
return Math.min(1.0, (double) duration.toMillis() / length.toMillis());
}
public Duration getRemaining() {
if (startedAt == null) {
return null;
}
Duration length = getLength();
Duration time = getDuration();
LocalDateTime endTime = startedAt.plus(length);
LocalDateTime runTime = startedAt.plus(time);
Duration duration = Duration.between(runTime, endTime);
if (duration.isNegative()) {
duration = Duration.ZERO;
}
return duration;
}
}
}
Before someone tells me how clearRect would solve the issue, it's important to note that clearRect will do two things. One, it would only display the "last" value of the loop, which is clearly not what the OP wants, and it will fill the specified area with the current background color of the Graphics context, which "may" not be what the OP want's (as it will paint a nice rectangle over the top of what ever else was painted before it).
If used properly, the Swing painting system will prepare the Graphics context BEFORE the component's paint method is called, rendering the need for using clearRect mute
Call clearRect to restore the background for a rectangular region before drawing again
I am making a 2d game and I need to draw an image on top of another. After I draw the first image(the larger one, jpg), the second image(the smaller one,png) erases from where the second image is to the lower right hand corner. Like this:
I have looked into this a bit, and it was suggested that I use buffered images, so I did that with both images and the problem remains. Here is one post I looked at: How to draw an image over another image?. I have also seen some people suggesting graphics2d, though I did not really understand the reason to use them or how to use them. I am new to java graphics and images, so it is probably a silly mistake.
Here is my code. Thank you.
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import javax.swing.*;
import java.util.ArrayList;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.IOException;
public class DisplayExample extends JComponent
{
private BufferedImage backgroundImage;
private String backgroundName;
private BufferedImage image; //image to draw
private int imageX; //position of left edge of image
private int imageY; //position of top edge of image
private JFrame frame;
public static void main(String[] args)
{
DisplayExample example = new DisplayExample();
example.run();
}
public DisplayExample()
{
imageX = 200;
imageY = 200;
backgroundName = "backgroundShip.jpg";
URL backgroundURL = getClass().getResource(backgroundName);
if (backgroundURL == null)
throw new RuntimeException("Unable to load: " + backgroundName);
try{backgroundImage = ImageIO.read(backgroundURL);}catch(IOException ioe){}
//load image
String fileName = "explosion.png";
URL url = getClass().getResource(fileName);
if (url == null)
throw new RuntimeException("Unable to load: " + fileName);
//image = new ImageIcon(url).getImage();
try{image = ImageIO.read(url);}catch(IOException ioe){}
System.out.println(image instanceof BufferedImage);
setPreferredSize(new Dimension(1040,500)); //set size of drawing region
//need for keyboard input
setFocusable(true); //indicates that WorldDisp can process key presses
frame = new JFrame();
frame.getContentPane().add(this);
frame.pack();
frame.setVisible(true);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if(backgroundImage != null)
g.drawImage(backgroundImage,0,0,getWidth(), getHeight(), null);
g.drawImage(image, imageX, imageY, this);
}
public void run()
{
while(true)
{
imageY+=1;
repaint();
try{Thread.sleep(100);}catch(Exception e){}
}
}
}
So I took your code, added my own images and it runs fine for me.
Having said that, there are some areas you can improve:
You're running the risk of either blocking the Event Dispatching Thread or introducing a thread race condition into your code with your run method. You should consider using a Swing Timer instead. See How to use Swing Timers for more details. This allows you to schedule regular callbacks which are called within the context of the EDT, making it safer to update the context of the UI
You should only ever create or modify the state of the UI from within the context of the EDT, Swing is not thread safe. See Initial Threads for more details. Swing has been known to have "issues" when the UI is not initialised within the EDT
Scaling an image is expensive, you should avoid doing so from within the paint methods, instead, scale the image and keep a reference to the result and use it when you need to paint it.
You should consider using the key bindings API over KeyListener, it will solve many of the issues associated with using KeyListener. See How to Use Key Bindings for more details.
For example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DisplayExample extends JComponent {
private BufferedImage backgroundImage;
private String backgroundName;
private BufferedImage image; //image to draw
private int imageX; //position of left edge of image
private int imageY; //position of top edge of image
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
DisplayExample example = new DisplayExample();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(example);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public DisplayExample() {
imageX = 200;
imageY = 200;
try {
backgroundImage = ImageIO.read(new File("..."));
} catch (IOException ioe) {
ioe.printStackTrace();
}
//load image
try {
image = ImageIO.read(new File("..."));
} catch (IOException ioe) {
ioe.printStackTrace();
}
//need for keyboard input
//setFocusable(true); //indicates that WorldDisp can process key presses
// Use the key bindings API instead, causes less issues
Timer timer = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
imageY += 1;
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return backgroundImage == null ? new Dimension(200, 200) : new Dimension(backgroundImage.getWidth(), backgroundImage.getHeight());
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (backgroundImage != null) {
// Scaling is expensive, don't do it here
int x = (getWidth() - backgroundImage.getWidth()) / 2;
int y = (getHeight() - backgroundImage.getHeight()) / 2;
g2d.drawImage(backgroundImage, x, y, this);
}
g2d.drawImage(image, imageX, imageY, this);
g2d.dispose();
}
}
Okay, so here's the deal: I'm trying to simply draw an object (in this case a tornado) onto my main canvas. I'm using JFrames, a canvas, a buffer strategy, and a buffered image to draw on. As far as I can figure I'm using the "game loop" correctly and from what I've been previously able to find my order of operations in the rendering is correct. Is there some thing I'm missing about the nature of using buffer strategies perhaps? I can't tell why i get just a grey screen.
Basically I'm trying to get this tornado program working using as many "proper" graphical and coding techniques as possible. Ultimately all I want is a little city that has a tornado moving through it, with each component existing as an object (the tornado, buildings, people, etc). However I find myself unable to continue util I can actually draw the blasted! The code below should show you whatever else you need to know, I'm fairly new to programming and this is a high school project, so any other pointers are welcome but mostly I want to know why the tornado wont draw!
I'm using eclipse, by the way. and so far I've followed these toutorials and posts to get where I am now:
http://www.gamedev.net/page/resources/_/technical/general-programming/java-games-active-rendering-r2418
http://examples.javacodegeeks.com/desktop-java/awt/image/drawing-on-a-buffered-image/
This is the main class:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Transparency;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Main {
static BufferStrategy BuffStrat;
static Thread t1;
static BufferedImage backbuff;
static JFrame mainframe;
static Tornado tornado;
public static void main(String[] args) {
Simulation();
}
public static void Setup() {
mainframe = new JFrame("Tornado Ally");
mainframe.setIgnoreRepaint(true);
mainframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Canvas maincanvas = new Canvas();
maincanvas.setIgnoreRepaint(true);
maincanvas.setSize(750, 600);
mainframe.add(maincanvas);
mainframe.pack();
mainframe.setVisible(true);
maincanvas.createBufferStrategy(2);
BuffStrat = maincanvas.getBufferStrategy();
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
backbuff = gc.createCompatibleImage(750, 600, Transparency.BITMASK);
tornado = new Tornado (0, 0, 0, 0, 0, backbuff);
}
public static void Simulation() {
Setup();
while (true) {
Render();
delay(10);
}
}
public static void Render() {
Graphics2D g = null;
g = backbuff.createGraphics();
g.setBackground(Color.LIGHT_GRAY);
g.clearRect(0, 0, 750, 600);
tornado.drawTornado(g);
Graphics gI = BuffStrat.getDrawGraphics();
gI.drawImage(backbuff, 0, 0, null);
BuffStrat.show();
gI.dispose();
g.dispose();
}
public static void delay(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
}
}
}
This is the Tornado Object:
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.geom.Dimension2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Tornado {
int x, y, z;
int mag;
double velocity;
Dimension2D hitbox;
GraphicsConfiguration gc;
Image t;
BufferedImage backbuff;
public Tornado(int x, int y, int z, int mag, double velocity, BufferedImage backbuff) {
this.x = x;
this.y = y;
this.z = z;
this.mag = mag;
this.velocity = velocity;
this.backbuff = backbuff;
{
try {
t = ImageIO.read(new File("Sprites.Tornado/TornadoFull.png"));
} catch (IOException e) {
}
}
}
public void drawTornado(Graphics2D g) {
g.drawImage(t, 0, 0, null);
}
}
When testing your code, it throw an exception because your code attempted to construct a BufferStrategy before the window had being resized. Because the main window is using a LayoutManager a better solution would be to use something like...
//maincanvas.setSize(750, 600);
maincanvas.setPreferredSize(new Dimension(750, 600));
When you call pack, the window will be resized to accommodate the preferred size of it's child components...
You are also ignoring your exceptions when you load you image, so you won't even know if it hadn't loaded for some reason. At the very least, you should be logging any exceptions...
For example...
try {
t = ImageIO.read(new File("TSprites.Tornado/TornadoFull.png"));
} catch (IOException e) {
e.printStackTrace();
}
This code suggests that the image is an external resource, if not (and it's built into the application), you would need to use getClass().getResource("/TSprites.Tornado/TornadoFull.png") instead of new File(...)...
You should also consider constructing your UI within the context of the Event Dispatching Thread, for details, take a look at Initial Threads.
For example, I changed your main method to look more like...
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Simulation();
}
});
And updated your Simulation method to execute the main loop within the context of another thread, for example...
public static void Simulation() {
Setup();
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
Render();
delay(10);
}
}
}).start();
}
You may also like to take a look at Code Conventions for the Java Programming Language as it will make you code easier to read by others
Also, beware of the over use of static. This can cause more problems then they solve if not used correctly...
Also, try and avoid the use of magic numbers, instead, use values you know, for example...
Instead of...
g.clearRect(0, 0, 750, 600);
Try using...
g.clearRect(0, 0, backbuff.getWidth(), backbuff.getHeight());
What I'm trying to do here is call the repaint() method from within my loadbg() method. However, repaint() isn't working, and my image (stored in the var bg) won't load onto the screen. Any suggestions as to why this won't work?
package core;
/*** #author Adil
* 2DPlatformer
* Written by Adil
* Built upon the player-core framework (written by Adil)
* GNU Licensed
*/
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.ImageIcon;
#SuppressWarnings("serial") //Suppress serial warning ID
public class Core extends JFrame {
public static void main(String[] args) {
DisplayMode dm = new DisplayMode(800, 600, 16,
DisplayMode.REFRESH_RATE_UNKNOWN);
//new display with parameters 800x600 + 16 bit color depth
Core i = new Core(); //new core class var
i.run(dm);
}
//variables for image loading below
public Screen s;
public Image bg;
public boolean loaded = false;
//run method below
public void run(DisplayMode dm) {
setBackground(Color.BLACK);
setForeground(Color.WHITE);
setFont(new Font("Ubuntu", Font.PLAIN, 24));
s = new Screen();
loaded = false;
try {
s.setScreenSize(dm, this);
loadbg();
try {
Thread.sleep(5000);
} catch (Exception ex) {
}
} finally {
s.RestoreScreen();
}
}
public void loadbg() {
bg = new ImageIcon(
"file:\\\\home\\adil\\Desktop\\pack_2\\bgame.jpg").getImage();
loaded = true;
s.repaint();//s is my screen object, but it won't repaint.
}
public void paint(Graphics g) {
if (g instanceof Graphics2D) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
if (loaded) {
g.drawImage(bg, 0, 0, null);
}
}
}
1) better way would be put Icon/ImageIcon to JLabel, rather than paint Image by using paint()
2) for Swing is there paintComponent() instead of paint()
3) don't use Thread.sleep(int) for Swing GUI use javax.swing.Timer instead, because during Thread.sleep(int) you GUI simply freeze, nothing else