How to prevent my method launches every loop 10 seconds earlier - forms

I want my other method launches precice 1:50 (10 seconds before ending) The problem is, it launches 10secondes too early every loop. It looks like
1 st loop
1:50 Method launches - correct
2 nd loop
3:40 Method launches - incorrect (10 seconds shorter)
3 rd loop
5:30 Method launches - incorrect (10 seconds shorter)
4 th loop
7:20 Method launches - incorrect (10 seconds shorter)
......
I want every 110 seconds my method launches precisely every 110 seconds.
the code:
private void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
Application.Current.Dispatcher.BeginInvokeOnMainThread(() =>
{
MainTimer.Text = stopwatch.Elapsed.ToString(#"hh\:mm\:ss");
double counter = stopwatch.Elapsed.TotalSeconds;
Tasklabel.Text = counter.ToString(); // tried to look what's going on
if (((int)counter % 120 == 0 && (int)counter != 0))
{
Value = false;
stopwatch.Stop();
timer.Stop();
// do sth
}
// I tried
//counter2 += 10;
// also tried to assign another variable // double counter2 = stopwatch.Elapsed.TotalSeconds;
if (((int)counter2 % 110 == 0 && (int)counter2 != 0))
{
// do sth
}
});
}
How to write it properly

You could make a small change to the code.
private void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
Application.Current.Dispatcher.BeginInvokeOnMainThread(() =>
{
MainTimer.Text = stopwatch.Elapsed.ToString(#"hh\:mm\:ss");
double counter = stopwatch.Elapsed.TotalSeconds;
if ((((int)counter + 10) % 120 == 0 && (int)counter != 0)) // make changes here
{
//make a stop at 1:50, 3:50, 5:50...
Value = false;
timer.Stop();
stopwatch.Stop();
counter = 0;
// do sth
Console.WriteLine("TIMER Close==============");
}
});
}
Hope it works for you.

Related

Unity 2D: How to decrement static int in while loop using deltaTime

In my Player script I set a static int called boost to be used from any script.
I have a few boost pick up coins through out the game, when the player gets one it fills their boost tank by +1
You need a min of 3 boost coins to start boosting in the vehicle. When the player is using boost, the boost will last for about as many seconds as many boost coins collected. Using the boost should decrement the boost tank.
Player Script
public static int boost;
private void OnTriggerEnter2D(Collider2D otherObject)
{
if (otherObject.tag == "Boost")
{
boost++;
GetComponent<AudioSource>().PlaySound(BoostSound, 5.7F);
Destroy(otherObject.gameObject);
}
}
Button call code
public void BoostButton()
{
StartCoroutine("Use_VehicleBoost");
}
Booster code that a button calls.
IEnumerator Use_VehicleBoost()
{
// Check which boost package player picked
int boostLevel = SecurePlayerPrefs.GetInt("BoostLevel");
if (boostLevel == 0)
{
Debug.Log("Boost Level: None");
yield return null;
}
else if (boostLevel == 1)
{
Debug.Log("Boost Level: 1");
float aceleRate = 400, maxFWD = -2500;
while (Player.boost >= 3)
{
vehicleController.GetComponent<CarMovement>().accelerationRate += aceleRate;
vehicleController.GetComponent<CarMovement>().maxFwdSpeed += maxFWD;
// Meant to slowly take one point/ Time second away from boost tank // Problem is here ----->>>
Player.boost = Player.boost - Mathf.RoundToInt(Time.deltaTime);
yield return null;
}
if (Player.boost <= 0)
{
yield return null;
}
}
yield return null;
}
Problem is here in this line
Player.boost = Player.boost - Mathf.RoundToInt(Time.deltaTime);
It is supposed to be decrementing with seconds from Player.boost. For example if player collects 3 boost coins then boost is active when used it will last for 3 seconds before turning off.
Not exactly sure on what to do here. They told me that in the while loop the deltaTime stays at value 0 because its stuck in one frame? Am I supposed to start a timer variable? Thank you.
Not exactly sure on what to do here. They told me that in the while
loop the deltaTime stays at value 0 because its stuck in one frame? Am
I supposed to start a timer variable?
Yes, I did say that but you have fixed the one frame issue with yield return null; which let's the loop to wait one frame therefore giving Time.deltaTime chance to change. Even with that being fixed, there is still 0 issue I told you but because while (Player.boost >= 3) is still true. That is true because Mathf.RoundToInt(Time.deltaTime); is returning zero. You can verify this with Debug.Log(Mathf.RoundToInt(Time.deltaTime)).
If Player.boost type is an int, change it to a float type, to gradually decrease it with Time.deltaTime directly:
while (Player.boost >= 3)
{
vehicleController.GetComponent<CarMovement>().accelerationRate += aceleRate;
vehicleController.GetComponent<CarMovement>().maxFwdSpeed += maxFWD;
// Meant to slowly take one point/ Time second away from boost tank
Player.boost = Player.boost - Time.deltaTime;
//OR Player.boost -= Time.deltaTime;
yield return null;
}
If Player.boost type is an int but you don't want to change it to float, remove the Time.deltaTime as that's used for float values then do the waiting with WaitForSeconds. With this you can subtract one from boost after each WaitForSeconds call.
while (Player.boost >= 3)
{
vehicleController.GetComponent<CarMovement>().accelerationRate += aceleRate;
vehicleController.GetComponent<CarMovement>().maxFwdSpeed += maxFWD;
// Meant to slowly take one point/ Time second away from boost tank
Player.boost = Player.boost - 1;
//OR Player.boost -= 1;
yield return new WaitForSeconds(1f);
}

How to offset note scheduling for interactive recording of notes via user controls

In the code below I have a note scheduler that increments a variable named current16thNote up to 16 and then looping back around to 1. The ultimate goal of the application is to allow the user to click a drum pad and push the current16thNote value to an array. On each iteration of current16thNote a loop is run on the track arrays looking for the current current16thNote value, if it finds it the sound will play.
//_________________________________________________________General variable declarations
var isPlaying = false,
tempo = 120.0, // tempo (in beats per minute)
current16thNote = 1,
futureTickTime = 0.0,
timerID = 0,
noteLength = 0.05; // length of "beep" (in seconds)
//_________________________________________________________END General variable declarations
//_________________________________________________________Load sounds
var kick = audioFileLoader("sounds/kick.mp3"),
snare = audioFileLoader("sounds/snare.mp3"),
hihat = audioFileLoader("sounds/hihat.mp3"),
shaker = audioFileLoader("sounds/shaker.mp3");
//_________________________________________________________END Load sounds
//_________________________________________________________Track arrays
var track1 = [],
track2 = [5, 13],
track3 = [],
track4 = [1, 3, 5, 7, 9, 11, 13, 15];
//_________________________________________________________END Track arrays
//_________________________________________________________Future tick
function futureTick() {
var secondsPerBeat = 60.0 / tempo;
futureTickTime += 0.25 * secondsPerBeat;
current16thNote += 1;
if (current16thNote > 16) {
current16thNote = 1
}
}
//_________________________________________________________END Future tick
function checkIfRecordedAndPlay(trackArr, sound, beatDivisionNumber, time) {
for (var i = 0; i < trackArr.length; i += 1) {
if (beatDivisionNumber === trackArr[i]) {
sound.play(time);
}
}
}
//__________________________________________________________Schedule note
function scheduleNote(beatDivisionNumber, time) {
var osc = audioContext.createOscillator(); //____Metronome
if (beatDivisionNumber === 1) {
osc.frequency.value = 800;
} else {
osc.frequency.value = 400;
}
osc.connect(audioContext.destination);
osc.start(time);
osc.stop(time + noteLength);//___________________END Metronome
checkIfRecordedAndPlay(track1, kick, beatDivisionNumber, time);
checkIfRecordedAndPlay(track2, snare, beatDivisionNumber, time);
checkIfRecordedAndPlay(track3, hihat, beatDivisionNumber, time);
checkIfRecordedAndPlay(track4, shaker, beatDivisionNumber, time);
}
//_________________________________________________________END schedule note
//_________________________________________________________Scheduler
function scheduler() {
while (futureTickTime < audioContext.currentTime + 0.1) {
scheduleNote(current16thNote, futureTickTime);
futureTick();
}
timerID = window.requestAnimationFrame(scheduler);
}
//_________________________________________________________END Scheduler
The Problem
In addition to the previous code I have some user interface controls as shown in the following image.
When a user mousedowns on a “drum pad” I want to do two things. The first is to hear the sound immediately , and the second is to push the current16thNote value to the respective array.
If I use the following code to do this a few problems emerge.
$("#kick").on("mousedown", function() {
kick.play(audioContext.currentTime)
track1.push(current16thNote)
})
The first problem is that the sound plays twice. This is because when the sound is pushed to the array it is immediately recognized by the next iteration of the note scheduler and immediately plays. I fixed this by creating a delay with setInterval to offset the push to the array.
$("#kick").on("mousedown", function() {
kick.play(audioContext.currentTime)
window.setTimeout(function() {
track1.push(note)
}, 500)
})
The second problem is musical.
When a user clicks a drum pad the value that the user anticipates the drum will be recorded at is one 16th value earlier. In other words if you listen to the metronome and click on the kick drum pad with the intent of landing right on the 1/1 down beat this won't happen. Instead, when the metronome loops back around it will have been “recorded” at one 16th increment later.
This can be remedied by writing code that intentionally offsets the value that is pushed to the array by -1 .
I wrote a helper function named pushNote to do this.
$("#kick").on("mousedown", function() {
var note = current16thNote;
kick.play(audioContext.currentTime)
window.setTimeout(function() {
pushNote(track1, note)
}, 500)
})
//________________________________________________Helper
function pushNote(trackArr, note) {
if (note - 1 === 0) {
trackArr.push(16)
} else {
trackArr.push(note - 1)
}
}
//________________________________________________END Helper
My question is really a basic one. Is there a way to solve this problem without creating these odd “offsets” ?
I suspect there is a way to set/write/place the current16thNote increment without having to create offsets to other parts of the program. But I'm hazy on what it could be.
In the world of professional audio recording there isn't a tick per 16th division value , you usually have 480 ticks per quarter note. I want to begin exploring writing my apps using this larger value but I want to resolve this "offset" issue before I go down that rabbit hole.

Is there a way to know when the stage is moved in Java FX?

In my application, I have the need to open a stage in the last place that it existed.
Currently I have implemented the saving of the location like so:
stage.setOnHidden(event -> {
PositionDTO dto = new PositionDTO();
dto.setHeight(stage.getHeight());
dto.setWidth(stage.getWidth());
dto.setX(stage.getX());
dto.setY(stage.getY());
//save the position to either a file or database...
});
However, I am wondering if there is a way to set that value when the user drags the window(stage) to a new location since they can open this stage more than one at a time, and opening in the same spot is what the users want. They may not have closed the first one that was opened?
I can't seem to find an event I can listen for.
Thanks!
This is one option for detecting whether or not the Stage has stopped moving so that you can record the location of its X and Y position:
double thisX = 0;
double thisY = 0;
private boolean windowStoppedMoving() {
boolean windowStoppedMoving = false;
try {
double x = thisX;
double y = thisY;
TimeUnit.SECONDS.sleep(2);
boolean xNotChanged = x == thisX;
boolean yNotChanged = y == thisY;
windowStoppedMoving = yNotChanged && xNotChanged;
}
catch (InterruptedException e) {e.printStackTrace();}
return windowStoppedMoving;
}
Then you register a ChangeListener on the Scene Window xProperty and yProperty:
scene.getWindow().xProperty().addListener((observable, oldValue, newValue) -> {
thisX = (double) newValue;
new Thread(() -> {
if (windowStoppedMoving()) {
double finalXValue = thisX;
double finalYValue = thisY;
}
}).start();
});
scene.getWindow().yProperty().addListener((observable, oldValue, newValue) -> {
thisY = (double) newValue;
});
As the user is dragging the window around the screen, the xProperty ChangeListener sets thisX to the newValue each time it is called, then it fires off a thread, while the yProperty is simply setting the value of thisY each time it is called. The thread starts by recording the value of thisX and thisY, then it waits for 2 seconds and if those values have not changed, it returns true.
It works quite well and only returns one true result after the window stops moving.

if Statement Acting Up

This is within the Update function. Excuse the brakeTorque stuff, that's just a bandaid for now. This is a drag racing game, and Staged means ready to go. Once both cars are staged, and the race hasn't started yet, then there should be a delay of 5 seconds then the words "GO 1" should appear (I added stupidCounter as a debugging tool). Then it sets the start time. Then it sets Racing to true in order to keep it from jumping back into this if statement again.
The issue is that it keeps jumping back in the if statement every frame; printing: GO1 GO2 GO3 etc.
The word "GO" is not mentioned anywhere else in any other script.
The "Racing" boolean is not mentioned anywhere else in any script.
Here's my code:
if(Staged && OtherCarStaged() && !Racing)
{
RearRightWheel.brakeTorque = 10000;
RearLeftWheel.brakeTorque = 10000;
FrontRightWheel.brakeTorque = 10000;
FrontLeftWheel.brakeTorque = 10000;
yield WaitForSeconds(5);
stupidCounter += 1;
Debug.Log("GO " + stupidCounter);
mainTimerStart = Time.realtimeSinceStartup;
Racing = true;
}
I'm assuming your function is a coroutine. The issue in your code is probably because you are calling the coroutine in every update frame. You either need to add a check to call the coroutine only once, or use your own timer to handle this instead of a coroutine.
Based on your mentioned requirement I think your code should go like this
var timeLeft : float = 5;
function Update()
{
StartCountdown();
}
function StartCountdown()
{
if(Staged && OtherCarStaged() && !Racing)
{
// your stuff
timeLeft -= Time.deltaTime;
if(timeLeft <= 0)
{
Debug.Log("GO");
mainTimerStart = Time.realtimeSinceStartup;
Racing = true;
}
}
}
Or, if you want to go with Coroutines, it would go like this
function Update()
{
if(!countdownStarted && Staged && OtherCarStaged())
StartCoroutine(StartCountdown(5));
}
var countdownStarted : bool = false;
function StartCountdown(float time)
{
countdownStarted = true;
yield WaitForSeconds(time);
Debug.Log("GO ");
mainTimerStart = Time.realtimeSinceStartup;
Racing = true;
}

Digging technique counter

I'm making and game which has digging as it's feature so I need timer which will count exact float (in seconds) and then destroy gameObject. This is what I tried now but it's freezing unity:
function Update()
{
if (Input.GetMouseButtonDown(0))
{
digTime = 1.5; // in secounds
}
while (!Input.GetMouseButtonUp(0)) // why is this infinite loop?
{
digtime -= Time.deltaTime;
if (digtime <= 0)
{
Destroy(hit.collider.gameObject);
}
}
Here is a basic example how you can check if player has clicked for a certain time period.
#pragma strict
// This can be set in the editor
var DiggingTime = 1.5;
// Time when last digging started
private var diggingStarted = 0.0f;
function Update () {
// On every update were the button is not pressed reset the timer
if (!Input.GetMouseButton(0))
{
diggingStarted = Time.timeSinceLevelLoad;
}
// Check if the DiggingTime has passed from last setting of the timer
if (diggingStarted + DiggingTime < Time.timeSinceLevelLoad)
{
// Do the digging things here
Debug.Log("Digging time passed");
// Reset the timer
diggingStarted = Time.timeSinceLevelLoad;
}
}
It is firing every DiggingTime of seconds even the player is holding the button down. If you want that the player needs to release the button and press again one solution is to add Boolean telling if the timer is on or not. It can be set true on GetMouseButtonDown and false on GetMouseButtonUp.
Update function is called every frame. If you add a while loop inside this function waiting for the mouseButtonUp, you'll freeze Unity for sure.
You don't need the while loop. Just check GetMouseButtonUp without while loop.
EDIT
This is the Update function:
void Update ()
{
if ( Input.GetMouseButtonDown( 0 ) )
{
digTime = 1.5f;
}
else if ( Input.GetMouseButton( 0 ) )
{
if ( digTime <= 0 )
{
Destroy( hit.collider.gameObject );
}
else
{
digTime -= Time.deltaTime;
}
}
}
Minor controls should be added to avoid destroying gameObject several times, but this is the idea to proceed