In a 2D game, that is being developed with libGDX, what is the most effective way to make the footsteps of the player, for example -
if(player.isWalking) {
Timer.schedule(new Task(){
public void run(){
play(single_footstep);
}
}, 0.5f);
}
This code isn't effective at all.. actually it's not working, the sound comes in a bad way, and no matter how much you will play with the delay value its still not effective.
BTW - I am using the Timer class of libgdx, which is very similiar to the util one.
So maybe you have a better idea to implement? I am kinda new to libGDX, so maybe I am missing something.
Thanks in advance :)
Is that code simply in your draw loop? If so, it is going to schedule the sound to play every frame, so you'll be starting 30 or 60 sounds a second (each of which is delayed from when you called it, but still played concurrently). You need to make sure that once you schedule the task, you don't do it again until you're ready to play the sound again.
I would do it without scheduling. Something like this:
if (player.isWalking){
mTimeToNextStep -= deltaTime;
if (mTimeToNextStep < 0){
play(single_footstep);
while (mTimeToNextStep < 0){ //in case of a really slow frame,
//make sure we don't fall too far behind
mTimeToNextStep += TIME_BETWEEN_STEP_SOUNDS;
}
}
} else {
mTimeToNextStep = 0; //or whatever delay you want for the first sound when
//you start walking
}
Related
I am creating a JavaFX application that uses sounds for example for Button hovering. I create an JavaFX AudioClip to create and play the sound. It works ok so far (meaning: I hear the sound).
When the play(); method is called, the sound is played immediatly. If I hover the button 10 times, I hear the sound 10 times.
BUT: in the background JavaFX is creating hundreds of threads when the play() method returns (several hundred for each call). I cannot even see what it actually is, because there are so many, Eclipse does not even show them properly (there is just a white area and a crazy jumping scrollbar up and down).
This causes a massive lag and I do not understand what JavaFX is doing here! It is always the same sound, so I do have cached it into a hashmap already, but the problem is not instantiating the AudioClip, it is clearly stacking up when the play() method returns.
I have been looking into this for hours, but I can't figure out a workaround to reduce the lag (other than maybe reduce the size of the soundfiles, which I did).
final AudioClip soundClip;
if (audioClipCache.get(url.toString()) != null) {
// Log.info("Playing sound from cache...");
soundClip = audioClipCache.get(url.toString());
} else {
// Log.info("Caching sound...");
soundClip = new AudioClip(url.toString());
audioClipCache.put(url.toString(), soundClip);
}
Platform.runLater(new Runnable() {
#Override
public void run() {
soundClip.play(soundVolume);
}
});
Forget the hashmap to cache the AudioClips for a moment, that does not make any difference whatsoever. So called the following code, say, 10 times in a row, leads Java to go crazy for about 10 seconds.
AudioClip soundClip = new AudioClip(url.toString());
soundClip.play(soundVolume);
That works as it should (as in 5.000.000 examples across the internet), but it produces Threads (and Lag) like crazy after the play(); method is called (several hundred threads per hover / call (as descibed)).
I think you have a problem elsewhere in your code. I've distilled your description down to this (admittedly simplistic) example:
#Override
public void start(Stage arg0) throws Exception
{
Thread.sleep(10000);
AudioClip audioClip = new AudioClip(Paths.get("src/main/resources/stackoverflow/audio/alert.wav").toUri().toString());
for (int i = 0; i < 100; i++)
{
int volume = i;
Platform.runLater(() -> audioClip.play(volume));
Thread.sleep(10);
}
arg0.show();
}
Watching Java Mission Control at the ten second mark, I see 100 threads get created all at once. However, they all immediately die (they've played the short alert sound and are done). So the "Live Thread" graph spikes up by 100 threads and then drops right back to where it was within a couple of seconds.
Is there something elsewhere in your code that is holding onto a resource or a thread reference? That's my best suggestion for trying to find out why you're multiplying.
I'm programming a game in Processing3 and I have a problem with the sound file. I'm playing song.play(); on draw() and every frame the program is playing again and again, anyone know a way to make it play the background music just once?
You haven't told us what library you're using- is it Minim?
If so, check out the Minim documentation for a list of classes and functions that you might find useful.
For example the AudioPlayer class has an isPlaying() function that you might use to check whether the song is playing before you play it.
You might also want to rearrange your program so that the song is only triggered once, either from the setup() function, or using the frameCount variable, or in response to user input.
I've found a way to make it work. I've created a variable: int x; and wrote
void draw()
{
x++;
If(x == 1)
song.play();
}
This way the song will play only when x is 1, and as x is growing every frame, it's not gonna be played again.
I want to create a music loop pad, something like this: https://www.youtube.com/watch?v=fwBPYwiYp-Y
Right now, i am using MediaPlayer to play the sounds. I have a global variable that stores the current time (position) of the first audio that is playing, and when i press another button the corresponding audio file starts playing at the position given by the global variable.
My proble is: the sounds are playing out of sync.
can you give me some help? How can i sync the sounds? like this app https://www.youtube.com/watch?v=fwBPYwiYp-Y
Can you point me some info or tutorials about how to create a loop pad?
Thanks
Richardd
Programming something like this is harder than you think. Here are two things you must do to have the sounds play in sync:
Make sure all you sounds are at the same tempo, and are cropped properly - that means that the starting and ending of the sound clip must be exactly on beat - another solution would be to store the starting and ending time for each clip (very easy with OOP)
Use a timer to make sure the sound starts playing on beat. For example, if you wanted to make your music run at 120 bpm, you would need to have your timer fire every 500 ms.
Here is some code (only concept, won't compile):
Timer beatTimer;
boolean isDrumLoopEnabled;
boolean isDrumLoopCurrentlyPlaying;
Sound drumloop;
public void startMusic(){
//prepare timer
beatTimer=new Timer();
beatTimer.interval=500;//for 120 bpm
beatTimer.onTick+=onTickHandler;
isDrumLoopPlaying=false;
isDrumLoopCurrentlyPlaying=false;
//load sounds
Sound drumloop=new Sound("/storage/emulated/drumloop.ogg");
//start music
beatTiemr.start();
}
//this method will run on every beat:
public void onTickHandler(){
if(isDrumLoopEnabled){
//make sure drum loop isn't already playing
if(!isDrumLoopCurrentlyPlaying){
//begin looping drumloop in background
drumloop.startloop();
isDrumLoopCurrentlyPlaying=true;
}
}else{
if(isDrumLoopCurrentlyPlaying){
//stop playing drumloop
drumloop.stopPlaying();
}
}
}
//when the button is pressed...
public void drumloop_buttonpressed(){
//this will toggle whether to play the drum loop:
isDrumLoopEnabled=!isDrumLoopEnabled;
}
I am learning java at the moment and trying to make different features and systems. Right now I am trying to make a really simple particle system, but I have problem.
public void eDelay()
{
try
{
Thread.sleep(17);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
public void engine()
{
int i = 0;
while (i < particles.size())
{
Particle a = (Particle) particles.get(i);
eDelay();
a.move();
i = i + 1;
}
}
public void actionPerformed(ActionEvent e)
{
engine();
repaint();
}
This is a part of my code where the particles suppose to move. It works fine and they do move, but I want them to move one after another one with a delay(17). However, they move all at once and not one after another.
(particles) is an arrayList with 50 elements in it, each element containst a position for a particle.
(a.move()) is just a movement method where particle moves up.
Don't worry for the rest of the code, the problem is in this part.
Graphics, positioning of the particles, movement of the particles, and other things work fine.
Going to make my comment an answer:
"Don't worry for the rest of the code, the problem is in this part. - Graphics, positioning of the particles, movement of the particles, and other things work fine."`
How can you say this when you know what the cause of your problem is? You could be creating a Swing application (which is part of the rest of the code) and calling Thread.sleep(...) on the event thread. So make no assumptions, tell us all of the story, show more pertinent code, and let's help you solve this.
Edit: I now see that this is in fact a Swing application and so that's likely your problem, although you don't show us where the Thread.sleep is called.Calling Thread.sleep(...) puts the thread that calls it asleep, and if this is the Swing event thread (or EDT), it will put your entire application to sleep -- not a good thing to do. So don't call Thread.sleep on the event thread and use a Swing Timer instead. The tutorials will show you how.
And of course again, don't make any assumptions.
You should call repaint in the engine() loop instead of actionPerformed().
Ok guys, this is actually a bit weird but I just rewrote the engine class again into a for loop and it works.
public void engine()
{
goingcrazy = goingcrazy + gameTimer.getDelay();
for(int i = 0; i < particles.size(); i++)
{
if (goingcrazy > 1000*i)
{
Particle a = (Particle) particles.get(i);
a.move();
}
}
}
I already posted a link for the full code so if you are interested you just need to change the old engine class with the one I just posted.
In a simple card game (human vs. CPU) the logic works, but I want to delay the computer's turn.
I have tried using Thread.sleep(int milliseconds) which works, but it messes up the order images are displayed. I'm not using a game loop, I am just dynamically updating ImageViews whenever cards are changed. The problem with Thread.sleep is all the images only update after Thread.sleep, there is no displaying only the human card before Thread.sleep. The human's card and computer's card display after Thread.sleep.
I've used Thread.sleep like so:
playPlayerCard(player); // Human first
displayPile(); // Display card pile (ImageView's)
player = nextPlayer(player); // Get's next player in Player mPlayers List<Player>
// Wait for computer to 'Think'
Thread.sleep(500);
playPlayerCard(player); //Computer's turn
displayPile(); // Display card pile (ImageView's)
Am I using Thread.sleep() wrong? Is there a better/correct way? I've searched online and tried using new Thread(), using handler.postDelayed(Runnable r, long milliseconds) and also CountDownTimer but none work since my variables: playPlayerCard(player); aren't final variables.
I've always had problems delaying actions and the images appearing at the correct times. Any suggestions? Thanks in advance.
Couldn't you just implement the Computer Playing logic in a AsyncTask and fire it when the human turn is done ?
I think it would make much more sense, that way, as soon as the computer is done "playing" you can determine the actions to take in the onPostExecute() method, in your case I think that would be dealing cards.
It would also be really simple to block user inputs while the computer is playing, either with a progress dialog (which isn't all that pleasent for a game I understand) or simply by disabling buttons :)
Here's the documentation for it.
Hope this helps!
I used the solution from #Jakar and changed my variables to class-scope in order to use the Handler and Runnable correctly. This worked, the delay works correctly using
Runnable r = new Runnable() {
public void run() {
playPlayerCard();
}
};
mHandler.postDelayed(r, 500);
To clarify the solution, I had to take out the arguments from playPlayerCard(Player player) and use a class-scope Player mPlayer; variable in playPlayerCard() instead.