I want that when I press and hold space button that the spaceship's bullets shoot every 2 seconds. Now if I press and hold space button the spaceship shoots lots of bullets in one line. How can I fix this?
Method in class Game
public void newBullet() {
Bullet k = new Bullet(this.spaceship.getX() + (Spaceship.WIDTH / 2), this.spaceship.getY() - 15, DEFAULT_SPEED,type.SPACESHIP);
bullets.add(k);
}
public class ShootBullet extends TimerTask {
private Game model;
private SpaceInvadersController controller;
public ShootBullet(Game model, SpaceInvadersController controller) {
this.model = model;
this.controller = controller;
}
#Override
public void run() {
long lastTime = System.nanoTime();
final double amountOfTicks = 60.0;
final double ns = 1000000000 / amountOfTicks;
double delta = 0;
while(true){
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while(delta >= 1) {
this.model.tick();
Platform.runLater(controller::update);
delta--;
}
}
}
}
This is in controller:
private void move(KeyEvent k) {
switch(k.getCode()){
case LEFT:
this.model.spaceshipLeft();
break;
case RIGHT:
this.model.spaceshipRight();
break;
case UP:
this.model.spaceshipUp();
break;
case DOWN:
this.model.spaceshipDown();
break;
case SPACE:
this.shoot();
break;
}
view.update();
}
private void shoot() {
ShootBullet task = new ShootBullet(this.model, this);
this.model.newBullet();
timer2.scheduleAtFixedRate(task, 0, 1000);
update();
}
Check the documentation for KeyEvent. You will notice there are three types of events:
KEY_PRESSED
KEY_TYPED (is only generated if a valid Unicode character could be generated.)
KEY_RELEASED
The KEY_TYPED events are the problematic ones for you, since they are generated by the hardware/keyboard driver according to operating system settings. You cannot change the rate at which they fire.
But you can completely ignore them and go for KEY_PRESSED and KEY_RELEASED. So as soon as you notice a KEY_PRESSED event, start your timer that will fire at the rate you want, and stop that timer when you receive a KEY_RELEASED.
Related
Okay so I am trying to add methods this stopwatch class to pause and resume the time on the stopwatch. The stopwatch works fine and so does the resume method. The problem is with the pause method.
When I use elapsedTime to check how much time has passed and then the pause method to pause the time and then I wait for a little bit and check the time again, the time paused. However if I then wait for a little bit and check the time again by using elapsedTime (without using pause() again) the time changes as if I had resume the time. If I check time, pause, check time, pause,... then the time does not change but obviously I want the time to stay paused until I resume.
public class Stopwatch {
private final long start;
private long additionalTime;
private long pauseStart;
public Stopwatch() {
start = System.currentTimeMillis();}
public void pause() {
if (pauseStart == 0)
pauseStart = System.currentTimeMillis();
}
public void resume() {
if (pauseStart != 0) {
long stopTime = System.currentTimeMillis() - pauseStart;
additionalTime += stopTime;
pauseStart = 0;
}
}
public double elapsedTime() {
long now = System.currentTimeMillis();
if (pauseStart != 0) {
long stopTime = System.currentTimeMillis() - pauseStart;
additionalTime += stopTime;
pauseStart = 0;
}
return ((now - start) - additionalTime) / 1000.0;}
public static void main(String[] args) {
Stopwatch watch = new Stopwatch();
double total = 0.0;
for (int i = 0; i < 100000000; i++)
total += Math.random();
double time = watch.elapsedTime();
StdOut.println(timi);
watch.pause();
for (int i = 0; i < 200000000; i++)
total += Math.random();
time = watch.elapsedTime();
StdOut.println(time);
for (int i = 0; i < 200000000; i++)
total += Math.random();
time = watch.elapsedTime();
StdOut.println(time);
}
}
I think you should use two different classes. Have you considered something like this?
Rename your Stopwatch class to, let's say: InnerStopwatch.
Create a new Stopwatch class that holds a List of InnerStopwatchs.
When you start a Stopwatch, it creates a new InnerStopwatch, starts it and stores a reference to it as your "current inner stopwatch"
When you pause the Stopwatch, it calls the stop method on the "current inner stopwatch".
When you resume the Stopwatch, it creates a new InnerStopwatch and starts it; and marks it as the new "current inner stopwatch"
When you ask for the elapsed time, than it sums the elapsed times of all inner stopwatchs in the List.
Please let me know if that works for you.
I need to make an image bounce on the screen. I am trying to do this by shifting the image up 5 units, then taking a one second break, then shifting another 5 units up, etc. I am trying to shift up 5 times and then shifting down 5 times, with a one second break between each shift. I need help making the timer for one second so it acts like a break between each shift. I need to write the time() method.
public void moveIt(KeyEvent evt) throws InterruptedException {
switch (evt.getKeyCode()) {
case KeyEvent.VK_DOWN:
myY += 0;
break;
case KeyEvent.VK_UP:
for (int i = 1; i <= 10; i++) {
if (i <= 5) {
bounceUp();
} else {
bounceDown();
}
time();
}
break;
case KeyEvent.VK_LEFT:
myX -= 5;
break;
case KeyEvent.VK_RIGHT:
myX += 5;
break;
}
repaint();
}
Timer timer = new Timer();
public void bounceUp() throws InterruptedException {
myY -= 10;
}
public void bounceDown() throws InterruptedException {
myY += 10;
}
public void time() {
}
Try this:
try{
Thread.sleep(1000);
}catch(InterruptedException e) {
}
TimerTask task = new TimerTask()
{
#Override
public void run()
{
time();//executed each second
}
}
timer.schedule(TimerTask task,1000,1000)
That should help
Welcome to SO!
Try using the schedule in Timer, like this:
Timer timer = new Timer();
timer.schedule(new YourClass(), 0, 1000);
Also, here's a great answer on the same issue:
https://stackoverflow.com/a/12908477/10713658
I'm working on a sudoku solver in javafx and I need to show the algorithm solving. My board is a bunch of buttons laid out in a 9x9 grid and the user enters the puzzle and I solve it.
The solving works fine but I cannot get the algorithm to run. This is what I have but whenever I run the program the window stops responding and I have to terminate the window and get an interrupted by signal 2: SIGINT.
private void loop(Sequence s) {
long currentTime = System.currentTimeMillis();
long lastTime = System.currentTimeMillis();
int x = s.getX();
int y = s.getY();
String n = Integer.toString(s.getNum());
Button button = buttons.get(x).get(y);
boolean isFinished = true;
while(isFinished) {
if(currentTime > lastTime + 400){
button.setText(n);
isFinished = false;
} else {
currentTime = System.currentTimeMillis();
}
}
public void show(){
for (Sequence s : sequences){
loop(s);
}
}
I would like to write a test for a method, that calls observers in a specific intervall, so that they will execute a method. The timer-object runs in its own thread.
Method of timer to be tested
private long waitTime;
public Metronome(int bpm) {
this.bpm = bpm;
this.waitTime = calculateWaitTime();
this.running = false;
}
public void run() {
long startTime = 0, estimatedTime = 0, threadSleepTime = 0;
running = true;
while (running) {
startTime = System.nanoTime();
tick();// notify observers here
estimatedTime = System.nanoTime() - startTime;
threadSleepTime = waitTime -estimatedTime;
threadSleepTime = threadSleepTime < 0 ? 0 : threadSleepTime;
try {
Thread.sleep(threadSleepTime / 1000000l);
} catch (InterruptedException e) {
// sth went wrong
}
}
}
Snippet from my testclass
private int ticks;
private long startTime;
private long stopTime;
#Test
public void tickTest(){
metronome.setBpm(600);
startTime = System.nanoTime();
metronome.run();
long duration = stopTime - startTime;
long lowThreshold = 800000000;
long highThreshold = 900000000;
System.out.println(duration);
assertTrue(lowThreshold < duration);
assertTrue(duration <= highThreshold);
}
#Override
public void update(Observable o, Object arg) {
ticks ++;
if(ticks == 10){
metronome.stop();
stopTime = System.nanoTime();
}
}
Right now, my testclass registers as an observer at the object in question, so that i can count the number of times tick() was executed. The test measures the time before and after the execution, but it feels awkward to me, to test the behaviour this way.
Any suggestions for improving the test?
Sometimes the solution is to use something from a standard library that is sufficiently simple such that it does not need to be tested. I think SchedulerExecuterService will do the trick for replacing the home made Timer being tested here. Note that it is pretty rare to be bit by a bug in library code, but they do exist.
In general though, I think it is okay to create a helper class or use a mocking framework (Mockito) to do something simple like counting "ticks".
P.S. You can replace Thread.sleep(threadSleepTime / 1000000l) with TimeUnit.NANOSECONDS.sleep(threadSleepTime) ... which moves some logic from your code into the standard library.
Based on your comments I changed my code. Instead of implementing the Observer-interface in my testclass, I now created a private class, that implements the interface an registers at my timer.
Thanks for your time and thoughts.
Here is what the code now looks like:
revised testcode
#Test(timeout = 2000)
public void tickTest(){
long lowThreshold = 400000000;
long highThreshold = 600000000;
TickCounter counter = new TickCounter();
metronome.addObserver(counter);
metronome.setBpm(600);
startTime = System.nanoTime();
metronome.run();
long duration = System.nanoTime() - startTime;
assertTrue(lowThreshold <= duration);
assertTrue(duration <= highThreshold);
}
private class TickCounter implements Observer{
private int ticks;
public TickCounter(){
ticks = 0;
}
#Override
public void update(Observable o, Object arg) {
ticks++;
if(ticks == 5){
metronome.stop();
}
}
}
snippet from my revised timer
private long expectedTime; // calculated when bpm of timer is set
#Override
public void run() {
long startTime = 0, elapsedTime = 0, threadSleepTime = 0;
running = true;
while (running) {
startTime = System.nanoTime();
tick();
elapsedTime = System.nanoTime() - startTime;
threadSleepTime = expectedTime - elapsedTime;
threadSleepTime = threadSleepTime < 0 ? 0 : threadSleepTime;
try { TimeUnit.NANOSECONDS.sleep(threadSleepTime); } catch (Exception e) { }
}
}
My biggest issue might have been, that I implemented the observer-interface in my JUnit testcase. So I created a private observer, that specifically counts the number of times, the tick was executed. The counter then stops my timer.
The testmethod measures the timing and asserts, that the needed time is somewhere between my defined limits.
It depends on how accurately you need to measure the time.
If you feel that it's "awkward" is that because you're not sure that the measurement is accurate enough? Do you fear that the OS is getting in the way with overhead?
If so, you may need an external timing board that's synchronized to an accurate source (GPS, atomic standard, etc.) to either test your code, or possibly to provide the trigger for your firing event.
Try this. You also need the time you are expecting. The expected time will be 1000000000/n where n is the number of times your timer needs to tick() per second.
public void run(){
long time = System.nanotime();
long elapsedTime = 0;
// Hope you need to tick 30 times per second
long expectedTime = 1000000000/30;
long waitTime = 0;
while (running){
tick();
elapsedTime = System.nanotime()-time;
waitTime = expectedTime-elapsedTime();
if (waitTime>0){
try { Thread.sleep(waitTime) } catch (Exception e){}
}
time = System.nanotime();
}
}
I am using this method in AndEngine to detect when a user taps on the screen,
#Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
if(pSceneTouchEvent.isActionDown()) {
if(pSceneTouchEvent.isActionDown()) { //Jump only if the user tapped, not moved his finger or something
taps++;
if(taps == 1){
if(isJumping == false){
final float jumpDuration = 2;
final float startX = player.getY();
final float jumpHeight = 100;
final MoveYModifier moveUpModifier = new MoveYModifier(.1f, startX, startX - jumpHeight);
final MoveYModifier moveDownModifier = new MoveYModifier(.1f, startX - jumpHeight, startX);
final SequenceEntityModifier modifier = new SequenceEntityModifier(moveUpModifier, moveDownModifier);
player.registerEntityModifier(modifier);
isJumping = true;
hipp_jump.play();
return true;
}
}
}
}
return false;
}
Sooo The issue I am having with this is that if the user double-taps the screen, then the sprite jumps twice which moves him out of the position he should return to. Because when it jumps twice the Y changes.
How can I allow the sprite to move only ONCE to each tap, even if the user taps more than once?
The manual solution is to set a delay (record a timestamp of tap), and ignore taps within some timedelta. I suggest using the high-resolution java.lang.System.nanoTime()
Especially capacitive touchscreens are prone to generate multiple taps even unintentionally. It is not handled in Android, and has proven to be a serious problem for our app...
Update: pseudocode sample
private long lastTap=0;
onTap() {
long now = System.nanoTime();
if (now-lastTap < threshold) return;
else lastTap = now;
...
}