So, I'm writing a small game. I have a JPanel inside of a JFrame and the JFrame repaints in the game engine class every frame, but the player sprite will not react to keypress events.
Any help?
Oh, I'm not entirely sure what code to post because I can't seem to find the source of the problem in any way so just tell me what code you wish to see.
Run method in the engine:
#Override
public void run() {
long lastTime = System.nanoTime();
double nsPerTick = 1000000000D / 60D;
int ticks = 0;
int frames = 0;
long lastTimer = System.currentTimeMillis();
double delta = 0;
init();
while (engineRunning) {
long now = System.nanoTime();
delta += (now - lastTime) / nsPerTick;
lastTime = now;
boolean shouldRender = true;
while (delta >= 1) {
ticks++;
tick();
delta -= 1;
shouldRender = true;
}
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (shouldRender) {
frames++;
render();
}
if (System.currentTimeMillis() - lastTimer >= 1000) {
lastTimer += 1000;
frames = 0;
ticks = 0;
}
}
}
Tick & render in engine class:
public void tick() {
for (BaseEntity e : worldEntities) {
e.tick();
}
}
public void render() {
frame.repaint();
}
Player tick:
public void tick() {
Position.X += Position.velX;
Position.Y += Position.velY;
if (Position.velX > Max_Speed)
Position.velX = Max_Speed;
if (Position.velY > Max_Speed)
Position.velY = Max_Speed;
}
Related
So I wrote this code for a game and now that game is very speeded up. I want to lower the FPS so that the game slows down a bit.
I thought the only way out for me is to make a timer. But I'm finding it difficult to locate where to place the timer? Can anyone help me with this?
So I wrote this code for a game and now that game is very speeded up. I want to lower the FPS so that the game slows down a bit.
I thought the only way out for me is to make a timer. But I'm finding it difficult to locate where to place the timer? Can anyone help me with this?
public class Gamepanel extends JPanel implements Runnable, KeyListener {
private static final long serialVersionUID = 1L;
public static final int WIDTH = 500, HEIGHT = 500;
private Thread thread;
private boolean running;
private boolean right = false, left = false, up = false, down= false;
private BodyPart b;
private ArrayList<BodyPart> snake;
private Apple apple;
private ArrayList<Apple> apples;
private Random r;
private int xCoor = 10, yCoor = 10, size = 1;
private int ticks = 0;
public Gamepanel(){
setFocusable(true);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
addKeyListener(this);
snake = new ArrayList<BodyPart>();
apples = new ArrayList<Apple>();
r = new Random();
start();
}
public void start () {
running = true;
thread = new Thread(this);
thread.start();
}
public void stop() {
running = false;
try {
thread.join();
} catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void tick() {
if(snake.size()==0) {
b= new BodyPart(xCoor, yCoor, 10);
snake.add(b);
}
ticks++;
if(ticks > 250000) {
if(right) xCoor++;
if(left) xCoor--;
if(up) yCoor--;
if(down) yCoor++;
ticks = 0;
b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);
if(snake.size() > size) {
snake.remove(0);
}
}
if(apples.size()==0) {
int xCoor = r.nextInt(49);
int yCoor = r.nextInt(49);
apple = new Apple(xCoor,yCoor,10);
apples.add(apple);
}
for(int i = 0; i < apples.size(); i++) {
if(xCoor == apples.get(i).getxCoor() && yCoor == apples.get(i).getyCoor()) {
size++;
apples.remove(i);
i++;
}
}
//COLLISION ON SNAKE BODY
for (int i = 0; i < snake.size(); i++) {
if(xCoor == snake.get(i).getxCoor() && yCoor == snake.get(i).getyCoor()) {
if(i != snake.size() - 1) {
System.out.print("Game Over");
stop();
}
}
//COLLISION ON BORDER
if(xCoor < 0 || xCoor > 49 || yCoor < 0 || yCoor > 49) {
System.out.print("Game Over" + '\n');
System.out.println("Your Score is: " + snake.size());
stop();
}
}
}
public void paint(Graphics g) {
g.clearRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
g.fillRect(0, 0, WIDTH, HEIGHT);
for (int i=0; i< WIDTH/10; i++) {
g.drawLine(i * 10, 0, i * 10, HEIGHT);
}
for (int i=0; i< HEIGHT/10; i++) {
g.drawLine(0, i * 10, HEIGHT, i * 10);
}
for (int i = 0; i< snake.size(); i++) {
snake.get(i).draw(g);
}
for (int i = 0; i< apples.size(); i++) {
apples.get(i).draw(g);
}
}
#Override
public void run() {
while(running) {
tick();
repaint();
}
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_D && !left) {
right = true;
up = false;
down=false;
}
if(key == KeyEvent.VK_A && !right) {
left = true;
up = false;
down = false;
}
if(key == KeyEvent.VK_W && !down) {
up=true;
left=false;
right=false;
}
if(key == KeyEvent.VK_S && !up) {
down=true;
left=false;
right=false;
}
}
#Override
public void keyReleased(KeyEvent e) {
}
}
The problem with your code is that now, game speed won't be the same on different machines, as some computers may execute your code faster and some may execute slower.
If you want your game to execute on every computer with the same speed you need define some kind of speed for your snake (unit per second) and then in game loop update your snake position based on how much time elapsed from last frame (last call of tick method)
// snake speed
double speed = 1.0; // units per second
// in game loop (your tick method)
position = speed * deltaTime;
now your position is not anymore depended on game framerate. On faster devices game will update snake position more often but deltaTime will be smaller as well as changes of position, on the other hand on slower devices tick method will be called less frequent but deltaTime will be higher
I'm making a small asteroids game, and I'm having some trouble controlling the animation speed.
For example, let's say I have 20 asteroids in my game, when I destroy an asteroid, the amount of asteroids goes down (obviously). Because there are fewer objects in the game, the fps goes up and the animation speed of the asteroids is getting faster and faster.
I fixed it by adjusting the animation speed according to the amount of asteroids I have in the game, but I'm also facing another problem with the explosions when I destroy an asteroid. I could do the same thing I did with the asteroids I suppose, but I just think it's not a very wise way to "solve" it and just seems like bad practice to me.
I thought of capping the fps, but I'm not really sure how to do it. I'd like to get some advices and what's the best way to deal with such situations.
I'll post here my main game class including the game loop, and an example of the explosion class so you'll get the general idea of the code.
Game class and loop:
import com.asteroids.view.*;
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = -8921419424614180143L;
public static final int WIDTH = 1152, HEIGHT = WIDTH / 8 * 5;
private Thread thread;
private boolean isRunning;
private LoadImages loadImages = new LoadImages();
private Player player = new Player();
private AllObjects objects;
private KeyInput keyInput;
private long delay = 80;
private long currentTime = System.currentTimeMillis();
private long expectedTime = currentTime + delay;
public static BufferedImage test;
public Game() {
new Window(WIDTH, HEIGHT, "Asteroids!", this);
objects = new AllObjects();
objects.addObject(player);
for (int i = 0; i < 20; i++) {
objects.addObject(new Rock((int) (Math.random() * (Game.WIDTH - 64) + 1),
(int) (Math.random() * (Game.HEIGHT - 64) + 1)));
}
keyInput = new KeyInput(player);
this.addKeyListener(keyInput);
}
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;
// main game loop.
while (isRunning) {
adjustAsteroidsSpeed();
destroyAsteroids();
collisionLoop();
// used to set delay between every bullet(milliseconds)
currentTime = System.currentTimeMillis();
if (KeyInput.shoot && currentTime >= expectedTime) {
// calculates the accurate position of the x,y on the "circumference" of the
// player
float matchedX = player.getX() + 1 + (float) ((player.getRadius() + 32) * Math.cos(player.getRadian()));
float matchedY = player.getY() - 7 + (float) ((player.getRadius() + 32) * Math.sin(player.getRadian()));
objects.addObject(new Bullet(matchedX, matchedY, player));
expectedTime = currentTime + delay;
}
destroyBullets();
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
tick();
delta--;
}
if (isRunning)
render();
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println("FPS: " + frames);
frames = 0;
}
}
render();
stop();
System.exit(1);
}
private void stop() {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.exit(1);
}
private void render() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.drawImage(LoadImages.getbackground(), 0, 0, getWidth(), getHeight(), this);
objects.render(g);
player.render(g);
g.dispose();
bs.show();
}
private void tick() {
player.tick();
objects.tick();
}
// starting thread and game loop.
public void start() {
thread = new Thread(this);
thread.start();
isRunning = true;
}
// minimum and maximum possible position for object.
public static float Bounds(float value, float min, float max) {
if (value >= max) {
return value = max;
}
if (value <= min) {
return value = min;
} else {
return value;
}
}
// detects collision between two objects
public boolean collision(GameObject a, GameObject b) {
return (b.getX() - a.getX() + 10) * (b.getX() - a.getX() + 10)
+ (b.getY() - a.getY() + 10) * (b.getY() - a.getY() + 10) < (a.getRadius() + b.getRadius())
* (a.getRadius() + b.getRadius());
}
// destroys bullets once they go out of the screen
public void destroyBullets() {
for (int i = 0; i < objects.getSize(); i++) {
if (objects.get(i).getId() == ID.BULLET) {
GameObject bullet = objects.get(i);
if (bullet.getX() > Game.WIDTH || bullet.getX() < 0 || bullet.getY() > Game.HEIGHT
|| bullet.getY() < 0) {
objects.removeObject(bullet);
}
}
}
}
// whenever a collision between an asteroid and a bullet occurs, the asteroid and the bullets are destroyed
public void destroyAsteroids() {
GameObject bullet = null;
GameObject bigRock = null;
for (int i = 0; i < objects.getSize(); i++) {
if (objects.get(i).getId() == ID.BULLET) {
bullet = (Bullet) objects.get(i);
for (int q = 0; q < objects.getSize(); q++) {
if (objects.get(q).getId() == ID.BIGROCK) {
bigRock = objects.get(q);
if (bullet != null && bigRock != null) {
if (collision(bigRock, bullet)) {
objects.addObject(new Explosion(bigRock.getX(), bigRock.getY(), objects));
objects.removeObject(bigRock);
objects.removeObject(bullet);
}
}
}
}
}
}
}
// calculates the amount of asteroids in the game and adjust the asteroids speed
public void adjustAsteroidsSpeed() {
int rocksCount = 0;
Rock rock;
for (GameObject object : objects.link()) {
if (object.getId() == ID.BIGROCK) {
rocksCount++;
}
}
for (GameObject object : objects.link()) {
if (object.getId() == ID.BIGROCK) {
rock = (Rock) object;
rock.setAnimSpeed(rocksCount * 0.002f);
}
}
}
Explosion class:
package com.asteroids.model;
import java.awt.Graphics;
import java.awt.Image;
import com.asteroids.controller.*;
import com.asteroids.view.LoadImages;
public class Explosion extends GameObject {
private AllObjects objects;
private Image explosion;
private float frame = 0;
private float animSpeed = 0.09f;
private int frameCount = 48;
public Explosion(float x, float y, AllObjects objects) {
super(x, y, ID.EXPLOSION, 1);
this.objects = objects;
}
public void render(Graphics g) {
explosion(g);
}
public void explosion(Graphics g) {
frame += animSpeed;
if (frame > frameCount) {
frame -= frameCount;
}
explosion = LoadImages.getExplosion().getSubimage((int) frame * 256, 0, 256, 256);
g.drawImage(explosion, (int) x, (int) y, 110, 110, null);
if (frame >= 47.8f) {
objects.removeObject(this);
}
}
public void tick() {
}
public void setAnimSpeed(float animSpeed) {
this.animSpeed = animSpeed;
}
}
Your main loop is generating uneven updates. If I do nothing, I get anywhere between 7799913 and 8284754 fps, however, if I throw in a 8 millisecond delay (to simulate some work), it drops to around 115-120 fps.
Your intention is to try and get the frame rate to be as even as possible, this will ensure that the animation speed remains the same
Personally, I don't like the "free-wheeling" style of game loop, it means that the loop is been allowed to consume CPU cycles without actually doing anything, where those cycles could be been used to do more important work, like update the UI.
In most cases, I just use a Swing Timer set to something like 5 millisecond intervals and then make use of the date/time API to calculate the difference between now and the last update and make choices about what to do, but, this assumes you're using a Swing based painting path. If you're doing a direct painting path (ie BufferStrategy), you could use a similar idea with a "loop" instead...
public void run() throws InterruptedException {
int frames = 0;
Duration threashold = Duration.ofMillis(1000 / 59);
Duration cycle = Duration.ofSeconds(1);
Instant cycleStart = Instant.now();
// main game loop.
while (isRunning) {
Instant start = Instant.now();
// Some update function...
Thread.sleep(rnd.nextInt(32));
Duration processTime = Duration.between(start, Instant.now());
Duration remainingTime = threashold.minusMillis(processTime.toMillis());
long delay = remainingTime.toMillis();
if (delay > 0) {
Thread.sleep(delay);
} else {
System.out.println("Dropped frame");
}
frames++;
// Render the output
Duration cycleTime = Duration.between(cycleStart, Instant.now());
if (cycleTime.compareTo(cycle) >= 0) {
cycleStart = Instant.now();
System.out.println(frames);
frames = 0;
}
}
}
In this example, your update and paint scheduling code simply have 16 milliseconds to get there job done, otherwise it will drop frames. If the work takes less then 16 milliseconds, the loop will "wait" the remaining time in order to provide some breathing room for the CPU to give time to other threads (and not take update unnecessary time on the CPU)
In the example above, I generate a "random" delay of up to 32 milliseconds for testing. Set it back to 16 and you should get (roughly) 60fps.
Now, I know people are extraordinarily passionate about these things, so if using Thread.sleep and Duration make your skin crawl, you "could" use a "free wheeling" loop, something like the one presented in Java Main Game Loop
Below is a sample implementation, I've set the number of updates and frames per second to 60, but you can change those values to suit your needs...
public void run() throws InterruptedException {
double ups = 60;
double fps = 60;
long initialTime = System.nanoTime();
final double timeU = 1000000000 / ups;
final double timeF = 1000000000 / fps;
double deltaU = 0, deltaF = 0;
int frames = 0, ticks = 0;
long timer = System.currentTimeMillis();
while (isRunning) {
long currentTime = System.nanoTime();
deltaU += (currentTime - initialTime) / timeU;
deltaF += (currentTime - initialTime) / timeF;
initialTime = currentTime;
if (deltaU >= 1) {
Thread.sleep(rnd.nextInt(32));
//getInput();
//update();
ticks++;
deltaU--;
}
if (deltaF >= 1) {
Thread.sleep(rnd.nextInt(32));
//render();
frames++;
deltaF--;
}
if (System.currentTimeMillis() - timer > 1000) {
System.out.println(String.format("UPS: %s, FPS: %s", ticks, frames));
frames = 0;
ticks = 0;
timer += 1000;
}
}
}
Again, the Thread.sleep here is just to inject a random amount of "work". Because it allows for more then 16ms of delay, you will also find it "drops" frames. Your job would be to get you work down to under 16ms per pass
First let me describe what I mean by stutter. When the player moves it looks as if it moves forward a little then back to where it should be and keeps doing it. I am making a small game for learning purposes in lwjgl3 and I am using JOML as my math library. I implemented a fixed time step loop (FPS = 60 and UPS = 30) and I use interpolation to try and smooth my player movement. It works nicely sometimes (not as smooth as I want it though) but other times its just as stuttery as without it. Any ideas on how to fix this? Am I doing the interpolation correctly?
Game Loop:
#Override
public void run() {
window.init("Game", 1280, 720);
GL.createCapabilities();
gameApp.init();
timer.init();
float delta;
float accumulator = 0f;
float interval = 1f / Settings.TARGET_UPS;
float alpha;
while (running) {
delta = timer.getDelta();
accumulator += delta;
gameApp.input();
while (accumulator >= interval) {
gameApp.update();
timer.updateUPS();
accumulator -= interval;
}
alpha = accumulator / interval;
gameApp.render(alpha);
timer.updateFPS();
timer.update();
window.update();
if (Settings.SHOW_PERFORMANCE) {
System.out.println("FPS: " + timer.getFPS() + " UPS: " + timer.getUPS());
}
if (window.windowShouldClose()) {
running = false;
}
}
gameApp.cleanUp();
window.cleanUp();
}
SpriteRenderer:
public class SpriteRenderer {
public StaticShader staticShader;
public SpriteRenderer(StaticShader staticShader, Matrix4f projectionMatrix) {
this.staticShader = staticShader;
staticShader.start();
staticShader.loadProjectionMatrix(projectionMatrix);
staticShader.stop();
}
public void render(Map<TexturedMesh, List<Entity>> entities, float alpha) {
for (TexturedMesh mesh : entities.keySet()) {
prepareTexturedMesh(mesh);
List<Entity> batch = entities.get(mesh);
for (Entity entity : batch) {
Vector2f spritePos = entity.getSprite().getTransform().getPosition();
Vector2f playerPos = entity.getTransform().getPosition();
spritePos.x = playerPos.x * alpha + spritePos.x * (1.0f - alpha);
spritePos.y = playerPos.y * alpha + spritePos.y * (1.0f - alpha);
prepareInstance(entity.getSprite());
GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, entity.getSprite().getTexturedMesh().getMesh().getVertexCount());
}
unbindTexturedMesh();
}
}
private void unbindTexturedMesh() {
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
GL30.glBindVertexArray(0);
}
private void prepareInstance(Sprite sprite) {
Transform spriteTransform = sprite.getTransform();
Matrix4f modelMatrix = Maths.createModelMatrix(spriteTransform.getPosition(), spriteTransform.getScale(), spriteTransform.getRotation());
staticShader.loadModelMatrix(modelMatrix);
}
private void prepareTexturedMesh(TexturedMesh texturedMesh) {
Mesh mesh = texturedMesh.getMesh();
mesh.getVao().bind();
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
texturedMesh.getTexture().bind();
}
}
EntityPlayer:
public class EntityPlayer extends Entity {
private float xspeed = 0;
private float yspeed = 0;
private final float SPEED = 0.04f;
public EntityPlayer(Sprite sprite, Vector2f position, Vector2f scale, float rotation) {
super(sprite, position, scale, rotation);
this.getSprite().getTransform().setPosition(position);
this.getSprite().getTransform().setScale(scale);
this.getSprite().getTransform().setRotation(rotation);
}
#Override
public void update() {
this.getTransform().setPosition(new Vector2f(this.getTransform().getPosition().x += xspeed, this.getTransform().getPosition().y += yspeed));
}
public void input() {
if (KeyboardHandler.isKeyDown(GLFW.GLFW_KEY_RIGHT)) {
xspeed = SPEED;
} else if (KeyboardHandler.isKeyDown(GLFW.GLFW_KEY_LEFT)) {
xspeed = -SPEED;
} else {
xspeed = 0;
}
if (KeyboardHandler.isKeyDown(GLFW.GLFW_KEY_UP)) {
yspeed = SPEED;
} else if (KeyboardHandler.isKeyDown(GLFW.GLFW_KEY_DOWN)) {
yspeed = -SPEED;
} else {
yspeed = 0;
}
}
}
Timer:
public class Timer {
private double lastLoopTime;
private float timeCount;
private int fps;
private int fpsCount;
private int ups;
private int upsCount;
public void init() {
lastLoopTime = getTime();
}
public double getTime() {
return GLFW.glfwGetTime();
}
public float getDelta() {
double time = getTime();
float delta = (float) (time - lastLoopTime);
lastLoopTime = time;
timeCount += delta;
return delta;
}
public void updateFPS() {
fpsCount++;
}
public void updateUPS() {
upsCount++;
}
// Update the FPS and UPS if a whole second has passed
public void update() {
if (timeCount > 1f) {
fps = fpsCount;
fpsCount = 0;
ups = upsCount;
upsCount = 0;
timeCount -= 1f;
}
}
public int getFPS() {
return fps > 0 ? fps : fpsCount;
}
public int getUPS() {
return ups > 0 ? ups : upsCount;
}
public double getLastLoopTime() {
return lastLoopTime;
}
}
Your "fixed time step" is not as smooth as you think.
This code:
while (accumulator >= interval) {
gameApp.update();
timer.updateUPS();
accumulator -= interval;
}
may run at 10000000Hz or at 0.1Hz depending on how long gameApp.update()takes to execute.
Edit: You can't take for sure that timer.getDelta() is aproximately the same value each time is called. Same goes for accumulator, which also depends on the remaining value after last -=interval call but starts with a different delta each time.
The OS can take more time for its own proccesses, delaying yours. Sometimes your time-step based on measures may run fine, and the next second it halts for a few milliseconds, enough to mess those measures.
Also, be aware that sending commands to GPU doesn't guarantee they get processed immediately; perhaps they accumulate and later run all in a row.
If you wish some code to be executed every M milliseconds (e.g. 16.6ms for 60 FPS) then use a Timer and scheduleAtFixedRate(). See this
The next issue you must deal with is that rendering must be done in a shorter time than the fixed step, or else some delay appears. To achieve this goal send to the GPU most of data (vertices, textures, etc) just once. And for each frame render send only the updated data (the camera position, or just a few objects).
I'm trying to make my first game in java but have stumbled over a problem. When I first wrote my game loop and FPS counter I tried to do it on my own, but it did not work well, so I used this code that I found online:
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();
}
It works great, but when I add the render() function, the window just sort of freezing. I can still close the window, but some times the whole computer need to be restarted. Here is the render function.
private void render(){
BufferStrategy bs = this.getBufferStrategy();
if(bs == null){
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.green);
g.fillRect(0, 0, WIDTH, HEIGHT);
handler.render(g);
g.dispose();
bs.show();
}
If I comment out everything in the render function, I get a white screen show up witch I can move around and a "constant" FPS on around 16200000. But when the code in the render function is active, the FPS looks like this:
FPS: 8644
FPS: 1
FPS: 5977
FPS: 3189
FPS: 3930
FPS: 8120
FPS: 1
FPS: 8024
FPS: 1
No stability or consistency, do anybody know what I have done wrong? My operating system is Ubuntu Mate and I use openjdk version 1.8.0_91 if it is of any importance. Thank you in advance.
Complete Code:
package com.tutorial.main;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
public class Game extends Canvas implements Runnable{
private static final long serialVersionUID = 1550691097823471818L;
public static final int WIDTH = 640, HEIGHT = WIDTH / 12 * 9;
private Thread thread;
private boolean running = false;
private Handler handler;
public Game(){
new Window(WIDTH, HEIGHT, "Lets Build!", this);
handler = new Handler();
handler.addObject(new Player(100, 100, ID.Player));
}
public synchronized void start(){
thread = new Thread(this);
thread.start();
running = true;
}
public synchronized void stop(){
try{
thread.join();
running = false;
}catch(Exception e){
e.printStackTrace();
}
}
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();
}
}
The problem was my operating system. When I switched over to Windows with JDK 8 installed everything worked great. Maybe becaus I have OpenJDK installed on my Linux machine there was some trobble, I honestly do not know. Will look in to it and see if I find it. Will update if so.
Assuming I use this game loop and want to maintain 60 FPS, what would be the appropriate UPS (updates per second)? Should it be 60 as well? Thanks for any help
#Override
public void run() {
long initialTime = System.nanoTime();
final double timeU = 1000000000 / UPS;
final double timeF = 1000000000 / FPS;
double deltaU = 0, deltaF = 0;
int frames = 0, ticks = 0;
long timer = System.currentTimeMillis();
while (running) {
long currentTime = System.nanoTime();
deltaU += (currentTime - initialTime) / timeU;
deltaF += (currentTime - initialTime) / timeF;
initialTime = currentTime;
if (deltaU >= 1) {
getInput();
update();
ticks++;
deltaU--;
}
if (deltaF >= 1) {
render();
frames++;
deltaF--;
}
if (System.currentTimeMillis() - timer > 1000) {
if (RENDER_TIME) {
System.out.println(String.format("UPS: %s, FPS: %s", ticks, frames));
}
frames = 0;
ticks = 0;
timer += 1000;
}
}
}
Update should be fixed
double previous = getCurrentTime();
double lag = 0.0;
while (true) {
double current = getCurrentTime();
double elapsed = current - previous;
previous = current;
lag += elapsed;
processInput();
while (lag >= MS_PER_UPDATE) {
update();
lag -= MS_PER_UPDATE;
}
render();
}
If the difference between the real time and the game time is higher than wanted time between two updates you have to update.
If lag is lower it means you dont have to update yet but you can render anyway.
Better explanation here: http://gameprogrammingpatterns.com/game-loop.html