Java Timer not working. Calling Multiple Timers at Once - java

I started making a game using Java. I am currently working on a basic enemy that will fire in range and when it fires I want it to wait for x seconds and fire 3 bullets at a rate of y.
So I decided to use a Timer to create this delay:
public class DelayFire
{
Toolkit toolkit;
Timer timer;
//The enemy firing
Enemy com;
public DelayFire(double seconds, Enemy e, boolean un)
{
toolkit = Toolkit.getDefaultToolkit();
timer = new Timer();
com = e;
timer.schedule(new FireTask(un), (int) seconds * 1000);
}
class FireTask extends TimerTask
{
public boolean unfire = false;
public FireTask (boolean x)
{
this.unfire = x;
}
public void run()
{
if(com.health>0)
{
com.charging = false;
com.fire();
if(unfire==true)
{
com.fire = false;
com.canFire = true;
}
this.cancel();
}
}
}
}
Then which I call in Enemy class it 3 times each with a different delay:
void spray()
{
new DelayFire(2.0,this,false);
new DelayFire(2.5,this,false);
new DelayFire(3.0,this,true);
}
This void is called when ever the player is in firing range (This is also in the Enemy class):
if(canFire==true && fire==false)
{
spray();
canFire = false;
fire = true;
}
Yet after all this work it will only create two bullets once I'm within range. Until I leave and re-enter the enemy's sight again.
Note: I only put the parts of my code where I would expect some mistake is made. Let me know if you need to see more code.

Are you absolutely sure only two bullets are fired? You can try inserting System.out.println("Hello, Bullet World!") in the run() method of FireTask. You might be surprised to find that the line will print three times.
What you're experiencing is the associativity of casts. Consider this part of your code:
(int) seconds * 1000
Since seconds is a double, and you want an int (or perhaps a long), it's natural that you'll want to cast it. However, the cast does not cast the entire expression seconds * 1000 to an int - just seconds. Next, consider your instantiations of your DelayFire class:
new DelayFire(2.0,this,false);
new DelayFire(2.5,this,false);
new DelayFire(3.0,this,true);
Here, you use the double values 2.0, 2.5, and 3.0. However, the 2.5 is casted to an int before the multiplication, causing it to become a flat 2. As a result, your program will schedule two bullets to be fired after 2 seconds, and one bullet to be fired after 3 seconds.
To get around this problem, stick some parentheses around the entire expression with the multiplication in it:
(int) (seconds * 1000)
This should result in the correct behavior. There may be other bugs in your code, though. But try that first.
Edit: As a side note, the conditions in your if-statements are overcomplicated. You are basically turning a boolean-valued expression into another boolean-valued expression by writing if (unfire == true). Since unfire is a boolean expression, there is no need for the == operator. You can simply write if (unfire). And instead of checking if the value is false, use the unary !-operator to negate the expression, if (!unfire).

Related

How to limit player activity?

I have a simple game where a player shoots some bullets. However, I want to make it so that the player can only shoot a bullet every x seconds. How would I do this?
I have tried to do it by taking the average time between bullets and saying that if average time is less than one second don't let the space bar (the control for shooting) work. However, I don't know how to make the space bar not work, AND that would mean a player could just not shoot for a wile and then shoot a lot of bullets at once.
The method for shooting looks something like this:
public void keyPressed(KeyEvent e) {
if (!keysDown.contains(e.getKeyCode()))
keysDown.add(new Integer(e.getKeyCode()));
This adds the integer of the key value to an array, which is then read here:
if (keysDown.contains(KeyEvent.VK_SPACE)) {
b = new Bullets(x);
bullCount.add(b);
System.out.println(bullCount.get(0).getY());
System.out.println ("There are " + bullCount.size() + "bullets alive.");
//elapsed = System.nanoTime() - start;
//if ((elapsed / bulletCount) < 1000000000) {
//this is where I would say 'no more bullets shot until
//average time in nanoseconds is more than 1 second!' but I don't know how
//}
Make a global variable ie: long lastShot.
When user shot, check if (System.currentTimeMilis()-lastShot>5000) before you allow him to shoot.
If it is ok to shoot, store the lastShot = System.currentTimeMilis(); and do the real shot. If not, don't allow him to shoot.
Here is an example in pseudo-code:
class SomeClass {
private long lastShot;
public void userPressedShot() {
if (System.currentTimeMillis()-lastShot>5000) {
lastShot = System.currentTimeMillis();
doTheRealShot();
}
// Ignored till 5000 miliseconds from last shot
}
}
One overkill option is to use the Guava's RateLimiter
final RateLimiter rateLimiter = RateLimiter.create(2.0); // rate is "2 permits per second"
while(true) {
rateLimiter.acquire();
shootSomething();
}
For this solution I assume that you use a Player Object.
It's very simple:
1.: add the field lastShot of the type long with the value 0 to your class.
2.: Whenever the player shoots, set lastShot to System.currentTimeMillis()
3.: Now, before you let him shoot, check if System.currentTimeMillis()-lastShot is smaller than your bullet delay in seconds.
This would be a MWE which has to be inserted in your player class:
Just call the Method player.shoot() to let him shoot - or not, if it's not possible.
private long lastShot = 0;
//return value is for you to check if the shot happened
public boolean shoot(){
//Did the last shot happen less than 1 second (1000 milliseconds) ago
if(System.currentTimeMillis()-lastShot <= 1000){
//If yes: return false, the shot can not happen
return false;
}else{
lastShot = System.currentTimeMillis();
//If no: insert your shooting code here to be executed
//return true, the shot happened
return true;
}
}
Try using a timer that resets every second the bullets count :
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
bullCount.clear();
}
}, 0, 1000); // 0 is the delay in milliseconds before it starts and 1000 is the time in milliseconds between successive task executions
Then when a player wants to shoot you just have to look at bullCount's size

Mp3 player with timer in java [fast forward]

I'm making fast forward button in my Mp3 player. I wrote already code for this, but have problem how to implement timer to jump 5% forward? I mean when I press button timer should jump 5% forward of total long song. This is my fastForward method.
public void FastForward(){
try {
//songTotalLength = fis.available();
fis.skip((long) ((songTotalLength * 0.05)));
} catch (IOException e) {
e.printStackTrace();
}
}
And here is the button method:
private void jButton3ActionPerformed(ActionEvent e) {
mp3.FastForward();
if(mp3.player.isComplete()){
bar = 100;
}
jProgressBar1.setValue((int)bar);
bar+=5;
}
And this one is for timer:
private void setTime(float t) {
int mili = (int) (t / 1000);
int sec = (mili / 1000) % 60;
int min = (mili / 1000) / 60;
start.set(Calendar.MINUTE, 0);
start.set(Calendar.SECOND, 0);
end.set(Calendar.MINUTE, 0 + min);
end.set(Calendar.SECOND, 0 + sec);
timer = new javax.swing.Timer(1000, new TimerListener());
percent = (float)100/(min*60+sec);
}
You're already redundantly tracking progress in two variables fis and bar. For the sake of good design, use one of those to determine elapsed time rather than using yet another variable for the same purpose.
but have problem how to implement timer to jump 5% forward?
You seem to have mistaken the purpose of a Timer. According to the Timer class documentation, it:
Fires one or more ActionEvents at specified intervals.
So the timer is not meant to keep track of how much time has elapsed. It will simply invoke the actionPerformed(ActionEvent) method of your TimerListener once per second (every 1000 milliseconds) as you have it configured.
For a more complete answer, please post the code for your TimerListener class.
Notes
It seems that your setTime(float) method is meant to be called repeatedly, so this method should not be initializing the timer variable. Rather initialize the timer once and leave it alone to do its job.
I'm assuming you intended the supplied float parameter t to represent microseconds.
The float data type has only 7 digits of precision. This could be fine since you're interested only in minutes and seconds, otherwise float is only good for up to about four months of seconds before losing accuracy.
It seems like you wanted your button click handler to do this (increment bar sooner):
private void jButton3ActionPerformed(ActionEvent e) {
mp3.FastForward();
bar+=5; // increment bar before checking complete, and before setting progress
if(mp3.player.isComplete()){
bar = 100;
}
jProgressBar1.setValue((int)bar);
}

set a delay in libgdx game

i have a game(like super jumper, this game is a jumping game) that our character has life. after collision with enemies, his life reduce. and i want to after 1 sec , calculate the collisions. i mean in this 1 sec, if my character contact with enemies , nothing happen and he continue his way.
for this , i define a boolean variable in my GameScreen class, name "collision" and another in Wolrd class, name "collBirds". after one contact with enemy collision and collBirds change to true. but i want after 1 sec collistion change to false. i use several things like System.currentTimeMillis() and "for loop",and nothing happen. i'm not so good in java.
this is my condition:
if(World.collBirds == true && collition == false){
life -= 1;
lifeString = "Life : " + life;
World.collBirds = false;
collition = true;
for (??? "need to stay here for 1 sec" ???) {
collition = false;
}
}
In some cases you could also want to use com.badlogic.gdx.utils.Timer
Example usage:
float delay = 1; // seconds
Timer.schedule(new Task(){
#Override
public void run() {
// Do your work
}
}, delay);
When the first collision occurs, set a float timeSinceCollision = 0;
Then each loop, you will need to add the time since last check to the variable, and check if it's more than a second.
timeSinceCollision += deltaTime;
if(timeSinceCollision > 1.0f) {
// do collision stuff
} else {
// ignore the collision
}
If you want to do this in same thread than you can use Thread.sleep(). But in this case your current thread will freeze and if this is single thread game, than your whole game will freeze. If you don't want your game to freeze for 1 second, than you should spawn the thread and in that thread call the sleep and after sleep, change the flag

read array in certain time range

How can I read an array in java in a certain time? Lets say in 1000 milliseconds.
for example:
float e[]=new float [512];
float step = 1000.0 / e.length; // I guess we need something like that?
for(int i=0; i<e.length; i++){
}
You'd need a Timer. Take a look at its methods... There's a number of them, but they can be divided into two categories: those that schedule at a fixed delay (the schedule(... methods) and those that schedule at a fixed rate (the scheduleAtFixedRate(... methods).
A fixed delay is what you want if you require "smoothness". That means, the time in between executions of the task is mostly constant. This would be the sort of thing you'd require for an animation in a game, where it's okay if one execution might lag behind a bit as long as the average delay is around your target time.
A fixed rate is what you want if you require the task's executions to amount to a total time. In other words, the average time over all executions must be constant. If some executions are delayed, multiple ones can then be run afterwards to "catch up". This is different from fixed delay where a task won't be run sooner just because one might have "missed" its cue.
I'd reckon fixed rate is what you're after. So you'd need to create a new Timer first. Then you'd need to call method scheduleAtFixedRate(TimerTask task, long delay, long period). That second argument can be 0 if you wish the timer to start immediately. The third argument should be the time in between task runs. In your case, if you want the total time to be 1000 milliseconds, it'd be 1000/array size. Not array size/1000 as you did.
That leaves us with the first argument: a TimerTask. Notice that this is an abstract class, which requires only the run() method to be implemented. So you'll need to make a subclass and implement that method. Since you're operating over an array, you'll need to supply that array to your implementation, via a constructor. You could then keep an index of which element was last processed and increment that each time run() is called. Basically, you're replacing the for loop by a run() method with a counter. Obviously, you should no longer do anything if the counter has reached the last element. In that case, you can set some (boolean) flag in your TimerTask implementation that indicates the last element was processed.
After creating your TimerTask and scheduling it on a Timer, you'll need to wait for the TimerTask's flag to be set, indicating it has done its work. Then you can call cancel() on the Timer to stop it. Otherwise it's gonna keep calling useless run() methods on the task.
Do keep the following in mind: if the work done in the run() method typically takes longer than the interval between two executions, which in your case would be around 2 milliseconds, this isn't gonna work very well. It only makes sense to do this if the for loop would normally take less than 1 second to complete. Preferably much less.
EDIT: oh, also won't work well if the array size gets too close to the time limit. If you want 1000 milliseconds and you have 2000 array elements, you'll end up passing in 0 for the period argument due to rounding. In that case you might as well run the for loop.
EDIT 2: ah why not...
import java.util.Random;
import java.util.Timer;
public class LoopTest {
private final static long desiredTime = 1000;
public static void main(String[] args) {
final float[] input = new float[512];
final Random rand = new Random();
for(int i = 0; i < input.length; ++i) {
input[i] = rand.nextFloat();
}
final Timer timer = new Timer();
final LoopTask task = new LoopTask(input);
double interval = ((double)desiredTime/((double)input.length));
long period = (long)Math.ceil(interval);
final long t1 = System.currentTimeMillis();
timer.scheduleAtFixedRate(task, 0, period);
while(!task.isDone()) {
try {
Thread.sleep(50);
} catch(final InterruptedException i) {
//Meh
}
}
final long t2 = System.currentTimeMillis();
timer.cancel();
System.out.println("Ended up taking " + (t2 - t1) + " ms");
}
}
import java.util.TimerTask;
public class LoopTask extends TimerTask {
private final float[] input;
private int index = 0;
private boolean done = false;
public LoopTask(final float[] input) {
this.input = input;
}
#Override
public void run() {
if(index == input.length) {
done = true;
} else {
//TODO: actual processing goes here
System.out.println("Element " + index + ": " + input[index]);
++index;
}
}
public boolean isDone() {
return done;
}
}
Change your step to be time per number (or total time divided by number of steps)
float step = 1000.0 / e.length;
Inside your for() loop:
try{
Thread.sleep(step);
}catch(InterruptedException e){
e.printStackTrace();
}

Problem related to variable persistence between threads in java

all. A thread in a Java program I am working on animates a random walk in space (or at least, it will once this problem is resolved). It contains the following two methods:
public void run() {
while(gw.checkBoundingBox()) {
if(!gw.pause) step();
}
}
public void step() {
Point3d p1, p2;
//get the last point, step, get the new point
p1 = new Point3d(gw.position);
gw.randomStep();
p2 = new Point3d(gw.position);
//create the Alpha that will do the animation, and wrap it in an AlphaControl,
//which will set this object's pause flag until the Alpha finishes
Alpha alpha = new Alpha();
alpha.setLoopCount(1);
if(alpha.finished()) System.out.println("DEBUG: I'm already dead.");
AlphaControl ac = new AlphaControl(alpha,gw);
ac.start();
//create a piece of the path, attach an interpolator to do the animation
PathCyl cyl = new PathCyl(p1,p2);
StretchInterpolator si = new StretchInterpolator(alpha, cyl.anchor);
si.setSchedulingBounds(new BoundingSphere(new Point3d(0,0,0),50));
cyl.anchor.addChild(si);
//put it all together
BranchGroup b = new BranchGroup();
b.addChild(cyl.tg);
trans.addChild(b);
}
So if the pause flag is not set, it runs step(). The only part of step() that you need to look at is the few lines about the Alpha object. (Alpha is an API class that produces a time-dependent function used for animating). So step() creates an Alpha object, which it then feeds to another thread called AlphaControl. AlphaControl tells the program to stop calculating points until this step is done animating. It does this by setting the pause flag that is checked in the run() method.
So what's the problem? Note that I added a debug line that immediately checks if the Alpha is finished after it is created. It seems like this line of code should never execute. Is the Alpha finished? Of course not, we just created it. But this line executes every time that the function is called AFTER the first time. Somehow it is hanging onto the same Alpha instance and using it over and over. I assume that this is because of the reference to the Alpha that is still alive in the AlphaControl thread.
So how do I fix this? I have tried several things. I created a huge array of Alphas, initialized them all before the walk even started, and tried to tell it to use a different alpha from the array at every step, but this had the same result. I also tried using the AlphaControl to set alpha to null before it closes, but this didn't work either. Is it possible to destroy this object? By the time the step() code gets back to running again, the AlphaControl that was created the first time around should be done and waiting for garbage collection.
Also, just in case it would be helpful to see it, here is the AlphaControl class.
public class AlphaControl extends Thread {
public Alpha alpha;
public GraphicalWalker gw;
public AlphaControl(GraphicalWalker gw, Alpha alpha) {
this.gw = gw;
this.alpha = alpha;
}
public void run() {
boolean stop = false;
boolean finished;
while(!stop) {
finished = alpha.finished();
if( !finished && !gw.pause ) gw.pause = true;
if( finished && gw.pause ) gw.pause = false;
if(finished) stop = true;
}
}
}
Thanks in advance for any help.
Jeff
I think key to understanding why your code fails is understanding what the Alpha class of the Java3D library does.
From your question it seems to me you do not understand it correctly. It does not loop. If you check the source code (http://www.java2s.com/Open-Source/Java/6.0-JDK-Modules/java-3d/javax/media/j3d/Alpha.java.htm) you will see it does not contain a single loop structure. What it does do, is define a function that maps a time value to a value in the range [0,1].
If you look at the source of the finished() method :
/**
* Query to test if this alpha object is past its activity window,
* that is, if it has finished looping.
* #return true if no longer looping, false otherwise
*/
public boolean finished() {
long currentTime = paused ? pauseTime : J3dClock.currentTimeMillis();
return ((loopCount != -1) &&
((float)(currentTime - startTime) * .001f > stopTime));
}
you notice that its value depends on when it is called.
And since you basically defined your alpha to have 1 loop of 1 millisecond, starting from the time of creation it will not be finished for 1 millisecond after you create that alpha, and finished ever after.
I hope this helps.
I'm not sure if I completely follow the intent of the program, but it seems like you have a race condition. When you call ac.start() on your AlphaControl object, there is no guarantee that gw.pause will be set prior to the next round of your loop executing. In fact, there's a fair chance that the loop will execute many times prior to gw.pause getting set.
Just for kicks, I suggest calling ac.run() instead of ac.start() on a run-through, as a shortcut to take threading out of the picture. If the intended behavior occurs, then I would look hard at your reason for doing this in multiple threads instead of a single one.
I think the problem is one of two issues:
Alpha's state is kept as a static variable, meaning that it's the same for all instances of Alpha, and you're likely not resetting it in the constructor (rightfully so).
Some part of your state isn't marked volatile, which breaks the semantics the compiler relies on to know that a marked field will always require a fresh value lookup (otherwise the compiler is free to cache the value)

Categories