Processing P5 - Timer issue with millis() - java

I am making a little game in Processing which is similar to those Guitar Hero style games and I am trying to do 2 things:
When the game loads, stop the time from moving
During the game, allow for Pause functionality
Now, I know I cant stop the time since the millis() returns the milliseconds since the application launched, so my timer will need to be millis() - millis() at the start to equal zero, so when the user presses START, they can obviously start at the start. The game reads a file at the start, similar to a subtitles file, that has the note to be played and the time in milliseconds that it should appear on screen.
My problem is, when I pause the game, the timer keeps going and when I unpause the game, all the notes get "bunched up" due to my logic, as you'll see from my code.
Can someone suggest a better algorithm than the one I'm using? Its late and I've been working on this all day and night. I think the problem is with the for() below:
public void draw()
{
if (gameInProgress)
{
currentTimerValue = millis(); // Update the timer with the current milliseconds
// Check to see if the note times falls between the current time, or since the last loop (difficult to match exact millisecond)
for(int i=0 ; i<songNotes.length ; i++)
{
if( songNotes[i].getStartTime() > previousTimerValue && songNotes[i].getStartTime() <=currentTimerValue)
notes.add(songNotes[i]);
}
noStroke();
textFont(f,18);
drawButtons(); //Draws coloured buttons relating to Button presses on the controller
drawHighScoreBox(); // Draws high score box up top right
drawLines(); // Draws the strings
moveNotes(); // Moves the notes across from right to left
//Now set the cutoff for oldest note to display
previousTimerValue=currentTimerValue; //Used everytime on the following loop
}
else
{
drawMenu(); // Draw the Main/Pause menu
}
}
NOTE: The boolean gameInProgress is set below when the users presses the pause button, eg "P", and songNotes is an array of objects of type Note that I wrote myself. It has 2 member variables, noteToBePlayed and timeToBePlayed. The method getStartTime()returns timeToBePlayed which is a millisecond value.
Any help is appreciated.
Thanks

How about having another integer to store time when you pause and use that to offset the game timer ?
So, in 'gameInProgress' mode you update currentTimerValue and previousTimerValue and in 'paused/menu' mode you update a pausedTimerValue, which you use to offset the 'currentTimerValue'. I hope this makes sense, it sounds more complicated in words, here's what I mean:
boolean gameInProgress = true;
int currentTimerValue,previousTimerValue,pausedTimerValue;
void setup(){
}
void draw(){
if(gameInProgress){
currentTimerValue = millis()-pausedTimerValue;
println("currentTimerValue: " + currentTimerValue + " previousTimerValue: " + previousTimerValue);
previousTimerValue=currentTimerValue;
}else{
pausedTimerValue = millis()-currentTimerValue;
}
}
void mousePressed(){
gameInProgress = !gameInProgress;
println("paused: " + (gameInProgress ? "NO" : "YES"));
}
Click the sketch to toggle modes and look in the console for times. You'll notice that you only loose a few millis between toggles, which is acceptable.

Use not system timer but special timer class with pause functionality. I'm sure it is not hard to implement such class by yourself. I know that java has Timer class but unfortunately it not support pause functionality.

Related

JavaFX event triggered by time value triggers multiple times

I am relatively new to programming, and to help myself I am making a personal project.
I am using Javafx to build drum machine, which allowing the user to program a sequence of beats.
I have constructed sets of rows which each will function as a programmable beat sequencer for each corresponding instrument, with each row consisting of 16 buttons. if that button is pressed, the button is activated, and it will produce the instrument's sound when the loop passes through that point.
for reference this piece of kit is similar to what i wish to construct :
https://images-na.ssl-images-amazon.com/images/I/81RctDCP38L._AC_SL1500_.jpg
Each button is assigned to a hashmap; the Key is an integer from 0-16, while the value is the button's characteristics itself.
The drum machine loops after 4 bars/ 16 buttons.
To trigger the event and to cause the instrument to play, the time (as a fraction of all buttons/16) will match the key of a button. once this occurs, the sound plays. the method to do this is below:
public void beatState(Button button, String filename) {
EventHandler handler = new EventHandler() {
#Override
public void handle(Event event) {
soundGeneration sound = new soundGeneration(filename);
// if the corresponding buttons key (on a range of 0-16) matches the time as a fraction (0-16)
// and if the button text is on (activated by clicking the pad)
if (button.equals(map.get(time.timeToFraction())) & button.getText().equals("On")) {
// plays the file
sound.play();
// when duration of animation is set lower the filename prints more frequently
// or sometimes not printed/sound played when the duration is higher
System.out.println(filename);
}
}
};
// as i increase the duration of the animation , the program becomes both slower but returns
// both the sound file and prints the filename more often
Timeline animationButton = new Timeline(new KeyFrame(Duration.millis(100), handler));
animationButton.setCycleCount(Timeline.INDEFINITE);
animationButton.play();
}
I'll next provide the time element:
public Integer timeToFraction(){
labelFormat();
new AnimationTimer() {
#Override
public void handle(long now) {
// time elapsed since program execution
double elapsedMillis = (System.currentTimeMillis() - startTime);
// converts to long
// multiplies the value to privide a fraction
long numerator = (long) ((elapsedMillis/1000)*8.33);
// value below denominates the time it takes to travel 4 beats at 125 beats per minute
double denominator = 1.92;
// converts below to show as a fraction
long denominatorToBeat =(long) Math.round(denominator * 8.3);
// if the elapsed time raises over 16
// resets numerator
if (numerator> denominatorToBeat) {
startTime = System.currentTimeMillis();
elapsedMillis = (System.currentTimeMillis() - startTime);
}
// converts from long to to allow for hashmap matching against button position
fractionTime = (int) numerator;
}
}.start();
return fractionTime;
}
When the values match up the beat plays, achieving my aim; however, it plays multiple times, and irregular in relation to the beat.
I assume that the animation timer repeat value in milliseconds is what causes this; I decrease it, there are more unwanted repeated sounds. I increase it and notes sometimes are not counted due to the animation passing over the value before it triggers.
I want the code to trigger the sound file when it passes over the button, more specifically when the Integer value of the hashmap the button corresponds to matches the time fraction.
I have spent hours researching and reading the documentation and for an easy problem it is becoming incredibly difficult to work around. Given that this project is seen in a multitude of portfolios and music development software i am sure there is a simple fix to my issue.
Thanks for taking the time.
Your approach in general is wrong, as you are abusing animation timers to do something not related to the GUI. You have to decouple the logic from the GUI.
I.e. The object which controls the timing and playing the sounds should have nothing to do with the buttons or any GUI. It should have some methods to set / clear a sound at particular interval, and then expose its state using properties, e.g. an ObjectProperty with some class describing the current tones being played.
The buttons should call the methods to set / clear tones, and you can add a change listener to the ObjectProperty to update the buttons appearance based on the state.

Bicycle Computer Dead Reckoning

I am creating a device where you can do video game bike racing by putting your bicycle on a trainer and hooking it up to your tablet/phone, which will count the pulses from a reed switch or hall effect sensor and calculate your speed, distance, etc in the same manner as a regular bike computer, and use that to move your avatar in the game world. It's written in Java with libGDX.
I'm stuck trying to get the digital bike to coast to a stop. If you are going a given speed, such that the time between pulses is normally 100ms, then if we check the time delta and it's been 200ms since the last click, we know you can't be going more than half of your former speed, and we should adjust down accordingly every time we update your speed, eventually passing some threshold where we decide you've effectively stopped.
I want the speed to decay along a roughly logarithmic curve so that hopefully I can approximate the speed envelope that your bike would have out on pavement. I also need to be smart about estimating the distance you've traveled since the last click, so that your distance doesn't jump ahead if we suddenly get a click.
How can I accomplish getting the bike to coast to a stop, and how should I go about positioning the bike in the game world with the uncertainty of how far we have to go until the next click? I have scoured the Internet looking for examples of code for a bicycle computer, and haven't found any yet, let alone any that have the added restriction that they need to be able to render their current position in the game world.
Here's the code:
The click function runs every time we get another pulse from the bike sensor:
public void click() {
currentTime = System.currentTimeMillis();
int delta = (int) (currentTime - lastClick);
// If we have less than N samples, just add it to the list.
// Otherwise pop one off and fill it in with the new value.
if (samples.size() == SAMPLE_RESOLUTION) {
samples.remove(0);
}
samples.add(delta);
clicks += 1;
lastClick = currentTime;
}
And the averageSamples function averages the last N samples to smooth out the speed. It's just a simple average right now, but later I intend on making it weighted such that new data is weighted more than old data.
public double averageSamples() {
Integer sum = 0;
if (!samples.isEmpty()) {
for (Integer sample : samples) {
sum += sample;
}
return wheelCircumference / (sum.doubleValue() / samples.size());
}
return sum.doubleValue();
}
And finally, the update function runs every frame of the game, so about once every 60th of a second. It's supposed to calculate your speed and distance, guessing how far you've gone since the last click based on the amount of time that's passed since then:
public void update() {
double newSpeed;
currentTime = System.currentTimeMillis();
int delta = (int) (currentTime - lastClick);
// The below line needs to adjust your speed downward if it's been too long since the last click. We're hoping for a smooth curve on the way to coasting to a stop.
newSpeed = averageSamples();
elapsedTime = currentTime - startTime;
instSpeed = newSpeed;
avgSpeed = (avgSpeed + instSpeed) / 2;
maxSpeed = Math.max(newSpeed,instSpeed);
/* This line needs to guess how far you've gone since the last click. Right now I'm using this value directly to draw the bike at a certain place in the game world, so we need to do this in a way that if we suddenly get a click, you don't end up jumping forward. */
distance = (long) (clicks * wheelCircumference);
}

How to implement different events through single tap and double tap in libgdx?

I am using LibGdx to develop an android game . I have implemented the gesture listener class in my InputHandler class . Now in the tap method I have to implement two features , short jump and long jump on single tap and double tap respectively. When I try to implement it using the count value of the function , the problem is when I double tap the screen the count value firstly becomes 1 and then 2 so it does not go into the second if statement and and the feature of short jump occurs. So how to differentiate single jump from double jump? Below is the code
#Override
public boolean tap(float x, float y, int count, int button) {
// TODO Auto-generated method stub
if(count==1)
{
//feature 1
}
if(count==2)
{
//feature 2
}
return true;
}
two solutions comes to my mind:
Use delay technique which would come with following steps:
when tap-count is 2 : trigger action for double tap
when tap-count is 1 : wait some time, if not tapped second time trigger action for single tap
code would be something like:
if(count==1)
{
if(wait) //wait is a boolean tells if it was tapped once already
{
if(getCurrentTime() - startTime > interval) //getCurrentTime() return current time or frame count or something
{
wait = false;
//feature 1
}
}
else
{
wait = true;
startTime = getCurrentTime(); //start time keeps the time when tapped first one
}
}
if(count==2)
{
//feature 2
}
return true;
}
the problem I see here is firstly "how to choose long enough interval for waiting for secon tap?" - if you will choose to short it will be impossible to make double tap, if too long there will be a lag and user will see that the character is not jumping directly after tap
Divide jump for a pieces and trigger them depends on tap count
And it depends on your "jumping" mechanism. If it be something like:
A. add force to jump
B. keep adding some force for some time to keep object in the air
C. avoid adding force to take object down back to ground
you could modify time to keep object in the air longer. If your "jumping mechanism" is more like impuls adding force (in upper example it would be variant without B point) you could add the force in A again for a some time and if user tapped second time before this interval ends keep on adding it just longer.
This solution eliminates lag problem but depends on "jumping mechanism" you choose.
Regards,
MichaƂ

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

Making just one part of the class wait for execution, with or without threads?

I am coding a space invaders clone, I need the invaders to do their usual movement but pause for one second before moving again.
EG. Move 5 pixels, then wait, then move another 5 pixels.
The method called moveInvaders() is the method I want to make wait for 1000ms. Below is that such method.
private void moveInvaders() {
if(direction == "right") {
if(invaderGreenEight.getX() == 455 || invaderRedEight.getX() == 455 || invaderBlueEight.getX() == 455) {
direction = "left"; // Change direction to left
}
} else {
if(invaderGreenOne.getX() == 15 || invaderRedOne.getX() == 15 || invaderBlueOne.getX() == 15) {
direction = "right"; // Change direction to right
}
}
if(direction == "right") {
// Move Green Invaders Right
invaderGreenOne.moveX(1);
invaderGreenTwo.moveX(1);
invaderGreenThree.moveX(1);
invaderGreenFour.moveX(1);
invaderGreenFive.moveX(1);
invaderGreenSix.moveX(1);
invaderGreenSeven.moveX(1);
invaderGreenEight.moveX(1);
// Move Red Invaders Right
invaderRedOne.moveX(1);
invaderRedTwo.moveX(1);
invaderRedThree.moveX(1);
invaderRedFour.moveX(1);
invaderRedFive.moveX(1);
invaderRedSix.moveX(1);
invaderRedSeven.moveX(1);
invaderRedEight.moveX(1);
// Move Blue Invaders Right
invaderBlueOne.moveX(1);
invaderBlueTwo.moveX(1);
invaderBlueThree.moveX(1);
invaderBlueFour.moveX(1);
invaderBlueFive.moveX(1);
invaderBlueSix.moveX(1);
invaderBlueSeven.moveX(1);
invaderBlueEight.moveX(1);
}
if(direction == "left") {
// Move Green Invaders Left
invaderGreenOne.moveX(-1);
invaderGreenTwo.moveX(-1);
invaderGreenThree.moveX(-1);
invaderGreenFour.moveX(-1);
invaderGreenFive.moveX(-1);
invaderGreenSix.moveX(-1);
invaderGreenSeven.moveX(-1);
invaderGreenEight.moveX(-1);
// Move Red Invaders Right
invaderRedOne.moveX(-1);
invaderRedTwo.moveX(-1);
invaderRedThree.moveX(-1);
invaderRedFour.moveX(-1);
invaderRedFive.moveX(-1);
invaderRedSix.moveX(-1);
invaderRedSeven.moveX(-1);
invaderRedEight.moveX(-1);
// Move Blue Invaders Right
invaderBlueOne.moveX(-1);
invaderBlueTwo.moveX(-1);
invaderBlueThree.moveX(-1);
invaderBlueFour.moveX(-1);
invaderBlueFive.moveX(-1);
invaderBlueSix.moveX(-1);
invaderBlueSeven.moveX(-1);
invaderBlueEight.moveX(-1);
}
}
The game is already a thread and the method in question is in the same class so issuing Thread.sleep(1000); just pauses the entire game for 1 second, but I just want the execution of one method to pause.
If you want more information I am more than happy to provide it.
GeissT
The moveInvaders() method should keep track of a member variable which stores the time the invaders were last moved (e.g. as a long number of milliseconds), this way, any time it is called it can check the value of that variable - if enough time has elapsed then the invaders can move, if not, then the method will simply return without doing anything. For example:
protected long invadersLastMovedMillis;
protected void moveInvaders() {
long currentTime = System.currentTimeMillis();
if ((invadersLastMovedMillis != 0)
&& ((currentTime - invadersLastMovedMillis) < 1000L)) {
return; // No need to move them yet.
}
// March on, space invaders!
invadersLastMovedMillis = currentTime;
}
You don't want to actually cause the thread to sleep because the game will then become unresponsive!
I'm guessing that you would use a Timer of some sort, but what sort will depend on many issues not yet known to us. What GUI library are you using?
For example, if this were a Swing GUI, I'd suggest using a Swing Timer for this delay -- but again, we've no idea what libraries your using.
Bottom line: Please provide more information and code.
Edit:
First suggestion: Get rid of all if (myString == "Foo"). You shouldn't compare Strings that way since this checks if one String object is one and the same as another, and you don't care about this. You want to know if they have the same content. Instead use the String#equals(...) or String#equalsIgnoreCase(...) methods.
Next: use arrays to reduce the severe code redundancy present.
Finally for a Swing app, consider using a Swing Timer to drive your game loop, and in the timer notify items listening to it of time ticks. Then have the items only respond after a certain amount of time has elapsed since their last action.
Create another thread (say T1) at the same level where you create game thread.
Start it after game thread is fully created OR when moveInvaders() method can be called without any crash.
ASA game thread ends, stop T1 also.
The game is already a thread and the method in question is in the same class so issuing Thread.sleep(1000);just pauses the entire game for 1 second, but I just want the execution of one method to pause.
The problem is there is one class, one object and only one thread to execute. It should be one class, one object and two thread. (Game Thread and T1)

Categories