Im working on a game in Java and having an issue (i believe its with the content pane) when rendering. I have a screen class which draws the background and all sprites to an Image. The frame then displays the image using a doubleBuffer. For some odd reason tho the image is rendering off the edge of the frame. You can see in the link below that the image is rendering 3 pixels to the left and 28 pixels above where it should be. Does anyone have any idea what could be causing this?
![enter image description here][1]
http://imageshack.us/photo/my-images/41/weirdg.png/
public class Game extends JFrame implements Runnable{
private static final long serialVersionUID = 1L;
//graphics
public BufferStrategy buffy;
BufferedImage image;
Screen screen;
public Boolean running = false;
public Boolean playerTurn = false;
public InputManager input;
public Level level;
//JButton b;
public static final int HEIGHT = 452;
public static final int WIDTH = 768;
public Game() {
super("GridWars");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel drawPanel = new JPanel();
drawPanel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
drawPanel.setLayout(null);
drawPanel.setOpaque(false);
//drawPanel.setLocation(50,50);
setContentPane(drawPanel);
setResizable(false);
pack();
setLocationRelativeTo(null);
setVisible(true);
requestFocus();
createBufferStrategy(2);
//b = new JButton("this sucks");
//getContentPane().add(b);
//b.setBounds(300, 300, 100, 50);
buffy = getBufferStrategy();
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
screen = new Screen(WIDTH, HEIGHT);
input = new InputManager(this);
level = new Level(WIDTH, HEIGHT, input, this);
}
public void start() {
running = true;
new Thread(this).start();
}
public void setup(){
}
public void run() {
final double TICKS = 30.0;
final double UPDATE_INTERVAL_NS = 1000000000 / TICKS;
double pastUpdateNS = System.nanoTime();
int updateCount = 0;
int frameCount = 0;
final double FRAPS = 60.0;
final double RENDER_INTERVAL_NS = 1000000000 / FRAPS;
double pastRenderNS = System.nanoTime();
int pastSecondNS = (int) (pastUpdateNS/1000000000);
while(running) {
double nowNS = System.nanoTime();
if(nowNS - pastUpdateNS >= UPDATE_INTERVAL_NS) {
update();
pastUpdateNS += UPDATE_INTERVAL_NS;
updateCount++;
}
float interp = Math.min(1.0f, (float) ((nowNS - pastUpdateNS) / UPDATE_INTERVAL_NS) );
render(interp);
pastRenderNS += RENDER_INTERVAL_NS;
frameCount++;
int thisSecondNS = (int) (pastUpdateNS/1000000000);
if (thisSecondNS > pastSecondNS) {
//System.out.println("TICKS: "+updateCount+" | FRAPS: "+frameCount);
updateCount = 0;
frameCount = 0;
pastSecondNS = thisSecondNS;
}
while( nowNS - pastRenderNS < RENDER_INTERVAL_NS && nowNS - pastUpdateNS < UPDATE_INTERVAL_NS) {
try { Thread.sleep(1); } catch(Exception e) {};
nowNS = System.nanoTime();
}
}
}
public void update() {
input.update();
level.update();
}
public void render(float interp) {
level.render(screen, interp);
image = screen.getImage();
Graphics g = buffy.getDrawGraphics();
g.drawImage(image, 0, 0, null, null);
//b.repaint();
g.dispose();
buffy.show();
}
public static void main(String[] args) {
Game game = new Game();
game.start();
}
}
The 0,0 coordinate of Graphics object you obtain from buffy.getDrawGraphics(); is exactly at top left corner of JFrame and it is ignoring frame decorations.
UPD I forgot one obvious option. JFrame.getInsets() provides information about decorations. You could simply shift your rendering.
You would make frame undecorated (setUndecorated(true)) and render/manage window controls yourself.
Or, and i think it is easier way, you would forget about direct rendering on JFrame, place Canvas on it, and use it instead. Canvas also contains createBufferStrategy method, so you need few simple changes.
JPanel drawPanel = new JPanel();
drawPanel.setLayout(new BorderLayout());
Canvas canvas = new Canvas();
canvas.setPreferredSize(new Dimension(WIDTH, HEIGHT));
drawPanel.add(canvas, BorderLayout.CENTER);
// some code skipped
canvas.setIgnoreRepaint(true); //important
canvas.createBufferStrategy(2);
buffy = canvas.getBufferStrategy();
I've created simple demo with similar render few days ago for another answer. Maybe it will helpful.
Related
I've looked all over and I can only find cases of people using their custom JPannel to draw an image over another image but what I'm trying to do is draw a component over the JPannel and no matter what I try it always moves the JPannel when it draws the next frame. It feels like ther must be a way to override the meathod that draws it on front and allows you to draw it in the very back but there was none that i could find.
public class MovingBackgroundDemo {
private JToggleButton button = new JToggleButton("Button");
private JFrame frame = new JFrame();
private int framewidth =frame.getWidth();
private int frameheight =frame.getHeight();
public MovingBackgroundDemo() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addComponentListener(new ComponentAdapter()
{
public void componentResized(ComponentEvent evt) {
framewidth =frame.getWidth();
frameheight =frame.getHeight();
button.setBounds(framewidth/2 - framewidth/14 - framewidth/6,frameheight/6, framewidth/6, frameheight / 12);
}
});
frame.add(button);
frame.add(new AnimatingPanel());
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private class AnimatingPanel extends JPanel {
private static final int DIM_W = 350;
private static final int DIM_H = 350;
private static final int INCREMENT = 10;
private BufferedImage backgroundImage;
private Image runnerImage;
private int dx1, dy1, dx2, dy2;
private int srcx1, srcy1, srcx2, srcy2;
private int IMAGE_WIDTH;
public AnimatingPanel() {
initImages();
initImagePoints();
Timer timer = new Timer(40, new ActionListener() {
public void actionPerformed(ActionEvent e) {
moveBackground();
repaint();
}
});
timer.start();
FlowLayout layout = (FlowLayout)getLayout();
layout.setHgap(0);
layout.setVgap(0);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
g.drawImage(backgroundImage, dx1, dy1, dx2, dy2, srcx1, srcy1,
srcx2, srcy2, this);
g.drawImage(runnerImage, 0, 0, getWidth(), getHeight(), this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(350, 350);
}
private void initImagePoints() {
dx1 = 0;
dy1 = 0;
dx2 = DIM_W;
dy2 = DIM_H;
srcx1 = 0;
srcy1 = 0;
srcx2 = DIM_W;
srcy2 = DIM_H;
}
private void initImages() {
try {
File icoen = new File("the picture");
runnerImage = ImageIO.read(icoen);
File icon = new File("the other one");
backgroundImage = ImageIO.read(icon);
IMAGE_WIDTH = backgroundImage.getWidth();
System.out.println(IMAGE_WIDTH);
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void moveBackground() {
if (srcx1 > IMAGE_WIDTH) {
srcx1 = 0 - DIM_W;
srcx2 = 0;
} else {
srcx1 += INCREMENT;
srcx2 += INCREMENT;
}
}
}
public static void main(String[] args) {
new MovingBackgroundDemo();
}
}
Any tips?
This:
frame.add(button);
frame.add(new AnimatingPanel());
Should be:
JPanel animationPanel = new AnimatingPanel();
animationPanel.add(button);
frame.add(animationPanel);
The first code is trying to add the two components (button and panel) to the same exact layout position in the frame. That won't work (properly, or in some cases, at all).
When I run my game the JFrame is just white. Can someone explain?
I have no idea why this is happening and I'm having a really hard time finding out what could be the issue. I hope one of you can explain/know the answer. I look forward to hearing your answer and I would love to continue coding but I'm stuck atm, - Artycal.
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.IOException;
public class Game extends Canvas implements Runnable {
static GraphicsDevice device = GraphicsEnvironment
.getLocalGraphicsEnvironment().getScreenDevices()[0];
private static JFrame frame;
private static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
private BufferedImage image = new BufferedImage((int)width, (int)height, BufferedImage.TYPE_INT_ARGB);
private BufferedImage spriteSheet = null;
private static double width = screenSize.getWidth();
private static double height = screenSize.getHeight();
private boolean running;
private Thread thread;
private BufferedImage player;
public void init() {
BufferedImageLoader loader = new BufferedImageLoader();
try{
spriteSheet = loader.loadImage("/sprite_sheet.png");
}catch (IOException e){
e.printStackTrace();
}
SpriteSheet ss = new SpriteSheet(spriteSheet);
player = ss.grabImage(1, 1, 32, 32);
}
public void run() {
init();
long lastTime = System.nanoTime();
final double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
int updates = 0;
int frames = 0;
long timer = System.currentTimeMillis();
while (running){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
if (delta >= 1){
tick();
updates++;
delta--;
}
render();
frames++;
if (System.currentTimeMillis() - timer > 1000){
timer += 1000;
System.out.println(updates + " Ticks, Fps " + frames);
updates = 0;
frames = 0;
}
}
stop();
}
private void render() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(new Color(81, 218, 221));
g.drawRect(0, 0, getWidth(), getHeight());
g.setColor(new Color(81, 218, 221));
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
g.setColor(new Color(255, 174, 80));
g.drawImage(player, 100, 100, this);
g.dispose();
bs.show();
}
private void tick() {
}
public static void main(String[] args){
Game game = new Game();
frame = new JFrame("Game");
frame.setMaximumSize(new Dimension((int)width, (int)height));
frame.setMinimumSize(new Dimension((int)width, (int)height));
frame.setPreferredSize(new Dimension((int)width, (int)height));
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(game);
frame.pack();
frame.setVisible(true);
//device.setFullScreenWindow(frame);
game.start();
}
private synchronized void start() {
if (running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
private synchronized void stop() {
if (!running)
return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.exit(1);
}
}
some things to note:
INT_ARGB for BufferedImage has a default alpha of 0 (completely clear) so unless you change the alpha value of the pixels you wont see anything.
drawRect draws only the outline of the rectangle. use fillRect to draw the entire rectangle.
as far as I know, drawing BufferedImages does not use the current color of the Graphics object as they are mainly defined as a rectangle made of different colored pixels. try drawing to the Images own Graphics object if you want to change its color.
you are exactly overlapping two drawings (the image and the rect) so you will only ever see one.
I hope I have finally been of some help.
Hello I am kind of new to java. I am working on a game. when the game starts a loading screen appears and the fades away that's it so far. My question is simple. Is there a way to change the image size to fit the size of the computer screen. I want it to fit all types of screen sizes and be a larger scale of the original image. Here is my Main class so far(there are other classes like player and title and play but they are irrelevant to the question:
package Main;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class Comp extends Canvas implements Runnable, KeyListener {
private static final long serialVersionUID = 1L;
public boolean run = true;
public Image screen, img;
public static double dir = 5;
public static int pixelSize = 1;
public static Dimension size = new Dimension(680, 500);
public static Dimension pixel = new Dimension(size.width / pixelSize,
size.height / pixelSize);
public static int mx;
public static manager m;
public static int my;
public static int fps;
public static boolean mr;
public static boolean ml;
JFrame frame = new JFrame();
public Thread t;
public boolean splashscreen = true;
public int time = 0;
public int timer = 140;
public int btime = 0;
public int btimer = 1;
private int FPS = 5;
private long targetTime = 1000 / FPS;
public Comp() {
setPreferredSize(size);
setFocusable(true);
addKeyListener(this);
addKeyListener(new listen());
addMouseListener(new listen());
addMouseMotionListener(new listen());
addMouseWheelListener(new listen());
m = new manager();
requestFocus();
// h = new InputHandler(this);
}
public void start() {
run = true;
frame.add(this);
frame.pack();
frame.requestFocus();
frame.setTitle("In The Maze");
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setIconImage(new ImageIcon("res/traps/beartrap1.png").getImage());
t = new Thread(this);
t.start();
}
public void stop() {
run = false;
}
public static void main(String[] args) {
Comp c = new Comp();
c.start();
}
public void render() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
createBufferStrategy(2);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, 1000, 1000);
if (!splashscreen) {
m.render(g);
}
if(splashscreen){
ImageIcon i62 = new ImageIcon("res/splashscreen.png");
img = i62.getImage();
g.drawImage(img,(int)0 ,(int)0,Comp.size.width+10,Comp.size.height + 10,null);
time++;
}
g.dispose();
bs.show();
}
public void tick() {
if(time >= timer){
time = 0;
splashscreen = false;
}
if(!splashscreen){
m.tick();
}
Keys.update();
Esentials.tick();
}
public void run() {
screen = createVolatileImage(pixel.width, pixel.height);
long start;
long elapsed;
long wait;
long currentTime = System.currentTimeMillis();
while (run) {
start = System.nanoTime();
fps++;
if(System.currentTimeMillis() - currentTime >= 1000){
// System.out.println("fps:" + fps);
currentTime = System.currentTimeMillis();
fps = 0;
}
tick();
render();
elapsed = System.nanoTime() -start;
wait = targetTime = elapsed / 1000000;
try {
Thread.sleep(wait);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void keyTyped(KeyEvent i) {
}
public void keyPressed(KeyEvent i) {
Keys.keySet(i.getKeyCode(), true);
}
public void keyReleased(KeyEvent i) {
Keys.keySet(i.getKeyCode(), false);
}
}
Try to use Toolkit.getScreenSize()
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double width = screenSize.getWidth();
double height = screenSize.getHeight();
For resizing the image you can use simple imgscalr library
BufferedImage scaledImage = Scalr.resize(myImage, 100);
Determining the screen size...
How to set present screensize in Java Swing?
Full-Screen Exclusive Mode API
Scaling the image...
Java: maintaining aspect ratio of JPanel background image
Quality of Image after resize very low -- Java
The Perils of Image.getScaledInstance()
I'd also discourage the use KeyListener and encourage the use of the Key Bindings API. See How to use key bindings for more details
Using the default Graphics object from the java.awt package, you can use the drawImage method with 10 parameters:
int destinationWidth = ...;
int destinationHeight = ...;
g.drawImage(originalImage, 0, 0, destinationWidth, destinationHeight, 0, 0, originalImage.getWidth(null), originalImage.getHeight(null), null);
That way your image will be scaled and painted to g. Note that simply by using as in the example provided will stretch and deform your image if the aspect ratio of your window is different from the aspect ratio of the image.
This is a follow up question to an earlier one of mine. I am making a java game, and it is basically a JFrame with a character image, some healthbars consisting of fillRect()s which are all on top of a background image. The problem is the healthbars and character are appearing but the background image isn't.
Here is a shortened version of the Game class which has the main() and render() methods:
public class Game extends Canvas implements Runnable{
public static boolean running = false;
public Thread gameThread;
private BufferedImage playerSpriteSheet;
private ImageManager im;
private static Player player;
private static HealthBar healthBars;
private static BackgroundImage backgroundImage;
public void init(){
ImageLoader loader = new ImageLoader();
playerSpriteSheet = loader.load("/spriteSheet.png");
SpriteSheet pss = new SpriteSheet(playerSpriteSheet);
im = new ImageManager(pss);
backgroundImage = new BackgroundImage("/background.png");
player = new Player(800, 250, im);
healthBars = new HealthBar(200, 200);
this.addKeyListener(new KeyManager());
}
public synchronized void start() {
if(running)return;
running = true;
gameThread = new Thread(this);
gameThread.start();
}
public synchronized void stop() {
if(!running)return;
running = false;
try {
gameThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run() {
init();
long lastTime = System.nanoTime();
final double amountOfTicks = 60D;
double ns = 1_000_000_000/amountOfTicks;
double delta = 0;
long now = System.nanoTime();
while(running)
{
delta += (now - lastTime)/ns;
lastTime = now;
if(delta >= 1)
{
tick();
delta--;
}
render();
}
stop();
}
public void tick() {
player.tick();
}
public void render() {
BufferStrategy bs = this.getBufferStrategy();
if(bs == null)
{
createBufferStrategy(3); //Use 5 at most
return;
}
Graphics g = bs.getDrawGraphics();
//RENDER HERE
backgroundImage.render(g);
player.render(g);
healthBars.render(g);
//END RENDER
g.dispose();
bs.show();
}
public static void main(String[] args)
{
JLabel backgroundImage;
JLabel controlKeyPanel;
JLabel statusLabel;
Game game = new Game();
game.setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
JFrame frame = new JFrame("Title");
frame.setResizable(false);
frame.setSize(WIDTH * SCALE, HEIGHT * SCALE);
frame.setLayout(new BorderLayout());
backgroundImage = new JLabel(new ImageIcon("/background.png"));
String htmlButtonGuide = "words";
controlKeyPanel = new JLabel(htmlButtonGuide);
statusLabel = new JLabel("label");
frame.add(backgroundImage, BorderLayout.CENTER);
frame.add(controlKeyPanel, BorderLayout.EAST);
frame.add(statusLabel, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(game);
frame.setVisible(true);
game.start();
//Program seems to continue running after ESC
}
public static Player getPlayer() {
return player;
}
}
Here is the BackGroundImage class:
public class BackgroundImage {
private Image background = null;
public BackgroundImage(String s) {
if(s == null)
{
background = getImage(s);
}
}
public void render(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.drawImage(background, 0, 0, 1200, 600, null);
}
public Image getImage(String path) {
Image tempImage = null;
File image2 = new File(path);
try {
tempImage = ImageIO.read(image2);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return tempImage;
}
}
I am concerned with the render() method reusing the "g" Graphics object for adding all 3 things to the screen. I was told to not combine lightweight Swing health bars with the heavy AWT background and character? Can anyone point me in the right direction to get the background to show? Should the render method not take care of the background? I only need the background to be put up once. It doesn't need to be constantly updated like the health bars and characters right?
Let's start with...
backgroundImage = new BackgroundImage("/background.png");
Which becomes...
File image2 = new File(path);
or
File image2 = new File("/background.png");
so you can see it...can you see a problem with this? This is requesting a file which resides at the root location of the current drive...not really what I think you want...
The images are stored in a folder called "res" in the main project folder
Which would suggest you want to use...
backgroundImage = new BackgroundImage("res/background.png");
Assuming that the images are not embedded resources....
Next...
public BackgroundImage(String s) {
if (s == null) {
background = getImage(s);
}
}
So, you only ever want to try a load the image when it's reference is null???
Side notes...
frame.setSize(WIDTH * SCALE, HEIGHT * SCALE); is a bad idea, as frames have borders which occupy space within side the frame itself.
Better to override the getPreferredSize method of Canvas and provide a default size value you want to use and then call pack on the frame instead. This will calculate the size of the frame as the preferred size of it's content PLUS the frame border requirements...
You "game loop" is running wild...
while (running) {
delta += (now - lastTime) / ns;
lastTime = now;
if (delta >= 1) {
tick();
delta--;
}
render();
}
Basically, this will run as fast as it possibly can and will reduce the opportunity for other threads to run, eventually bringing your game (and probably your PC) to it's knees
This is "simple" concept of a run loop...
public void run() {
init();
final long amountOfTicks = 60;
long ns = Math.round(1_000_000_000 / (double)amountOfTicks);
int frames = 0;
long frameStart = System.currentTimeMillis();
while (running) {
long startedAt = System.nanoTime();
tick();
render();
long completedAt = System.nanoTime();
long duration = completedAt - startedAt;
long frameEnd = System.currentTimeMillis();
if (frameEnd - frameStart >= 1000) {
System.out.println(frames);
frames = 0;
frameStart = System.currentTimeMillis();
} else {
frames++;
}
long rest = ns - duration;
if (rest > 0) {
rest = TimeUnit.MILLISECONDS.convert(rest, TimeUnit.NANOSECONDS);
try {
Thread.sleep(rest);
} catch (InterruptedException ex) {
}
}
}
stop();
}
Basically, it tries to ensure that there is enough delay between each iteration in order to maintain the 60fps you are trying to target...without starving the system...
I am making a java game and at it's heart, it consists of a JFrame that holds a a JLabel that holds the background image. Early in the project this was being displayed. However, after I implemented a Game render method that put healthbars and a character on screen, the background image no longer displays. Here is the Game's render() and main() methods.
public class Game extends Canvas implements Runnable{
private static final long serialVersionUID = 1L;
public static final int WIDTH = 1200, HEIGHT = 600, SCALE = 1;
public static boolean running = false;
public Thread gameThread;
private BufferedImage playerSpriteSheet;
private ImageManager im;
private static Player player;
private static HealthBar healthBars;
public void init(){
ImageLoader loader = new ImageLoader();
playerSpriteSheet = loader.load("/spriteSheet.png");
SpriteSheet pss = new SpriteSheet(playerSpriteSheet);
im = new ImageManager(pss);
player = new Player(0, 0, im);
healthBars = new HealthBar(200, 200);
this.addKeyListener(new KeyManager());
}
public synchronized void start() {
if(running)return;
running = true;
gameThread = new Thread(this);
gameThread.start();
}
public synchronized void stop() {
if(!running)return;
running = false;
try {
gameThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run() {
init();
long lastTime = System.nanoTime();
final double amountOfTicks = 60D;
double ns = 1_000_000_000/amountOfTicks;
double delta = 0;
long now = System.nanoTime();
while(running)
{
delta += (now - lastTime)/ns;
lastTime = now;
if(delta >= 1)
{
tick();
delta--;
}
render();
}
stop();
}
public void tick() {
player.tick();
}
public void render() {
BufferStrategy bs = this.getBufferStrategy();
if(bs == null)
{
createBufferStrategy(3); //Use 5 at most
return;
}
Graphics g = bs.getDrawGraphics();
//RENDER HERE
player.render(g);
healthBars.render(g);
//END RENDER
g.dispose();
bs.show();
}
public static void main(String[] args)
{
JLabel backgroundImage;
JLabel controlKeyPanel;
JLabel statusLabel;
Game game = new Game();
game.setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
JFrame frame = new JFrame("Java Game");
frame.setResizable(false);
frame.setSize(WIDTH * SCALE, HEIGHT * SCALE);
frame.setLayout(new BorderLayout());
backgroundImage = new JLabel(new ImageIcon("/background.png"));
String htmlButtonGuide = "<html>← - Move Left<br>→ - Move Right<br>A - Attack<br>S - Fire Gun<br>P - Position<br>esc - Exit</html>";
controlKeyPanel = new JLabel(htmlButtonGuide);
statusLabel = new JLabel("Game Status");
frame.add(backgroundImage, BorderLayout.CENTER); //This should be displaying the background image
frame.add(controlKeyPanel, BorderLayout.EAST);
frame.add(statusLabel, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(game);
frame.setVisible(true);
game.start();
}
public static Player getPlayer() {
return player;
}
}
Here is the catch, and where I think part of the issue is visible. Inside the render() method there are these 2 lines:
player.render(g);
healthBars.render(g);
If I put player.render(g) first, then both the player and health bars appear on the screen. However, if I put healthBars.render(g) before player.render(g), then the player doesn't appear. This really confuses me, because I would expect the one that renders second causes the first one to be hidden behind, but the opposite happens. Could anyone point me in the right direction?
BufferStrategy doesn't play well with Swing, as you've taken control of the painting process
Canvas can't be transparent, so it will hide anything beneath it...
When you use frame.add(game) you are replaceing what ever use to be at BorderLayout.CENTER
Instead of mixing lightweight (Swing) and heavy weight (AWT) components, paint the background image as part of your render process
public void render() {
BufferStrategy bs = this.getBufferStrategy();
if(bs == null)
{
createBufferStrategy(3); //Use 5 at most
return;
}
Graphics g = bs.getDrawGraphics();
//RENDER HERE
// Paint background here...
player.render(g);
healthBars.render(g);
//END RENDER
g.dispose();
bs.show();
}