It's my game loop code:
public void run() {
running = true;
boolean renderCheck = false;
double firstTime = 0;
double lastTime = System.nanoTime() / 1000000000.0;
double passedTime = 0;
double unprocessedTime = 0;
double frameTime = 0;
int frames = 0;
int fps = 0;
while (running) {
firstTime = System.nanoTime() / 1000000000.0;
passedTime = firstTime - lastTime;
lastTime = firstTime;
unprocessedTime += passedTime;
frameTime += passedTime;
while (unprocessedTime >= UPDATE_CAP) {
tick();
unprocessedTime -= UPDATE_CAP;
renderCheck = true;
}
if (frameTime >= 1.0) {
frameTime = 0;
fps = frames;
frames = 0;
System.out.println(fps);
}
if (renderCheck) {
render();
frames++;
renderCheck = false;
} else {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
It's a render zone:
private void render() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics graphics = bs.getDrawGraphics();
graphics.setColor(Color.black);
graphics.fillRect(0, 0, WIDTH, HEIGHT);
handler.render(graphics);
graphics.dispose();
bs.show();
}
And here is a tick part(it's not necessary to show other code for handler because it'll be so much to read):
private void tick() {
handler.tick();
}
So the main problem is in the next thing. When i press the button my character has to start moving. And, actually, it does but with some delays which make this process look terrible. Than after a second, all is going perfectly. (I've already checked CPU loading - all goes normal)
This problem is happening only on linux PC. I've checked it on Windows 10 in exe format and all was working fine! That's a bit weird.
This lazy initialization might be your problem:
private void render() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
return;
}
...
Did you consider the fact on the first call of your render() function the getBufferStrategy() will return null at which point
you will first create it (that is ok)
then return without any action
(that is suspicious)
Subsequent calls of render would actually perform rendering ... later. If you know for sure that you will need that bufferStrategy anyway, it would make sense to create it straight away when initializing your system.
Soo, finally i found a solution for fixing this issue!
Just set system properties to java2d in your static main method by writing this code:
public static void main(String argsp[]) {
System.setProperty("sun.java2d.opengl", "true");
new Game();
}
Related
I'm playing around with graphics in Java. At the moment I have a rectangle that moves from left to right. I want it to start moving left once it hits the right side of the Canvas and left when it hits the right side, i have included a game loop as this will eventually turn into my first very basic game. Thanks.
P.S - I followed some tutorials for different parts of this code hence why it might be a bit messy, I'm working on it :)
Main Class:
public class Game extends JFrame implements Runnable {
private Canvas canvas = new Canvas();
private RenderHandler renderer;
private boolean running = true;
public static int WIDTH = 1200, HEIGHT = WIDTH / 12*9;
public static int moveX =WIDTH/2;
public Game() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(WIDTH, HEIGHT);
setLocationRelativeTo(null);
setLocationRelativeTo(null);
add(canvas);
setVisible(true);
canvas.createBufferStrategy(3);
renderer = new RenderHandler(getWidth(), getHeight());
}
public void update() {
}
public void render() {
BufferStrategy bufferStrategy = canvas.getBufferStrategy();
Graphics graphics = bufferStrategy.getDrawGraphics();
super.paint(graphics);
renderer.render(graphics);
graphics.dispose();
bufferStrategy.show();
}
public void run() {
BufferStrategy bufferStrategy = canvas.getBufferStrategy();
int FRAMES = 0;
int TICKS = 0;
long lastTime = System.nanoTime();
double unprocessed = 0;
double nsPerSecs = 1000000000 /60.0;
long Timer = System.currentTimeMillis();
while(running) {
long now = System.nanoTime();
unprocessed += (now - lastTime) / nsPerSecs;
lastTime = now;
if(unprocessed >= 1) {
TICKS ++;
update();
unprocessed -= 1;
}
try
{
Thread.sleep(3);
}catch (InterruptedException e) {
e.printStackTrace();
}
FRAMES++;
render();
if(System.currentTimeMillis() - Timer > 1000) {
System.out.println("Ticks: " + TICKS + " FPS: " + FRAMES);
TICKS = 0;
FRAMES = 0;
Timer += 1000;
}
}
}
public static void main(String[] args) {
Game game = new Game();
Thread gameThread = new Thread(game);
gameThread.start();
}
}
Class drawing the graphics:
public class RenderHandler {
public RenderHandler(int width, int height) {
}
public void render(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, Game.WIDTH, Game.HEIGHT);
g.setColor(Color.RED);
g.fillRect(Game.moveX, Game.HEIGHT/2, 50, 50);
if (Game.moveX >= Game.WIDTH) {
Game.moveX ++;
} else if (Game.moveX <= 0) {
Game.moveX --;
}else { Game.moveX++;
}
}
}
If you know how to draw on the screen and how stuffs work, I would think that this is more about getting the logic down.
This code slice I so brutally tore from your question is right next to where the rendering takes place (a problem because I view it as rather unorganized; I would recommend game logic and rendering to take place in two different functions). It basically says that it will move right if it is beyond the right of the screen, if not, it will move left if it is beyond the left of the screen, and finally, if not, it will just move left.
if (Game.moveX >= Game.WIDTH) {
Game.moveX ++;
} else if (Game.moveX <= 0) {
Game.moveX --;
}else { Game.moveX++;
}
If you want it to bounce, you will have to use a boolean to keep track of its moving state, or, if you want more versatility, use a pair of floats or doubles (floats are typically used in Java game design) to keep track of its position, and another for its velocity. I'm in a tight squeeze right now, I will return.
Add this to render handler instead of the current if statement in render
bool rol = true; // initialize this outside the method
If(Game.movex + 50 >= Game.width)
rol = false;
Else if(Game.movex <= 0)
rol = true;
If(rol)
Game.movex++;
Else
Game.movex--;
You need to store current moving direction somewhere, so add this to Game class:
public static int deltaX = 1;
And replace condition in render() with
if (Game.moveX >= Game.WIDTH-50) {
Game.deltaX =-1;
} else if (Game.moveX <= 0) {
Game.deltaX =1;
}
Game.moveX += Game.deltaX;
I am building this game in Java. Basically it is minecraft in 2D. I made it so that block objects are deleted when pressed. My block object rendering sometimes gives a nullpointerexception after clicking/deleting a block (randomly after about 200 blocks). It seems as if the object is sometimes deleted while the game is in the renderingloop. When I add a try-catch, the next render cycle does not have the error anymore. Any ideas what is causing this? Is this gameloop a solid one, I suspect that is what is causing my error.
Render method in my handler:
LinkedList<GameObject> object = new LinkedList<GameObject>();
public void render(Graphics g){
for(int i = 0; i < object.size(); i++){
GameObject tempObject = object.get(i);//sometimes nullpointer when getting the object I clicked on
tempObject.render(g);
}
}
Deleting with mouseInput
for(int i = 0; i < handler.object.size(); i++){
if(handler.object.get(i).getID() == ID.Block){
int x1 = (int) handler.object.get(i).getX();
int y1 = (int) handler.object.get(i).getY();
//if mouse is over object
if((MouseX >= x1+1 && MouseX <= (x1 +32-1)) && (MouseY >= y1+1 && MouseY <= (y1 +32-1))){
Block b = (Block) handler.object.get(i);
inventory.addInventoryBlocks(b.getType(), 1);
handler.removeObject(handler.object.get(i));
}
}
}
Gameloop:
public void run() {
this.requestFocus();
long lastTime = System.nanoTime();
double amountOfTicks = 60;
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();
}
I assume your mouse input handler runs as a seperate thread. In this case the deletion of a block can occure within your rendering loop.
A solution would be not to delete the blocks immediately in your mouse handler but to save the blocks to delete in a separate array. These blocks can be handled at a dedicated position in your main loop right before rendering.
Most likely your mouse handler is running in the AWT thread while the render is running in another thread. In this case you would be suffering of concurrency troubles.
Try using a critical section.
public static Object lock = new Object();
public void render(Graphics g){
synchronized(lock)
{
for(int i = 0; i < object.size(); i++){
GameObject tempObject = object.get(i);//sometimes nullpointer when getting the object I clicked on
tempObject.render(g);
}
}
}
void mouseInputHandler()
{
synchronized( lock )
{
code
}
}
This could be better refined knowing more about your code's structure but it should get you going in the right direction.
Assuming you are using different threads for updating the game state and rendering, this behavior does not seem that odd to me, as one thread might have deleted an object as the other tries to render it.
A good way to debug this is to force sequential execution of your code. Check if the current behavior persists. A nice introduction (Android) to game loops can be found here
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm fairly new to game programming in Java and I was wondering if someone could help me out with my game loop. I'm trying to avoid using premade engine libraries (I want to see if I can do it myself). Currently, my game loop is giving me a really low FPS, sometimes even in the single digits. Would this be a case where I have to use multithreading? Or is there a better fix to this problem? Any help is much appreciated!
Here is the code which runs the game loop. I don't include all of the code (because it would be a lot of files), but I think this might be enough, tell me if you need more. I also include a screenshot of the game that I'm trying to create. Thanks in advance!
package com.Farthorn.game;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferStrategy;
import javax.swing.ImageIcon;
public class Game extends Canvas implements Runnable
{
private static final long serialVersionUID = -4431078110090264106L;
public final static int WIDTH = 640;
public final static int HEIGHT = WIDTH / 12 * 9;
private Thread thread;
private boolean running = false;
private CharacterHandler cHandler;
private ObjectHandler oHandler;
public int change = 0;
private String mapBackgroundTop = "/Users/Ahhblala/Desktop/FarthornPics/background_top.png";
private String mapBackgroundBottom = "/Users/Ahhblala/Desktop/FarthornPics/background_bottom.png";
private Image backgroundTop;
private Image backgroundBottom;
public Game()
{
ImageIcon i = new ImageIcon(mapBackgroundTop);
backgroundTop = i.getImage();
i = new ImageIcon(mapBackgroundBottom);
backgroundBottom = i.getImage();
cHandler = new CharacterHandler();
cHandler.addCharacter(new Player(ID.Player, WIDTH/2-32, HEIGHT/2+64));
cHandler.addCharacter(new PlantEnemy(ID.PlantEnemy, WIDTH+180, HEIGHT/2+104, (Player) cHandler.characters.getLast()));
cHandler.addCharacter(new PlantEnemy(ID.PlantEnemy, WIDTH+195, HEIGHT/2+104, (Player) cHandler.characters.get(0)));
cHandler.addCharacter(new PlantEnemy(ID.PlantEnemy, WIDTH+300, HEIGHT/2+104, (Player) cHandler.characters.get(0)));
cHandler.addCharacter(new PlantEnemy(ID.PlantEnemy, WIDTH+315, HEIGHT/2+104, (Player) cHandler.characters.get(0)));
oHandler = new ObjectHandler();
oHandler.addObject(new HUD(10, 10, cHandler));
this.addKeyListener(new KeyInput(cHandler));
this.addMouseListener(new MouseInput(((Player) cHandler.characters.get(0))));
FarthornWindow window = new FarthornWindow(WIDTH, HEIGHT, this);
}
public synchronized void start()
{
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop()
{
try
{
thread.join();
running = false;
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void run()
{
this.requestFocus();
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()
{
int deltaX = 0;
int afterX = 0;
deltaX = cHandler.characters.get(0).getX();
oHandler.tick();
cHandler.tick();
deltaX = cHandler.characters.get(0).getX();
if (deltaX != afterX)
change = (afterX-deltaX);
else
change = 0;
render();
}
private void render()
{
BufferStrategy bs = this.getBufferStrategy();
if (bs == null)
{
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.drawImage(backgroundTop, 0+change, 0, null);
g.drawImage(backgroundBottom, 0+change, 364, null);
oHandler.render(g);
cHandler.render(g);
g.dispose();
bs.show();
}
public static int clamp(int var, int min, int max)
{
if (var >= max)
{
return var = max;
}
else if (var <= min){
return var = min;
}
else
return var;
}
}
As you might be able to tell, I am rendering a lot of outside images.
There's probably something inefficient in your rendering causing it to drop below your target of 60hz. That aside, there's definitely a problem in your "catch up" loop:
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1)
{
tick();
delta--;
}
Since your tick() routine also calls render(), tick() is effectively a frame in itself, but you are not incrementing your frame counter. Your tick() should be causing all the parts to update, but not render the image, render should only be called once per frame. You probably want to remove the render() line from your tick() routine.
I´m having some problems with a small game I´m developing. although I´m using double buffer and was able to get rid of flickering, the movement still looks somewhat jittery and not fluid.
I know it can be caused by increasing the movement in big steps and/or low framerate, but I still have the same problem using increments of 1 and 50+ fps. It´s somewhat difficult to explain, but the sprites move strangely (correctly, but not in a fluid motion)
I would appreciate if someone could point me in the right direction.
public class Gameplay extends javax.swing.JPanel {
GUI gui;
Canvas canvas = new Canvas();
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
BufferedImage bi;
BufferStrategy buffer;
public Gameplay(GUI gui) {
this.gui = gui;
initComponents();
}
// Used to start the gameplay. Called by GUI
public void start() {
new RefreshScreen().start();
}
// ==============================================================================================
// DOUBLE BUFFER AND PAINTING ===================================================================
// ==============================================================================================
Date date = new Date(); // time
int lastSecond = 0; // seconds controll - for FPS calculation
int fpsCount = 0; // Count frames rendered
int showFps = 0; // The total FPS text that will appear on screen
int MAX_FPS = 30; // targeted Max FPS
int MIN_FPS = 24; // targeted Min FPS
int sleepTimeBetweenRefresh = 20; // Delay before new refresh
Color fpsColor = Color.yellow; // color of the FPS information on screen
String fpsInfo = ""; // Aditional info on FPS (increasing, decreasing, etc)
class RefreshScreen extends Thread {
public void run() {
Graphics graphics = null;
Graphics2D bufferGraphics = null;
add(canvas, BorderLayout.CENTER);
canvas.setIgnoreRepaint(true);
canvas.setVisible(true);
canvas.setSize(gui.getWidth(), gui.getHeight());
canvas.createBufferStrategy(2);
buffer = canvas.getBufferStrategy();
bi = gc.createCompatibleImage(gui.getWidth(), gui.getHeight());
bufferGraphics = bi.createGraphics();
while (true) {
try {
//FrameRate count
date = null;
date = new Date();
if (lastSecond != date.getSeconds()) {
lastSecond = date.getSeconds();
showFps = fpsCount;
fpsCount = 0;
if (showFps > MAX_FPS) {
sleepTimeBetweenRefresh++;
fpsInfo = "(--)";
fpsColor = Color.blue;
}
if ((showFps < MIN_FPS) && (sleepTimeBetweenRefresh > 5)) {
sleepTimeBetweenRefresh--;
fpsInfo = "(++)";
}
if (showFps < MIN_FPS) {
fpsColor = Color.red;
}
if ((showFps > MIN_FPS) && (showFps <= MAX_FPS)) {
fpsColor = Color.green;
fpsInfo = "(ok)";
}
}
fpsCount++;
//Clear canvas =============================
bufferGraphics.setColor(Color.black);
bufferGraphics.clearRect(0, 0, gui.getWidth(), gui.getHeight());
//FPS =============================
bufferGraphics.setColor(fpsColor);
bufferGraphics.drawString("FPS: " + showFps, 3, 15);
bufferGraphics.setColor(Color.black);
//SPRITES =============================
try {
for (int count = 0; count < Sprites.getSprites().size(); count++) {
bufferGraphics.drawImage(Sprites.getSprite(count).getImage(), Sprites.getSprite(count).getX(), Sprites.getSprite(count).getY(), null);
}
} catch (Exception e) { }
//HERO =============================
try {
bufferGraphics.drawImage(Sprites.getHero().getImage(), Sprites.getHero().getX(), Sprites.getHero().getY(), null);
} catch (Exception e) { }
// PAINT BUFFER =================================
try {
graphics = buffer.getDrawGraphics();
graphics.drawImage(bi, 0, 0, null);
if (!buffer.contentsLost()) {
buffer.show();
}
} catch (Exception e) { }
// SLEEP =================================
sleep(sleepTimeBetweenRefresh);
} catch (Exception e) { }
}//while
}//run
}//inner class
I would also like to point out that the X and Y of the sprite are being handled so that it doesn´t go right and then down - for instance - when it is supposed to go diagonally. I don´t suppose that´s the problem anyways since the problems occurs even on a straight line.
You might try timing how long it takes to draw everything then subtracting that from your sleep time.
long beforeTime = System.currentTimeMillis();
// do all drawing
sleepTimeBetweenRefresh -= System.currentTimeMillis() - beforeTime;
if(sleepTimeBetweenRefresh < 0) sleepTimeBetweenRefresh = 0;
This helps ensure that your thread is firing every 50ms (or whatever sleepTimeBetweenRefresh is). Say you want it to fire ever 50ms, your drawing takes 10ms. Without the code above after the code ran one time you would actually be painting 60ms after the last paint because you painted for 10 and slept for 50. By subtracting the time it took to paint the components you can keep your FPS stable.
Hey guys on my 2D game the movement speed varies.. I was making my game on my Desktop and it ran fine but then I went on my laptop and the Player moved slower then the Desktop.
Here is my current game loop:
public void gameLoop() throws IOException {
isRunning = true;
while(isRunning == true) {
Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();
//main game loop
//updates everything and draws
//main componenets
//e.g. Player
// clear the screen
g2d.setColor(Color.lightGray);
g2d.fillRect(0,0,640,496);
//drawing
player.paint(g2d);//paint player
map.paint(g2d);//paint each wall in wall list
g2d.dispose();
strategy.show();
//update
try { player.updateMovement(); } catch (Exception e) {};
try { Thread.sleep(4); } catch (Exception e) {};
}
}
Here is my player.updateMovement() method:
public void updateMovement() {
if(!down || !up) {
ny = 0;
}
if(!left || !right) {
nx = 0;
}
if(left) {
nx = -1;
}
if(right) {
nx = 1;
}
if(up) {
ny = -1;
}
if(down) {
ny = 1;
}
if ((nx != 0) || (ny != 0)) {
x += nx;
y += ny;
}
}
How can I fix this issue?
You could have a fixed-rate drawing loop: every iteration should last the same, and if there is some time left, sleep that amount of time. For instance, if we fix a period of 41.6 ms (which is 24 fps), and a certain iteration lasts 20 ms, then you should sleep 41.6 - 20 = 21.6 ms that pass.
If your code is too heavy to run in that time on a low end PC, then you can increase the period so that every machine can cope with it.
By the way, you could also optimize your code.
You can find more information on gaming.stackexange.com