I've coded a complex Snake game using Swing components.
I have a timer (call it moveRate) that calls repaint(); every x ms (x is changed during game and never goes below 50).
Now for the issue: I'm successful playing like 4 min or so before the whole frame freezes.
MoveRate class:
class MoveRate extends Timer{
private Date dateCreated=new Date();
private long timeLast=0;
public MoveRate(){
super(190, null);
dateCreated=new Date();
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(getWidth()>0 && getHeight()>0){
if(points.get(0).x+HOPS>getWidth() || points.get(0).x<0 ||
points.get(0).y+HOPS>getHeight() || points.get(0).y<0)
if(!crosswalls && !cheats){
moveRate.stop();
prizeRate.stop();
GameOver();
}
else{
if(points.get(0).y<0)
points.get(0).y=sp.getHeight()-HOPS;
else if(points.get(0).y+HOPS>sp.getHeight())
points.get(0).y=0;
else if(points.get(0).x<0)
points.get(0).x=sp.getWidth()-HOPS;
else
points.get(0).x=0;
}
timeLast=(System.currentTimeMillis()-dateCreated.getTime())/SECONDS;
score+=timeLast*(200/moveRate.getDelay());
}
if(prize!=null)
if(points.get(0).x==prize.x && points.get(0).y==prize.y){
int newX = points.get(points.size()-1).x-(points.get(points.size()-1).x - points.get(points.size()-2).x);
int newY = points.get(points.size()-1).y-(points.get(points.size()-1).y - points.get(points.size()-2).y);
points.add(new Point(newX, newY));
if(moveRate.getDelay()>50)
moveRate.setDelay(moveRate.getDelay()-5);
prize.createPrize(PU_NONE);
prizeRate.restart();
score+=timeLast*20*eatmultiplier;
}
if(powerup!=null)
if(points.get(0).x==powerup.x && points.get(0).y==powerup.y){
int newX = points.get(points.size()-1).x-(points.get(points.size()-1).x - points.get(points.size()-2).x);
int newY = points.get(points.size()-1).y-(points.get(points.size()-1).y - points.get(points.size()-2).y);
//points.add(new Point(newX, newY)); //if powerup should increase size
powerUpPerform(powerup.getType());
if(moveRate.getDelay()>50)
moveRate.setDelay(moveRate.getDelay()-5);
//powerUpRate.restart();
score+=timeLast*20*eatmultiplier;
powerup=null;
}
p.setScore(score);
repaint();
}
});
}
}
Basically MoveRate is responsible for animation aswell "eat moves" for prizes & powerups and checks for Game Over situations.
Some other notes:
I thought this has something to do with threads which I haven't learned yet so I added this:
new Thread(new Runnable() {
public void run() {
moveRate=new MoveRate();
moveRate.start();
powerUpRate.start();
prizeRate.start();
}
}).start();
Frame still freezes.
System.gc(); doesn't work neither if I time it every 30 seconds.
Be easy with me because I'm junior student with Java :>
EDIT
I've tried to reproduce the "bug" by making the snake longer (much longer - using my final int SNAKE_INITIAL_LENGTH=200). doesn't seem to have any effect on the problem.
Related
I am trying to get my Asteroids game in Java to have the ArrayList container be removed once it's off screen. I figured out how to stop having it print when off screen, but can see in my console the array continues to grow. Not sure where to go from here.
I think the way I can get them to be removed when off screen is by either using the remove or set feature with arrayLists. Visually everything is disappearing right, but in the console my ArrayList is still growing. I thought about setting a limit of how long it can be, but not sure if there is a better way than that.
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Iterator;
public class AsteroidGame extends Frame {
private int FrameWidth = 500;
private int FrameHeight = 400;
static public void main(String[] args) {
AsteroidGame world = new AsteroidGame();
world.show();
world.run();
}
public AsteroidGame() {
setTitle("Asteroid Game0");
setSize(FrameWidth, FrameHeight);
addKeyListener(new keyDown());
addWindowListener(new CloseQuit());
}
public void run() {
while (true) {
movePieces();
repaint();
try {
Thread.sleep(100);
} catch (Exception e) {
}
}
}
private ArrayList asteroids = new ArrayList();
private ArrayList rockets = new ArrayList();
private Station station = new Station(FrameWidth / 2, FrameHeight - 20);
public void paint(Graphics g) {
station.paint(g);
Iterator astIt = asteroids.iterator();
while (astIt.hasNext()) {
Asteroid rock = (Asteroid) astIt.next();
if (rock.y >= 400 || rock.x >= 500){
rock = null;
} else {
rock.paint(g);
}
}
Iterator rocIt = rockets.iterator();
while (rocIt.hasNext()) {
Rocket rock = (Rocket) rocIt.next();
if (rock.y >= 400 || rock.x >= 500) {
rock = null;
} else {
rock.paint(g);
}
}
}
public void movePieces() {
if (Math.random() < 0.3) {
Asteroid newRock = new Asteroid(FrameWidth * Math.random(), 20, 10 * Math.random() - 5, 3 + 3 * Math.random());
if (newRock.y >= 500 || newRock.x >= 500){
asteroids.remove(0);
} else{
asteroids.add(newRock);
}
System.out.println(asteroids.size());
}
Iterator astIt = asteroids.iterator();
while (astIt.hasNext()) {
Asteroid rock = (Asteroid) astIt.next();
if (rock.y >= 400 || rock.x >= 500) {
rock = null;
} else {
rock.move();
station.checkHit(rock);
}
}
Iterator rocIt = rockets.iterator();
while (rocIt.hasNext()) {
Rocket rock = (Rocket) rocIt.next();
if (rock.y >= 400 || rock.x >= 500) {
rock = null;
} else {
rock.move(asteroids);
}
}
}
private class gameMover extends Thread {
public void run() {
while (true) {
movePieces();
repaint();
try {
sleep(100);
} catch (Exception e) {
}
}
}
}
Change:
rock = null;
to:
astIt.remove();
Assigning null to the variable that has been assigned the value of an element of a List does absolutely nothing to either the List or the element in it; it only affects the value that the variable holds.
As an aside, nice variable name choice of rock - it is appropraite for both types of object - either an abbreviation of "rocket" or a reasonable synonym for an astroid.
Change rock = null; to asteroids.remove(rock); or astIt.remove();
and it should be fine, also no need to set the variable to null as the garbage collector will take care of it for you.
EDIT
Actually asteroids.remove(rock); will throw an exception as said in the comments of this answer, so nevermind it and use the other.
Also I think when in movePieces() you create a new rock and you check if this new rock is outside the screen, I don't think removing the first asteroid in the ArrayList is correct as you will not add the new rock (which may be right if the rock can actually randomly spawn outside the screen) but you will also remove a maybe fine working asteroid from the ArrayList (and thus from the game and the screen).
So, personally I would change that part of code to:
if (Math.random() < 0.3) {
Asteroid newRock = new Asteroid(FrameWidth * Math.random(), 20, 10 * Math.random() - 5, 3 + 3 * Math.random());
if (!(newRock.y >= 500 || newRock.x >= 500)){
asteroids.add(newRock);
}
System.out.println(asteroids.size());
}
But tell me if this works for you.
I'v just created a countdown for a minigame im working on but when i was about to test the countdown i noticed that if i was the only one online the countdown worked perfect, but when another player joined the countdown doubled like this: 10,8,6,4 etc. I think it has something todo with "for(Player p : Bukkit.getOnlinePlayers()){" but i am not quite sure. Anyone that can help?
Here is my countdown class:
Main plugin;
public StartCountdown(Main pl) {
plugin = pl;
}
public static int timeUntilStart;
#Override
public void run() {
for(Player p1 : Bukkit.getOnlinePlayers()){
if(timeUntilStart == 0) {
if(!Game.canStart()) {
plugin.restartCountdown();
ChatUtilities.broadcast(ChatColor.RED + "Not enough players to start. Countdown will");
ChatUtilities.broadcast(ChatColor.RED + "restart.");
p1.playSound(p1.getLocation(), Sound.ENDERDRAGON_WINGS, 5, 1);
return;
}
Game.start();
}
if(timeUntilStart == 1) {
}
for(Player p : Bukkit.getOnlinePlayers()){
p.setLevel(timeUntilStart);
if(timeUntilStart < 11 || timeUntilStart == 60 || timeUntilStart == 30) {
p.playSound(p.getLocation(), Sound.ORB_PICKUP, 5, 0);
if(timeUntilStart == 1) {
p.playSound(p.getLocation(), Sound.ORB_PICKUP, 5, 1);
}
ChatUtilities.broadcast(String.valueOf(timeUntilStart)
+ " §6Seconds until the game starts!");
}
timeUntilStart -= 1;
}
if(timeUntilStart == 0) {
ChatUtilities.broadcast("§6The round has started, good luck!");
}
}
}
}
Your call to decrement time (timeUntilStart -= 1;) is inside a loop for(Player p1 : Bukkit.getOnlinePlayers())....
This means that for each player online, you decrement timeUntilStart by one. However, you only want to do that once per run - take it outside of the for each player p1 loop.
With that being said, most of this logic only should be happening once per RUN, not per player per run (i.e. unless you know something I don't, game.start should probably only get called once)... but that's irrelevant so I'll leave it alone.
I'm writing an android app to measure display lag on tvs using the mirror function on the video out. After many revisions, my code got too complex for its own good, so I scraped it and did a rewrite. My issue is that it is not behaving as expected. The square is not blinking, and the time is 0.0 and the rating is excellent. i have tested changing the ui via the thread by making the square turn different colors, that worked fine. Can someone tell me what the issue is and how to fix it? The way the app works is that you hook the device to a tv and it mirrors the display. then it changes the color of a square in the app and dose a time stamp, then it wait till the camera detects a change then dose another time stamp. using both time stamps you can figure out the delay of the tv. I have it in a loop because the camera only captures at 15ish fps, so I need to run the test multiple times to get an accurate result. The issue is that it always shows up as 0.0ms, that is an impossible number because the lag on most consumer tvs is 9ms. I get the RGB values from each camera frame.
class lagTestThread extends Thread {
#Override
public void run () {
long lagStartTime;
long lagEndTime;
long tempResult;
final double rating;
int x;
long testResult = 0;
int cnt;
for (cnt = 0; cnt >= 100; cnt++){
runOnUiThread(new Runnable() {
#Override
public void run() {
lagSquare.setBackgroundColor(Color.rgb(000, 000, 000));
}
});
while (redVal >= 10.0 && blueVal >= 10.0 && greenVal >= 10.0) {
x = 0;
}
redVal = 0;
blueVal = 0;
greenVal = 0;
lagStartTime = System.nanoTime(); //start lagTimer start
runOnUiThread(new Runnable() {
#Override
public void run() {
lagSquare.setBackgroundColor(Color.rgb(255, 255, 255));
}
});
while (redVal <= 100.0 && blueVal <= 100.0 && greenVal <= 100.0) {
x = 0;
}
lagEndTime = System.nanoTime(); //start lagTimer end
runOnUiThread(new Runnable() {
#Override
public void run() {
lagSquare.setBackgroundColor(Color.rgb(000, 000, 000));
}
});
tempResult = (lagEndTime - lagStartTime);
if (tempResult <= testResult && tempResult != 0) {
testResult = tempResult;
}
}
rating = ((double) testResult) / 1000000.0;
final String finalResultString = String.valueOf(rating);
runOnUiThread(new Runnable() {
#Override
public void run() {
lagTime.setText(finalResultString);
if (rating <= 17.0) {
lagRating.setText("Excellent");
} else if (rating <= 34.0) {
lagRating.setText("Great");
} else if (rating <= 51.0) {
lagRating.setText("Average");
} else {
lagRating.setText("Bad");
}
}
});
}
}
I call it like this
public void startTest(View view) {
lagTestThread lagTest = new lagTestThread();
lagTest.start();
}
redVal, blueVal, greenVal declaration
#Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
double[] rgb = inputFrame.rgba().get(100, 100);
redVal = rgb[0];
blueVal = rgb[2];
greenVal = rgb[1];
Log.i("", "red:" + rgb[0] + " green:" + rgb[1] + " blue:" + rgb[2]);
return rgbMat;
}
The runOnUiThread() causes the Runnable to be posted to the UI thread, at which point the function returns immediately. The Runnable executes at some later time.
Your code is posting events to the UI thread and checking the system time, which means you're calculating how long it takes to post events to the UI thread, not how long it takes them to run. Also, because all the events are queued up behind one another, it's likely they will all execute in the same frame, so you will only see the result of the last setBackgroundColor() call.
If you really want to divorce your display and timing code from the UI thread, you should consider doing this with a SurfaceView, which can be updated independently of the UI thread. (The down side of SurfaceView is that it's a lot more complicated to work with than a custom View.)
I'm making a snake game(for those who don't know) where the snake is controlled by an AI using different algorithms to catch the food. The difference with the regular game is that the snake doesn't move unless a command has been sent by the AI.
My problem is that as soon as I run the AI, the AI creates a stack of commands to be executed to catch the food but my GUI just freezes; probably because it can't keep up with the amount of repaints that the move stacks cause. Through console logs, I can see that AI and the game logic is still running.
I tried to do Thread.sleep() after each move but I guess this just makes the entire program including the GUI sleep. I also have a Timer for my paintComponent but that doesn't seem to change anything.
How can you make your program sleep so that the GUI can catch up to what's happening?
EDIT:
Ok guys, I tried your solutions and it's still not working as it should. I don't really want to just dump the code here but I'm really lost. I have a timer that should repaint on a 140 millisecond interval(that's the value of DELAY), the commands are sent on a different thread which goes to sleep after each key press for 1000 milliseconds and I call repaint() after each call to move()... Here is relevant code(the original code without my modifications here):
private void initGame() {
dots = 5;
for (int z = 0; z < dots; z++) {
x[z] = 50 - z * 10;
y[z] = 50;
}
locateApple();
for (int k = blockNb - 1; k > 0; k--) {
locateBlock(k, apple_x, apple_y);
}
if (blocks) {
locateBlock(0, apple_x, apple_y);
}
timer = new Timer(DELAY, this);
timer.start();
startAi();
}
// AI CONTROLLER
public void startAi() {
Ai theAi = new Ai();
String move = "";
switch (ai) {
case "BFS":
move = theAi.bfs(this);
break;
}
//AI returns a string where each char is a move command
autoMove(move);
}
public void autoMove(String move) {
try {
Robot robot = new Robot();
System.out.println(move);
if (move != "#No") {
Thread thread = new Thread(new Runnable() {
public void run() {
for (int j = 0; j < move.length(); j++) {
if (move.charAt(j) == 'l') {
robot.keyPress(KeyEvent.VK_LEFT);
robot.keyRelease(KeyEvent.VK_LEFT);
}
if (move.charAt(j) == 'r') {
robot.keyPress(KeyEvent.VK_RIGHT);
robot.keyRelease(KeyEvent.VK_RIGHT);
}
if (move.charAt(j) == 'u') {
robot.keyPress(KeyEvent.VK_UP);
robot.keyRelease(KeyEvent.VK_UP);
}
if (move.charAt(j) == 'd') {
robot.keyPress(KeyEvent.VK_DOWN);
robot.keyRelease(KeyEvent.VK_DOWN);
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
thread.run();
}
} catch (AWTException e) {
e.printStackTrace();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
private void doDrawing(Graphics g) {
if (inGame) {
g.drawImage(apple, apple_x, apple_y, this);
for (int j = 0; j < blockNb; j++) {
g.drawImage(block, block_x[j], block_y[j], this);
}
for (int z = 0; z < dots; z++) {
if (z == 0) {
g.drawImage(head, x[z], y[z], this);
} else {
g.drawImage(ball, x[z], y[z], this);
}
}
Toolkit.getDefaultToolkit().sync();
} else {
// gameOver(g);
}
}
private void move() {
for (int z = dots; z > 0; z--) {
x[z] = x[(z - 1)];
y[z] = y[(z - 1)];
}
if (leftDirection) {
x[0] -= DOT_SIZE;
}
if (rightDirection) {
x[0] += DOT_SIZE;
}
if (upDirection) {
y[0] -= DOT_SIZE;
}
if (downDirection) {
y[0] += DOT_SIZE;
}
}
#Override
public void actionPerformed(ActionEvent e) {
if (inGame) {
repaint();
}
}
private class TAdapter extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if ((key == KeyEvent.VK_LEFT) && (!rightDirection)) {
leftDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == KeyEvent.VK_RIGHT) && (!leftDirection)) {
rightDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == KeyEvent.VK_UP) && (!downDirection)) {
upDirection = true;
rightDirection = false;
leftDirection = false;
}
if ((key == KeyEvent.VK_DOWN) && (!upDirection)) {
downDirection = true;
rightDirection = false;
leftDirection = false;
}
move();
checkApple();
checkCollision();
repaint();
}
}
EDIT 2: Also, I just wanted to point out that I tried to move without relying on a robot but to no avail.
Part 1:
Difference bettween Thread.sleep:
When you use it in main Thread(the Thread which java use to run the program)
then your whole program just freeze for that reason.
When you use A Thread for example(follow code)
new Thread(new Runnable(){
public void run(){
//do something...
while(flag==false)
Thread.sleep(a given time) //it need and try catch
else
//do your move
});
then only this Thread freeze (for a given time) or (Whatever you transform it to freeze).
In your case you can use a flag so every time a commant is hitten by user
the flag is going true and then again false to keep stopped the part of the
game you want but the main Thread your programms need to work still works
(if it is a window or anything...)
Part 2:(Basic form of your Thread)(The flag i use must be seen by all Methods)(public or private)
new Thread(new Runnable() {
public void run() {
flag=true;
while(flag==true){
if(move.equals("yes")){
//your code
move="no";
}else
Thread.sleep(20); //Sleep For a While(and then check again)
}
//That means that your Thread will run all over your game
//until game over (when game over just do the flag=false;)
//and The Thread will stop-exit
}});
*About Repaint Method(Dont call the repaint method too fast)
Call it only when the player make a move(this is the time that the frame
need to be repainted[Ok if you have .gif images in your game just dont see this]
Part 3:(When i made a similar game what i did)
Before some months i tried a similar game.The basic idea was a player who must past a labirinth so....
For each level i had one class like this...
public abstarct class Level2(){
//The game was into a panel like your.
//Here i added .setFocusable and .addKeyListener to panel
//Here it was an
public void actionListener(){
//The actionListener checked if the player found the door(for next level)
//Here it was the repaint so every time something happened repaint()
repaint();
}//End of Action Listener
//Use the paint or paintComponent what you need..
public void paint[or paintComponent](Graphics g){
//the 'squares' and the icons the had to be *repainted* again
}
//Here i had an extra class into this for the KeyListeners
//And I added the KeyListener like your game(up,down,left,right)
//I i said before i added this KeyListener to the panel
private class TAdapter extends KeyAdapter {
//KeyPressed,Released...etc
}
}
Thats the basic idea and for your game i think.
The Thread it's an extra option i can't help more you must find the way...
You should have a single "update" looped, from which your execute update commands and repaint request.
A simple approach would be to use a Swing Timer, which can trigger updates to a listener at regular intervals. It has the benefit of been triggered within the context of the EDT making it safe to update the UI from within. See How to use Swing Timers for more details
A more complex approach would be to use a Thread, which contained some kind of loop. This would perform the required updates and schedule repaint, but you'd need to insert Thread.sleep in to allow time for the updates to occur at a regular bases. The problem with this is you will need to synchronise your updates so that you don't update the model while painting is occurring as well synchronise you updates to the UI with the EDT
You need to have some sort of game scheduler loop and an understanding of how it works.
Here is some example code for java swing:
http://staticvoidgames.com/tutorials/swing/swingTimers
Another way to simplify things along with the scheduler is to make your game turn based at first. That is when the player moves 1turn (ie input) the game does all its processing and blocks on user input till the processing is done (ie single loop).
Every time your game AI outputs a new move, you need to call paint, but you also need to wait for whatever event is called when the painting is done before you output your next move, and you may want to wait like a second longer or something, play around with it
pseudo code
def fun 0 // entry point for program
// hook paint done event to func 1
call fun 2
def fun 1 // event handler method for when painting done
call fun 2
def fun 2 // function that does AI work
// do game logic
// call paint
I'm making a simulation in a 3D environment. So far, I have the movements of all the creatures, but it is not "smooth". I've tried quite a few things but was horribly wrong. Now I just have no idea what to do. I was thinking of implementing a vector (not vector class) but don't really know how.
import env3d.EnvObject;
import java.util.ArrayList;
abstract public class Creature extends EnvObject
{
/**
* Constructor for objects of class Creature
*/
public Creature(double x, double y, double z)
{
setX(x);
setY(y);
setZ(z);
setScale(1);
}
public void move(ArrayList<Creature> creatures, ArrayList<Creature> dead_creatures)
{
double rand = Math.random();
if (rand < 0.25) {
setX(getX()+getScale());
setRotateY(90);
} else if (rand < 0.5) {
setX(getX()-getScale());
setRotateY(270);
} else if (rand < 0.75) {
setZ(getZ()+getScale());
setRotateY(0);
} else if (rand < 1) {
setZ(getZ()-getScale());
setRotateY(180);
}
if (getX() < getScale()) setX(getScale());
if (getX() > 50-getScale()) setX(50 - getScale());
if (getZ() < getScale()) setZ(getScale());
if (getZ() > 50-getScale()) setZ(50 - getScale());
// collision detection
if (this instanceof Fox) {
for (Creature c : creatures) {
if (c.distance(this) < c.getScale()+this.getScale() && c instanceof Tux) {
dead_creatures.add(c);
}
}
}
}
}
import env3d.Env;
import java.util.ArrayList;
/**
* A predator and prey simulation. Fox is the predator and Tux is the prey.
*/
public class Game
{
private Env env;
private boolean finished;
private ArrayList<Creature> creatures;
/**
* Constructor for the Game class. It sets up the foxes and tuxes.
*/
public Game()
{
// we use a separate ArrayList to keep track of each animal.
// our room is 50 x 50.
creatures = new ArrayList<Creature>();
for (int i = 0; i < 55; i++) {
if (i < 5) {
creatures.add(new Fox((int)(Math.random()*48)+1, 1, (int)(Math.random()*48)+1));
} else {
creatures.add(new Tux((int)(Math.random()*48)+1, 1, (int)(Math.random()*48)+1));
}
}
}
/**
* Play the game
*/
public void play()
{
finished = false;
// Create the new environment. Must be done in the same
// method as the game loop
env = new Env();
// Make the room 50 x 50.
env.setRoom(new Room());
// Add all the animals into to the environment for display
for (Creature c : creatures) {
env.addObject(c);
}
// Sets up the camera
env.setCameraXYZ(25, 50, 55);
env.setCameraPitch(-63);
// Turn off the default controls
env.setDefaultControl(false);
// A list to keep track of dead tuxes.
ArrayList<Creature> dead_creatures = new ArrayList<Creature>();
// The main game loop
while (!finished) {
if (env.getKey() == 1) {
finished = true;
}
// Move each fox and tux.
for (Creature c : creatures) {
c.move(creatures, dead_creatures);
}
// Clean up of the dead tuxes.
for (Creature c : dead_creatures) {
env.removeObject(c);
creatures.remove(c);
}
// we clear the ArrayList for the next loop. We could create a new one
// every loop but that would be very inefficient.
dead_creatures.clear();
// Update display
env.advanceOneFrame();
}
// Just a little clean up
env.exit();
}
/**
* Main method to launch the program.
*/
public static void main(String args[]) {
(new Game()).play();
}
}
You haven't shown enough of your program. Basically, if you want animation to be smooth, and you want to do it yourself (as opposed to using JavaFX or something), then you need to do lots of inter-frames. So rather than advancing an entire timer tick, advance a 10th of a timer tick, move everything on a screen a tiny bit, and then advance again. You should have the background redraw happening every 10th of a second for smooth animation.
As vy32 mentioned, we need to see more of your code. But it looks like you are missing timing code.
What you probably want to do is check the time each iteration of your game loop and then sleep for a certain amount of time to achieve some desired frame rate. Otherwise your game loop will run hundreds of thousands of times a second.
Alternatively, you should be advancing your creatures by a distance that is proportional to the amount of time that has elapsed since the previous frame.
Here is an example of a very simple regulated loop ("fps" is the desired framerate):
private long frameLength = 1000000000 / fps;
public void run() {
long ns = System.nanoTime();
while (!finished) {
//Do one frame of work
step();
//Wait until the time for this frame has elapsed
try {
ns += frameLength;
Thread.sleep(Math.max(0, (ns - System.nanoTime())/10000000));
} catch (InterruptedException e) {
break;
}
}
}
It should be very easy to retrofit this into your game loop.