I have a game JPanel that is added to a frame. The gamePanel (posted below) is meant to render movements every frame. public Game() {
public Game() {
Dimension dimension = new Dimension(Game.WIDTH, Game.HEIGHT);
setPreferredSize(dimension);
setMaximumSize(dimension);
setMinimumSize(dimension);
setVisible(true);
player = new Player(Game.WIDTH / 2, Game.HEIGHT / 2);
level = new Level("/map/map.png");
spriteSheet = new SpriteSheet("/sprites/sprites.png");
new Texture();
start();
setFocusable(true);I cant seem to get the action to happen.
//other game functions like keybindings.
The code that handles the frame rate and what is supposed to paint() to the frame is...
#Override
public void run() {
requestFocus();// This does not require the mouse to click frame for it to work
int fps = 0;
double timer = System.currentTimeMillis();
long lastTime = System.nanoTime();
double targetTick = 60.0;
double delta = 0;
double ns = 1000000000 / targetTick;
while (isRunning) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
this.tick();
repaint();//not sure if this is right I just want the frame to update the position of the player and the level
fps++;
delta--;
}
if (System.currentTimeMillis() - timer >= 1000) {
fps = 0;
timer += 1000;
}
}
stop();
}
public synchronized void start() {
System.out.println("start accessed");//this does get accessed
if (isRunning) return;
isRunning = true;
thread = new Thread(this);//UPDATED
thread.start();
}
public synchronized void stop() {
if (!isRunning) return;
isRunning = false;
try {
thread.join();// what does thread join do?
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void tick() {
if (enter) { //enter boolean
System.out.println(enter);
player.tick();
level.tick();
repaint();
revalidate();
}
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, Game.WIDTH, Game.HEIGHT);
player.render(g);
level.render(g);
}
essentially the level and the player move over time. I had it working with on a canvas however since then converted the program to use JPanel.
Thanks for any help.
Related
I have this code from this tutorial https://youtu.be/Nn8LH6T3xuc
and I can't understand why is running so slow.
There is a thread that handles the game loop and renders the graphics on screen.
Before the implementation of the render() method it runs nice..
There is a thread that handles the game loop and renders the graphics on screen.
public class Game extends Canvas implements Runnable {
public static final int WIDTH = 420;
public static final int HEIGHT = WIDTH / 12 * 9;
public static final int SCALE = 2;
private boolean running = false;
private Thread thread;
private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
#Override
public void run() {
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;
}
}
stop();
}
private void tick() { }
private void render() {
BufferStrategy bs = this.getBufferStrategy();
if(bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
//////////////////////////////////
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
//////////////////////////////////
g.dispose();
bs.show();
}
public static void main(String[] args) {
//jframe creation etc...
game.start();
}
public synchronized void start() {
if(running) return;
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop() {
if(!running) return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.exit(1);
}
}
I have this code for a game called Wave, and normally when I run it, it should be a black window with white squares in it. But the window is white, with a very thin black stripe on the left of the window. I can barely see it.
Does anybody have any idea on why would this happen?
package wave.myFirstGame;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.Random;
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 3580879553502102315L;
public static final int WITDH = 640, HEIGHT = WITDH / 12 * 9;
private Thread thread;
private boolean running = false;
private Random r;
public Handler handler;
public Game() {
new Window(WITDH, HEIGHT, "Wave", this);
handler = new Handler();
r = new Random();
for(int i = 0; i < 50; i++){
handler.addObject(new Player(r.nextInt(WIDTH), r.nextInt(HEIGHT), ID.Player));
}
handler.addObject(new Player(200, 200, ID.Player));
}
public synchronized void start() {// initializing the thread
thread = new Thread(this);
thread.start();
running = true;
}
public synchronized void stop() {
try {
thread.join();
running = false;
} catch (Exception e) {
e.printStackTrace();
}
}
// GAME LOOP
public void run() {
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
tick();
delta--;
}
if (running)
render();
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println("FPS " + frames);
frames = 0;
}
}
stop();
}
private void tick(){
handler.tick();
}
private void render(){
BufferStrategy bs = this.getBufferStrategy();
if(bs == null){
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, WIDTH, HEIGHT);
handler.render(g);
g.dispose();
bs.show();
}
public static void main(String[] args) {
new Game();
}
}
Have a look into the API of Canvas. There you will find:
Fields inherited from interface java.awt.image.ImageObserver
[...] HEIGHT, [...], WIDTH
So since you extend your class from Canvas class you already have WIDTH and HEIGHT constants and for some reason WIDTH seams to have value 1.
So simply rename your constants and it will display as expected.
I have designed a code for a game. The problem is that the background won't change to any of my selected colors I have picked from graphics color library.
I need someone to figure this out with the code i have provided (please don't make a whole new code). idk why java/ eclipse won't display it??? am i missing something?? The program here should display a GUI with a background color blue. instead i get white.
public class MainApp extends Canvas implements Runnable {
private static final long serialVersionUID = 8928635543572788908L;
private static final int WIDTH= 648, HEIGHT= WIDTH/ 12 * 9;
private Thread thread;
private boolean running= false;
public MainApp()
{
new Window(WIDTH, HEIGHT, "App", this);
}
public synchronized void start()
{
thread= new Thread(this);
thread.start();
running= true;
}
public void run()
{
long lastTime= System.nanoTime();
double amountOfTicks= 60.0;
double ns= 1000000000 / amountOfTicks;
double delta= 0;
long timer= System.currentTimeMillis();
int frames= 0;
while(running){
long now= System.nanoTime();
delta += (now- lastTime) / ns;
lastTime= now;
while(delta >= 1){
tick();
delta--;
}
if(running)
render();
frames++;
if(System.currentTimeMillis() - timer > 1000)
{
timer += 1000;
System.out.print("FPS: " + frames);
frames= 0;
}
}
stop();
}
public synchronized void stop()
{
try
{
thread.join();
running= false;
}catch(Exception e){e.printStackTrace();}
}
public void tick()
{
}
public void render()
{
BufferStrategy bs= this.getBufferStrategy();
if(bs== null)
{
this.createBufferStrategy(3);
return;
}
Graphics g= bs.getDrawGraphics();
g.setColor(Color.BLUE);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.dispose();
bs.show();
}
public static void main(String[] args) {
new MainApp();
}
}
Your codes a little messed up, you shouldn't be making a new instance of Window from MainApp, the Window should be creating it (IMHO).
Also, you should be overriding the getPreferredSize method the the MainApp, as this is what should be controlling the viewable size of the window, this way, when you use pack on the JFrame, it will ensure that the window is larger then the preferredSize of it's contents, allowing the frame decorations to wrap around the outside of it.
BUT, the main problem you have, is adding the MainApp to the JFrame AFTER it's already been made visible
The following works for me...
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class MainApp extends Canvas implements Runnable {
private static final long serialVersionUID = 8928635543572788908L;
private static final int WIDTH = 648, HEIGHT = WIDTH / 12 * 9;
private Thread thread;
private boolean running = false;
public MainApp() {
new Window("App", this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(WIDTH, HEIGHT);
}
public synchronized void start() {
thread = new Thread(this);
thread.start();
running = true;
}
public void run() {
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
tick();
delta--;
}
if (running) {
render();
}
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.print("FPS: " + frames);
frames = 0;
}
}
stop();
}
public synchronized void stop() {
try {
thread.join();
running = false;
} catch (Exception e) {
e.printStackTrace();
}
}
public void tick() {
}
public void render() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.BLUE);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.dispose();
bs.show();
}
public static void main(String[] args) {
new MainApp();
}
public static class Window {
private Window(String title, MainApp app) {
JFrame frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(app);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
app.start();
}
}
}
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...
If you run the program, you can see that it prints "Run() method is called", when the run gets called. But the System.out.println() inside the if statement does not get called nor the render() method gets called.
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable {
public static int WIDTH = 300;
public static int HEIGHT = WIDTH / 16*9;
public static int SCALE = 3;
public static String TITLE = "";
private Thread thread;
private boolean running = false;
private JFrame frame;
public void start() {
if(running) return;
thread = new Thread(this);
thread.start();
}
public void stop() {
if(!running) return;
try{
thread.join();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
System.out.println("Run() has been called");
long lastTime = System.nanoTime();
long timer = System.currentTimeMillis();
double ns = 1000000000.0 / 60.0;
double delta = 0;
int ticks = 0;
int fps = 0;
while(running) {
long now = System.nanoTime();
delta += (now-lastTime) / ns;
lastTime = now;
while(delta >= 1) {
tick();
ticks++;
delta--;
}
render();
fps++;
if(System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println("Fps: " + fps + " Ticks: " + ticks);
fps = 0;
ticks = 0;
}
}
stop();
}
public void tick() {
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if(bs==null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.fillRect(36, 25, 25, 25);
g.dispose();
bs.show();
}
public Game() {
setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
frame = new JFrame();
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("SPACE ADAPT PRE-ALPHA 0.001");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
You never set running to true, then it's false. As a side note not related with this question but most of swing components methods are not thread-safe so calling in another thread that is not the Event Dispatch Thread would not work as you expected.
Read more Concurrency in Swing