How to fix stuttering on 60hz?

Hello guys!
I am SUPER new to programming and especially to game development.
Two days ago I started learning java. I follow this http://www.kilobolt.com/day-5-background-and-sprites.html tutorial.
My main class looks like this right now:

package kiloboltgame;

import java.applet.Applet;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.URL;

public class StartingClass extends Applet implements Runnable, KeyListener {

	private Robot robot;
	private Image image, currentSprite, character, characterDown,
			characterJumped, background;
	private Graphics second;
	private URL base;
	private static Background bg1, bg2;

	@Override
	public void init() {

		setSize(800, 480);
		setBackground(Color.BLACK);
		setFocusable(true);
		addKeyListener(this);
		Frame frame = (Frame) this.getParent().getParent();
		frame.setTitle("Q-Bot Alpha");
		try {
			base = getDocumentBase();
		} catch (Exception e) {
			// TODO: handle exception
		}

		// Image Setups
		character = getImage(base, "data/character.png");
		characterDown = getImage(base, "data/down.png");
		characterJumped = getImage(base, "data/jumped.png");
		currentSprite = character;
		background = getImage(base, "data/background.png");
	}

	@Override
	public void start() {

		bg1 = new Background(0, 0);
		bg2 = new Background(2160, 0);
		robot = new Robot();

		Thread thread = new Thread(this);
		thread.start();
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
	}

	@Override
	public void run() {
		while (true) {
			robot.update();
			if (robot.isJumped()) {
				currentSprite = characterJumped;
			} else if (robot.isJumped() == false && robot.isDucked() == false) {
				currentSprite = character;
			}
			bg1.update();
			bg2.update();
			repaint();
			try {
				Thread.sleep(17);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public void update(Graphics g) {
		if (image == null) {
			image = createImage(this.getWidth(), this.getHeight());
			second = image.getGraphics();
		}

		second.setColor(getBackground());
		second.fillRect(0, 0, getWidth(), getHeight());
		second.setColor(getForeground());
		paint(second);

		g.drawImage(image, 0, 0, this);

	}

	@Override
	public void paint(Graphics g) {
		g.drawImage(background, bg1.getBgX(), bg1.getBgY(), this);
		g.drawImage(background, bg2.getBgX(), bg2.getBgY(), this);
		g.drawImage(currentSprite, robot.getCenterX() - 61,
				robot.getCenterY() - 63, this);

	}

	@Override
	public void keyPressed(KeyEvent e) {

		switch (e.getKeyCode()) {
		case KeyEvent.VK_UP:
			System.out.println("Move up");
			break;

		case KeyEvent.VK_DOWN:
			currentSprite = characterDown;
			if (robot.isJumped() == false) {
				robot.setDucked(true);
				robot.setSpeedX(0);
			}
			break;

		case KeyEvent.VK_LEFT:
			robot.moveLeft();
			robot.setMovingLeft(true);
			break;

		case KeyEvent.VK_RIGHT:
			robot.moveRight();
			robot.setMovingRight(true);
			break;

		case KeyEvent.VK_SPACE:
			robot.jump();
			break;

		}

	}

	@Override
	public void keyReleased(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_UP:
			System.out.println("Stop moving up");
			break;

		case KeyEvent.VK_DOWN:
			currentSprite = character;
			robot.setDucked(false);
			break;

		case KeyEvent.VK_LEFT:
			robot.stopLeft();
			break;

		case KeyEvent.VK_RIGHT:
			robot.stopRight();
			break;

		case KeyEvent.VK_SPACE:
			break;

		}

	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub

	}

	public static Background getBg1() {
		return bg1;
	}

	public static Background getBg2() {
		return bg2;
	}

}

My question is: can I somehow set DOUBLE variable to Thread.sleep()? As far as I understand I need to get Thread.sleep(16.6) somehow? I tried to switch monitor refresh rate to 50 hz and set sleep time to 20 nano seconds. It completely eliminated stuttering. But what should I do with 60hz if double is not possible?

First, I’d look into a BufferStrategy

Second, I would use a timer instead of Thread.Sleep.

Something like this


if((System.currentTimeMillis() - milisecondsAmount) > lastUpdate) {
    doStuff();
    lastUpdate = System.currentTimeMillis();
}

where, the milisecondsAmount would be the amount of time needed to “sleep”

Example:

   @Override
   public void run() {
      while (true) {
 	if((System.currentTimeMillis - 166) > lastUpdate) {
         robot.update();
         if (robot.isJumped()) {
            currentSprite = characterJumped;
         } else if (robot.isJumped() == false && robot.isDucked() == false) {
            currentSprite = character;
         }
         bg1.update();
         bg2.update();
         repaint();
	lastUpdate = System.currentTimeMillis();
	}
      }
   }

Sorry for conventions, did that in notepad.

Thanks a lot for your answer!

private static long lastUpdate = System.currentTimeMillis();

public void run() {
		while (true) {
			if ((System.currentTimeMillis() - 166) > lastUpdate) {
				robot.update();
				if (robot.isJumped()) {
					currentSprite = characterJumped;
				} else if (robot.isJumped() == false
						&& robot.isDucked() == false) {
					currentSprite = character;
				}
				bg1.update();
				bg2.update();
				repaint();
				lastUpdate = System.currentTimeMillis();
			}
		}
	}

I did as you mentioned but can you tell me more about System.currentTimeMillis - 166? If I leave it as it is then I see 2~ frames per second instead of 60. Everything is super slow. If I change it to 17 the speed is normal but It stutters as it does with sleep method.

Use system.nanoTime() much more accurate.

private long lastRender;
	private int frames;
	private final int FRAME_CAP = 60;
	
	public void run() {
		while(true) {
			update();
			if((System.currentTimeMillis() - (1000 / FRAME_CAP) > lastRender))
				render();
		}
	}
	
	private void update() {
        robot.update();
        if (robot.isJumped()) {
           currentSprite = characterJumped;
        } else if (robot.isJumped() == false
              && robot.isDucked() == false) {
           currentSprite = character;
        }
        bg1.update();
        bg2.update();
	}
	
	private void render() {
		repaint();
		lastRender = System.currentTimeMillis();
	}

This calculates the game logic as fast as possible, but allows it to only draw as fast as the frame cap.

Thanks a lot for trying to help me!
After modifying my class the code looks like this:

package kiloboltgame;

import java.applet.Applet;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.URL;

public class StartingClass extends Applet implements Runnable, KeyListener {

	private Robot robot;
	private Image image, currentSprite, character, characterDown,
			characterJumped, background;
	private Graphics second;
	private URL base;
	private static Background bg1, bg2;
	private long lastRender;
	private int frames;
	private final int FRAME_CAP = 60;

	@Override
	public void init() {

		setSize(800, 480);
		setBackground(Color.BLACK);
		setFocusable(true);
		addKeyListener(this);
		Frame frame = (Frame) this.getParent().getParent();
		frame.setTitle("Q-Bot Alpha");
		try {
			base = getDocumentBase();
		} catch (Exception e) {
			// TODO: handle exception
		}

		// Image Setups
		character = getImage(base, "data/character.png");
		characterDown = getImage(base, "data/down.png");
		characterJumped = getImage(base, "data/jumped.png");
		currentSprite = character;
		background = getImage(base, "data/background.png");
	}

	@Override
	public void start() {

		bg1 = new Background(0, 0);
		bg2 = new Background(2160, 0);
		robot = new Robot();

		Thread thread = new Thread(this);
		thread.start();
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
	}

	@Override
	public void run() {
		while (true) {
			update();
			if ((System.currentTimeMillis() - (1000 / FRAME_CAP) > lastRender))
				render();
		}
	}

	@Override
	public void update(Graphics g) {
		if (image == null) {
			image = createImage(this.getWidth(), this.getHeight());
			second = image.getGraphics();
		}

		second.setColor(getBackground());
		second.fillRect(0, 0, getWidth(), getHeight());
		second.setColor(getForeground());
		paint(second);

		g.drawImage(image, 0, 0, this);

	}

	private void update() {
		robot.update();
		if (robot.isJumped()) {
			currentSprite = characterJumped;
		} else if (robot.isJumped() == false && robot.isDucked() == false) {
			currentSprite = character;
		}
		bg1.update();
		bg2.update();
	}

	private void render() {
		repaint();
		lastRender = System.currentTimeMillis();
	}

	@Override
	public void paint(Graphics g) {
		g.drawImage(background, bg1.getBgX(), bg1.getBgY(), this);
		g.drawImage(background, bg2.getBgX(), bg2.getBgY(), this);
		g.drawImage(currentSprite, robot.getCenterX() - 61,
				robot.getCenterY() - 63, this);

	}

	@Override
	public void keyPressed(KeyEvent e) {

		switch (e.getKeyCode()) {
		case KeyEvent.VK_UP:
			System.out.println("Move up");
			break;

		case KeyEvent.VK_DOWN:
			currentSprite = characterDown;
			if (robot.isJumped() == false) {
				robot.setDucked(true);
				robot.setSpeedX(0);
			}
			break;

		case KeyEvent.VK_LEFT:
			robot.moveLeft();
			robot.setMovingLeft(true);
			break;

		case KeyEvent.VK_RIGHT:
			robot.moveRight();
			robot.setMovingRight(true);
			break;

		case KeyEvent.VK_SPACE:
			robot.jump();
			break;

		}

	}

	@Override
	public void keyReleased(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_UP:
			System.out.println("Stop moving up");
			break;

		case KeyEvent.VK_DOWN:
			currentSprite = character;
			robot.setDucked(false);
			break;

		case KeyEvent.VK_LEFT:
			robot.stopLeft();
			break;

		case KeyEvent.VK_RIGHT:
			robot.stopRight();
			break;

		case KeyEvent.VK_SPACE:
			break;

		}

	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub

	}

	public static Background getBg1() {
		return bg1;
	}

	public static Background getBg2() {
		return bg2;
	}

}

Now everything runs VERY fast :(. Should I delete override update method or else?

Off Topic:
I highly recommend spending at the very least 2-3 weeks (though 1-2 months is better) reading through The Java Tutorials before trying to make a game. It may be boring, but trying to make a game without any basic programming knowledge is a mistake that many people make. Copy & pasting code/ typing in code that you don’t understand in depth won’t help in the long term. Create simple useless stuff like calculator programs while reading the tutorials and I assure you that you’ll get a much better understanding of the language. If you don’t understand something properly do a lot of research on the topic.

Once you’ve got to the stage of understanding data types, operators, objects and basic inheritance, creating simple pong/snake/maze games is the way to go. Trust me; if you have a passion to want to create games, a month is nothing.

It’s going to run fast, you’re processing the games logic as fast as possible.
If you want certain things to be delayed, you’ll have to delay them yourself, or look into doing movements based on deltatime.