GameLoop, What To Put For Delta? - java

I was just wondering for a quick question, what do you put in for delta exactly. The parameter double delta is (as the developer stated, in seconds of logic updates). If I wanted the loop to run 20 times a second, would I have it set to .2 or something like that? I am a bit confused on the logic updates (in seconds) part.
Anyways if you want to check any more of the game loops provided then check out the page here http://entropyinteractive.com/2011/02/game-engine-design-the-game-loop/
public abstract class GameLoop
{
private boolean runFlag = false;
/**
* Begin the game loop
* #param delta time between logic updates (in seconds)
*/
public void run(double delta)
{
runFlag = true;
startup();
// convert the time to seconds
double nextTime = (double)System.nanoTime() / 1000000000.0;
while(runFlag)
{
// convert the time to seconds
double currTime = (double)System.nanoTime() / 1000000000.0;
if(currTime >= nextTime)
{
// assign the time for the next update
nextTime += delta;
update();
draw();
}
else
{
// calculate the time to sleep
int sleepTime = (int)(1000.0 * (nextTime - currTime));
// sanity check
if(sleepTime > 0)
{
// sleep until the next update
try
{
Thread.sleep(sleepTime);
}
catch(InterruptedException e)
{
// do nothing
}
}
}
}
shutdown();
}
public void stop()
{
runFlag = false;
}
public abstract void startup();
public abstract void shutdown();
public abstract void update();
public abstract void draw();
}

You input the time in milliseconds that a single logic-loop should be based on.
If you want 20 times per second then 1/20 second is the number which is not 0.2 but 0.05.
You can write it more intuitively (IMO) by writing "1.0 / 20" then you don't have to convert back and forth and can just replace 20 with the frequency.

Related

How do I reset a Timer in Java?

So I'm trying to program a handheld electronic game, called Lights Out Cube, in Java using Eclipse Oxygen.2, and I decided to include a timer so that the player knows how much time was required by him to finish the game. When the player clicks on a button called "Start/Reset"(I change its text to "Reset" after clicking it once), which is where I activate the timer, the game starts. After every click I check if player has finished the game, and if he does, I stop the timer. If he wishes to play again, I want the timer to restart. Please help me out here:
//here i have a function called checkIfWinning() which does the checking; if there is a winner, the following code is executed to stop the timer
timer.cancel();
timer.purge();
//timer is a publicly declared java.util.Timer
//this is a code snippet for btnStart with "time" recording the time in seconds
time=0;
timer.schedule(new TimerTask()
{
#Override
public void run()
{
time++;
int hours = (int) time / 3600;
int remainder = (int) time - hours * 3600;
int mins = remainder / 60;
remainder = remainder - mins * 60;
int secs = remainder;
timeTaken.setText(String.format("%02d:%02d:%02d",hours,mins,secs));
}
}, 1000,1000);
Is there anyway this can be done? Or will I have to remove the timer entirely?
You can't reset when the TimerTask object will be activated, but in your specific case, you can reset the game time count without removing and recreating the timer.
Since your timer is fired every second, all you have to do is reset the time variable you are using, when the user clicks the reset button.
I am editing this answer based on Hulks and your comments:
Hulk is right, and you should use AtomicInteger for your time count. If you keep the timer running, there could be a bug some times where the value will not reset.
You can have an AtomicBoolean flag that lets the TimerTask know if the player is playing or not.
Here is a code example:
AtomicInteger time = new AtomicInteger();
//whenever you want to reset it:
time.set(0);
AtomicBoolean isPlaying = new AtomicBoolean();
//when user clicks "start":
isPlaying.set(true);
//when user wins or clicks "reset"
isPlaying.set(false);
//your timer task will look something like this:
public void run() {
if (isPlaying.get()) {
int currentTime = time.incrementAndGet();
int hours = (int) currentTime / 3600;
int remainder = (int) currentTime - hours * 3600;
int mins = remainder / 60;
remainder = remainder - mins * 60;
int secs = remainder;
timeTaken.setText(String.format("%02d:%02d:%02d",hours,mins,secs));
}
}
This might be clear.
You can't reset or pause the Timer in Java, but the functionality can be achieved by not running the Timer based on a boolean check.
As previously said by Hulk and Lev.M, AtomicInteger can be used in need of thread safety.
Whole logic in run() can be simplified using TimeUnit for converting seconds to the specified format,
time+=1000;
System.out.println(String.format("%02d:%02d:%02d", TimeUnit.SECONDS.toHours(time), TimeUnit.SECONDS.toMinutes(time), time%60));
import java.util.Timer;
import java.util.TimerTask;
public class Game
{
private static int time = 0;
private static Timer t = new Timer();
private static Game g;
private static boolean ispaused = false;
public static void main(String[] args)
{
t.schedule(new TimerTask() {
public void run()
{
if(ispaused)
{
return;
}
time++;
System.out.println(String.format("%02d:%02d:%02d", TimeUnit.SECONDS.toHours(time), TimeUnit.SECONDS.toMinutes(time), time%60));
}
}, 1000, 1000);
g = new Game();
try
{
System.out.println("Starting first game");
g.startGame(); Thread.sleep(5000); g.endGame();
System.out.println("Starting second game.");
g.startGame(); Thread.sleep(5000); g.endGame();
}
catch(Exception e)
{}
}
private void startGame()
{
time = 0;
ispaused = false;
System.out.println("Game Started");
}
private void endGame()
{
time = 0;
ispaused = true;
System.out.println("Game ended");
}
};

Running a counter thread in the background during a game

I am wondering the best way to keep a timer going in the background while a game is played.
I am programming a version of the HiLo game (in Java), which gives a user a certain amount of time to determine a number. If a guess is not correct, the game will tell the user whether the name is too high or too low.
I'm keeping track of time using System.currentTimeMillis() and seeing how much time has elapsed. This seems to work well, and so far I have been checking to see how much time has elapsed each time a new number is entered. For example, currently the app output looks like this:
Welcome to HiLo!
You have 10 seconds to guess a number I'm thinking of between 1 and 100.
> 67
Too high.
> 29
Too low.
Half of your time is gone! Only 5 seconds remains!
> 37
Too high.
> 33
Oops! Time is up - try again.
As you can see, currently, it can only check when I enter a new number how much time is passed.
I have tried creating a thread to start with a timer, however, when I start it, it keeps counting until the time is exhausted, without going on to the thread.run(int guess) which will be run when there is a new guess. I want to be able to still make guesses while the counter runs. Here is my attempt at a new implementation for thread.start():
public void start(int time_sent) throws InterruptedException {
time = time_sent;
startTime = (System.currentTimeMillis() / 1000);
while (1==1) {
long elapsed = ((System.currentTimeMillis() / 1000) - (startTime));
if (elapsed >= (time)) {
System.out.println("Oops! Time is up - try again.");
System.exit(0);
}
else if (elapsed >= (time/2) && !halfWarning) {
System.out.println("Half of your time is gone! Only " + (time/2) + " seconds remains!");
halfWarning = true;
}
}
}
How can I continue running this counter in the background?
This is one more approach:
public void game() {
Scanner scanner = new Scanner(System.in);
int time = 10; // sec
message("You have " + time + " seconds to guess...");
new Thread(new Background(System.currentTimeMillis() / 1000, time)).start();
while (true) {
String s = scanner.next();
if (s.equals("55")) {
message("You win");
System.exit(0);
} else {
message("try again...");
}
}
}
private void message(String str) {
System.out.println(str);
System.out.print("> "); // monit
}
You start 1 thread with behavior implemented in Background class. Next you enter while loop to capture user inputs. The Background thread works in background...
private class Background implements Runnable {
private long startTime;
private long time;
private boolean halfWarning;
private Background(long startTime, long time) {
this.startTime = startTime;
this.time = time;
}
#Override
public void run() {
while (true) {
long now = System.currentTimeMillis() / 1000;
long elapsed = now - startTime;
if (elapsed >= (time / 2) && !halfWarning) {
message("\n Half of your time is gone! Only " + (time / 2) + " seconds remains!");
halfWarning = true;
}
if (elapsed >= time) {
message("\n Oops! Time is up - try again.");
System.exit(0);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
//ignore
}
}
}
}
Use a ScheduledExecutorService to execute concurrent actions in the future:
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture<?> half = ses.schedule(new Runnable() {
#Override
public void run() {
System.out.println("Half of your time is gone!");
}
}, time / 2, TimeUnit.SECONDS);
ScheduledFuture<?> full = ses.schedule(new Runnable() {
#Override
public void run() {
System.out.println("Oops! Time is up - try again.");
// System.exit(0) ?
}
}, time, TimeUnit.SECONDS);
// check
if (input == toGuess) {
half.cancel();
full.cancel();
}
You could have a Timer thread that prints out these messages and shuts down the listening program.
It might inspire you :
public static class Game extends TimerTask {
private long start;
private long end;
public Game(long end) {
super();
this.start = System.currentTimeMillis();
this.end = end;
}
#Override
public void run() {
while (System.currentTimeMillis() - start < end)
System.out.println(System.currentTimeMillis());
}
}
public static void main(String[] args) {
TimerTask task = new Game(10000);
Timer timer = new Timer();
timer.schedule(task,0);
}

Java - Subtract 32 from a number in a specific amount of time

I was wondering... Is there a way that I could subtract 32 from a number in a specific amount of time? Such as 500 mils?
If you could help out, it would be great!
Thanks!
public void update() {
x += dx;
if(this.y % 32 == 0) {
this.tileY = this.y / 32;
}
if(this.x % 32 == 0) {
this.tileX = this.x / 32;
}
System.out.println(tileX);
}
public void moveLeft () {
// subtract 32 dx in 500 ms
}
Well, here is a lovely code I've developed for you. I've added the keyword static to be able to call it from main without creating any objects, but it does not use anything from a static context.
As my comments through the code try to explain, this isn't the perfect solution, it's just a start, you may face issues such as multi-threading errors (if you decide to use a separate Thread to update the position) or slight timing issues if the body of the method takes a while to execute.
If you feel the nanosecond precision is a bit too much for your purposes, remember there is also Thread.sleep(int milis).
Here is the code (try changing the values calling moveLeft(int, int) to see the results):
public class Slider {
public static void main(String[] args) {
Thread thread = new Thread() {
#Override
public void run() {
/*
* If you are going to use something like this, beware you are multi-threading
* Make sure what you do is thread-safe
*/
moveLeft(32, 500);
}
};
thread.start();
}
public static void moveLeft(int distance, int milis) {
//time_px is how many nanoseconds the Thread can sleep until it has to move 1 dx
double time_px = (100000*milis)/distance;
if (time_px >= 1) {
//Get the milis and nanos, rounding for Thread.sleep
long time_round = (long) Math.floor(time_px);
long milis_sleep = time_round/100000;
System.out.print("Waiting " + milis_sleep + "ms ");
int nano_sleep = (int) (time_round%100000);
System.out.println(nano_sleep + "ns per dx");
for (int i=0; i<distance; i++) {
try {
Thread.sleep(milis_sleep, nano_sleep);
/*
* Your code here
* A long code here might not get you the desired result since the sleeping does
* not account for the time spent processing the code. But this is a good start
*/
System.out.println("moving 1 dx");
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
else {
System.out.println("Cannot go that fast");
//If you are moving that fast (more than 1 dx per nanosecond) then you need to change this up a little.
}
}
}

problems converting CountDownTimer to my SimpleDateFormat output

I have a timer that counts down. I want the displayed format to be 00.00 or "ss.SS". However I haven't made any progress in hours. Without the SimpleDateFormat it displays 01.91 then goes to 01.9. This makes it hard to watch as it flickers to keep the view centered. All I really want is a way to keep the format 01.90 and not allow the 0 to be dropped. Could I accomplish this with my original code without the SimpleDateFormat?
/*
* This is my original code before I tried the SimpleDateFormat
*
* This code is fully functional and works good, it just keeps dropping the 0 every
* 10 milliseconds and makes the view shake
*
* getTimeSecs() could return 5, 10, 15, 30, 90 seconds converted to milliseconds
* getCountDownInterval() returns 10
*
*/
public void createTimer() {
myCounter = new CountDownTimer(getTimeSecs(), getCountDownInterval()) {
public void onTick(long millisUntilFinished) {
timerIsRunning = true;
if(millisUntilFinished < 10000) {
TVcountDown.setText("0" + ((millisUntilFinished / 10) / 100.0));
} else {
TVcountDown.setText("" + ((millisUntilFinished / 10) / 100.0));
}
} //end onTick()
#Override
public void onFinish() {
timerIsRunning = false;
TVcountDown.setBackgroundColor(myRes.getColor(R.color.solid_red));
TVcountDown.setTextColor(myRes.getColor(R.color.white));
TVcountDown.setText("Expired");
// Make sure vibrate feature is enabled
if(wantsVib == true) {
vib.vibrate(300);
}
} //end onFinish()
}.start();
} //end createTimer()
Here is my code after trying the SimpleDateFormat
public void createTimer() {
myCounter = new CountDownTimer(getTimeSecs(), getCountDownInterval()) {
public void onTick(long millisUntilFinished) {
timerIsRunning = true;
long current = (long) ((millisUntilFinished / 10) / 100.0);
TVcountDown.setText("" + timerDisplay.format(current));
}
#Override
public void onFinish() {
timerIsRunning = false;
TVcountDown.setBackgroundColor(myRes.getColor(R.color.solid_red));
TVcountDown.setTextColor(myRes.getColor(R.color.white));
TVcountDown.setText("Expired");
// Make sure vibrate feature is enabled
if(wantsVib == true) {
vib.vibrate(300);
}
}
}.start();
} //end createTimer()
I know! I don't even think I'm close to getting it with the SimpleDateFormat and I'm getting frustrated. It runs, but counts down only seconds, on the milliseconds side. So 15 seconds shows 00.15 not 15.00.
I don't expect someone to code it all out for me just need pointed in the right direction. All the tutorials I can find involve years, days, and such and I can't grasp the concept from that.
I'd prefer not to use the SimpleDateFormat -- cuz it hasn't been to simple for me -- and just use my original code and add a zero to the end of the milliseconds side every 10 milliseconds.
Thanks in advance.
Try this:
TVcountDown.setText(convertToMyFormat(millisUntilFinished));
and convertToMyFormat() method:
public String convertToMyFormat(long ms) {
String secString, msecString;
//constructing the sec format:
int sec = (int) (ms / 1000);
if(sec < 10) secString = "0"+sec;
else if(sec == 0) secString = "00";
else secString = ""+sec;
//constructing the msec format:
int msec = (int) ((ms-(sec*1000))/10.0);
if(msec < 10) msecString = "0"+msec;
else if(msec == 0) msecString = "00";
else msecString = ""+msec;
return secString+":"+msecString;
}
I'm not sure if I did the msec part correctly but you can tweek it as you want.
convert the number to a string and it will keep formatting. additionally you can do something like this
public String NumToStr(long i){
if (i < 10 ) {
return ("0" + Long.toString(i));
}
return Long.toString(i);
}
to make sure "9" will always come back as "09". Now set the string to the text.
actually what might be easier is this
if(millisUntilFinished < 10000) {
TVcountDown.setText("0" + Long.toString((millisUntilFinished / 10) / 100.0));
} else {
TVcountDown.setText("" + Long.toString((millisUntilFinished / 10) / 100.0));
}
Use Float.toString() or Double.toString, or whatever you need. Dont be afraid to write a little function to edit the string to make it appear as you want if you need to.
public String KeepFirstTwoCharOfString(String string){
//code to store first two Char into string
// return the string containing only first 2 chars
}

Smooth movement in Java

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.

Categories

Resources