I'm trying to work up a basic text-based game as I'm learning Java. I'd like to be able to count rounds in the game as a means of managing the pacing of certain events. For instance, changing rooms could be limited to once per round (a second, in the test code.) A small creature might attack or change rooms at a higher rate, whereas a larger one might be more cumbersome. Good so far? Great.
So, I cooked this up and immediately realized that I'd be hitting a block each time the while loop waited for the player to input a command. Code:
private void startPlaying() {
//declare clock/round variables.
int lastRound = 0;
int currentRound = 0;
long lastTime = System.currentTimeMillis();
long currentTime;
while (player.getIsPlaying()){
//Clocking
currentTime = System.currentTimeMillis();
if ((lastTime + 1000) < currentTime) {
lastTime = currentTime;
lastRound = currentRound;
currentRound++;
System.out.println("Current round:\t" + currentRound + "\tCurrent time:\t" + currentTime); //EDIT:NOTE: This is just a test line to observe the loop.
}//end if (Clocking)
Command command = new Command();
String[] commandString = command.setAll(); //Array gets parsed elsewhere.
player.doCommand(commandString);
//Class Player extends Pawn extends Actor; Pawn has most command methods.
}
finishPlaying();
}//END STARTPLAYING()
So, here is my question:
Is there a way I could use a separate method to log time/rounds concurrent to the while loop presenting the player with a command prompt?
If not, is there a different way to make this a non-issue that I'm just not seeing/practiced in yet?
Take a look at Concurrency tutorial. With threads you can wait user input without stopping other processes (and make these other processes execute at the same time - not in parallel, but time-sharing).
It is called "game loop" which allows the game to run smoothly regardless of the input of the user.
The most straightforward solution - create 2 threads, frist will wait for user input and puts it into ConcurrentLinkedQueue with capacity 1. The second thread will run your game loop and takes user input from queue to process it if queue is not empty.
You can use any data structure you want to exchange data between 2 threads, it can be even volatile string variable. The only requirements read write access to this variable should be synchronized somehow.
A real-time text adventure? Sounds interesting. I wouldn't suggest trying to do concurrency for this particular problem, there are easier ways.
Normally you wouldn't mix blocking on input with time in seconds. Unless you have your heart set on this design, I'd suggest either.
1) Don't block on user input. Write your own input handling code by checking for key-presses each frame. Then you can just calculate the time difference between iterations. E.g. a monster moves 1 block second, so if the current loop iteration took 100ms then it moves 0.1 blocks. (store these values as floats internally, even if you draw on a text grid.
2) Increment game time in 'ticks' based on user input. This would be NetHack/Roguelike-style. Monsters can move so many blocks per tick, rather than per second.
Yes there is a way. You would need to put the "Round Counting" code in its own Thread, so it in not blocked by the user waiting to input data. The java.util.concurrency package can help with this.
Look at Java Doc the scheduleAtFixedRate() method will execute a runnable at fixed intervals. The "round counting" code would be moved to a class that implements the runnable interface. And this would be executed at the set time interval. This is reasonably advanced though.
Related
Iam new here, like week ago I started learning to program and Iam working on my text based strategic game in which I would like to make resources gather every x seconds passively.
basicaly my game is based on while (true) loop in which are switch cases and the game keeps waiting for keys to press to gather resources.
I would like the game to gather resources passively every x seconds.
example : every 10 seconds you will receive +1 wood.
I will welcome in help :)
Iam programming in java using NetBeansIDE
Just get the current time in every loop run with this
and check whether the 10 seconds passed since last time you gave +1 wood.
Note the time unit.
I am not sure how you are storing gathered resources, but if you could call a method to look it up based on when the game began. You could store the following variable as part of your game class:
private long startTime = System.currentTimeMillis();
And then get current resources by using the following method:
public int getWood() {
long diffMilliseconds = System.currentTimeMillis() - startTime;
int numSeconds = (int)diffMilliseconds / 1000;
int amtWood = numSeconds/10;
return amtWood + <any other wood gathering/calculating parameters>;
}
This does not account for using your wood. If you want a variable to update every ten seconds, you could use something like the solution here: Print "hello world" every X seconds. This solution uses the TimeTask class. Rather than printing, you could update a amtWood variable.
If there are no restrictions on what classes you can use, try Timer class available as part of Java Swing. You can also look at java.util.Timer class for scheduling your updates.
I have program that uses 4 input .txt files. When program is started, certain data manipulation is done, data is grabbed from those 4 files, and program creates 2 output .txt files at the end. Program execution time at that time is about 18 seconds. I would like to know what would be fastest way to write this programs in terms of program execution? This is how program is written now:
First, I started to read and write data sequentially, so my program logic is based on 2 parts - One loop (for reading necessary data and file creation) is used for first output file, and another loop (also for reading necessary data and file creation for that fole) is used for second output file. Second method needed to wait to first method to be done, with this approach. My total time of execution was at this point about 18 seconds.
Then, I involved theads - I used 2 threadsm (one thread running it's loop) so every loop would be running in separate thread. With that approach, I cut total time of execution to about 9 seconds.
Now; I started to ask If I could be speeding up total time of execution even more?
My code for the first thread looks like this (and the code for other thread is basically more or less similar):
Thread thread1 = new Thread() {
public void run() {
final List<Articles> article_list = ac.getFileValues("resources/articles.txt");
String file_contents = "";
String file1_data = "";
for (int i = 0; i < article_list.size(); i++) {
double price_art_local_val = cc.getPrice("resources/pricelist.txt", article_list.get(i).sifra);
double[] art_all_shops = sc.getAmountInAllStores("resources/supply.txt", article_list.get(i).sifra);
double total_value_art_all_shops_local = price_art_local_val * art_all_shops[0];
double total_value_art_all_shops_foregin = total_value_art_all_shops_local / exchange_rate;
file_contents = article_list.get(i).sifra+"\t"+article_list.get(i).naziv+"\t"+df.format(price_art_local_val)+"\t"+df.format(art_all_shops[0])+"\t"+article_list.get(i).jedinica_mjere+"\t"+df.format(total_value_art_all_shops_local)+"\t"+df.format(total_value_art_all_shops_foregin)+"\t"+df.format(art_all_shops[1])+"\n";
System.out.print(file_contents);
file1_data += file_contents;
}
if(file1_data != "")
{
save.saveFile("results/supply_value_articles.txt", file1_data);
}
}
};
The place I see further execution time reduction in my opinion is on methods cc.getPrice and sc.getAmountInAllStores() in that piece of code. My view is that It would be good to achieve that they run in separate threads, so other method would not have to wait execution of first method. Am I on good track?
So I presume that if I want to speed up execution in for loop I would need to make execution of methods cc.getPrice() and sc.getAmountInAllStores() also in separate threads. If that is not right solution, I would like to know what to do.
Then, if this is right solution, how can I achieve that? I do not know how to properly write code to use another thread, if that code is already in run() method. Can it be done even, I am not sure? Also, that methods return certain values, and they need to be stored in variables. So I would need also to get data for that metods stored; meaning threads would return data for me. I do not know how to done that properly. Seems like this won't help me then to basically write this (if I create one thread for method cc.getPrice, and another thread for method sc.getAmountInAllStores and name them thread3 and thread4):
thread3.join();
thread4.join();
I would need piece of code showing the appropriate solution.
If I am not on the right track, and this can't be done (starting and using new threads inside running thread), please instruct me what to do. I have read some stackowerflow questions about BlockingQuene, but I think my approach brings something else that I need.
Please help with examples of code If you can. Thank you very much, help appreciated.
So, I am fairly new to java and android programming and I am having an issue coming up with the code for a project I am working on. Basically, there is a list of times, which I assume need to be stored as an array. Once the game has started, it needs to do one of two things:
If the user presses the screen within a few milliseconds of a time in the array, it will register as a hit and increase count.
If the user presses the screen outside of the "hit" time, it will register as a miss and reset count to 0.
Now, I have all the elements in place to make everything work (increasing count on screen press, etc). My issue is with the code to detect if the user pressed the screen on time or not. I have tried doing some searches, but I can't figure it out. Here is a small list of the times that are "good" hits:
0.25
0.84
1.03
1.60
2.3
2.6
2.9
These times can change a little and some can be removed if its not working correctly. The biggest issue I can think of is making sure that it starts the timer when the game starts so the times match up. The current timer starts at 100 and counts down 1 second at a time and when it reaches zero it takes the user to the game over screen. This of course can change if there is a better way to do it or a different way that it has to happen to make the screen press detection code work.
Any idea how to make this work?
Really, all you need to do is log the current system time at the time the game starts. Then, it's just:
long startTime = System.currentTimeMillis();
//...
System.currentTimeMillis() - startTime;
Then, to check if you're within the bounds set at any point in the array (which I will assume is an array of doubles):
public final static int THRESHOLD_MSEC = 100;
public boolean isHit(double time) {
int time = System.currentTimeMillis - startTime;
for(double d : array)
if(Math.abs(d-time) < THRESHOLD_MSEC) return true;
return false;
}
Then, elsewhere in your application, you can handle what happens when isHit returns either true or false. I'm not going to write that part for you. A point of note: a few milliseconds is nothing in comparison to human reflexes, and nobody will be able to make that time.
as an excercise I'm trying to create a metronome with Java using Thread.sleep as a timer and JMF for sounds. It's working out quite well but for some reason JMF seems to be only playing sounds at a maximum of 207 beats per minute.
From my Metronome-class:
public void play() {
soundPlayer.play();
waitPulse();
play();
}
From my SoundPlayer-class:
public void play() {
new Thread(new ThreadPlayer()).start();
}
private class ThreadPlayer implements Runnable {
public void run() {
System.out.println("Click");
player.setMediaTime(new Time(0));
player.start();
}
}
I've made SoundPlayer.play() work as a thread to test if it would make a difference, but it's not. I can easily change tempos up to about 207bpm but even if I set my timer to 1000bpm the sounds aren't played any faster than about 207bpm.
I've put the System.out.println("Click"); inside my ThreadPlayer.run() to check if my loop is working correctly – it is.
The issue seems to be with my implementation of JMF. I'm pretty sure there is a simple solution, can anybody help me out?
Thank you so much for your help! :)
The answer about Thread.sleep() being unreliable is correct: you can't count on it to return in exactly the amount of time you specify. In fact, I'm rather surprised your metronome is usable at all, especially when your system is under load. Read the docs for Thread.sleep() for more details. Max Beikirch's answer about MIDI is a good suggestion: MIDI handles timing very well.
But you ask how to do this with audio. The trick is to open an audio stream and fill it with silence between the metronome clicks and insert the metronome clicks where you want. When you do that, your soundcard plays back the samples (whether they contain a click or silence) at a constant rate. The key here is to keep the audio stream open and never close it. The clock, then, is the audio hardware, not your system clock -- a subtle but important distinction.
So, let's say you are generating 16 bit mono samples at 44100 Hz. Here is a function that will create a click sound at the requested rate. Keep in mind that this click sound is bad for speakers (and your ears) so if you actually use it, play it at a low volume. (Also, this code is untested -- it's just to demonstrate the concept)
int interval = 44100; // 1 beat per second, by default
int count = 0;
void setBPM( float bpm ) {
interval = ( bpm / 60 ) * 44100 ;
}
void generateMetronomeSamples( short[] s ) {
for( int i=0; i<s.length; ++i ) {
s = 0;
++count;
if( count == 0 ) {
s = Short.MAX_VALUE;
}
if( count == interval ) {
count = 0;
}
}
}
Once you set the tempo with setBPM, you can play back the samples generated by calling the the generateMetronomeSamples() function repeatedly, and streaming that output to your speakers using JavaSound. (see JSResources.org for a good tutorial)
Once you have that working, you could replace the harsh click with a sound you get from a WAV or AIFF or a short tone or whatever.
Take your time and take a look at MIDI! - http://www.ibm.com/developerworks/library/it/it-0801art38/ or http://docs.oracle.com/javase/tutorial/sound/TOC.html . It's the best solution for everything related to computer made sound.
My assumption would be, and maybe someone else can jump in here, is that thread running times are up to the whims of the thread scheduler. You can't guaranty how long it will take for the JVM to get back to that thread. Also, seeing as the JVM is running as a process on the machine, and is subject to the OS's process scheduler, you are looking at at least two levels of unpredictability.
Just like Jamie Duby said, just because you tell the Thread to sleep 1 millisecond, doesn't mean that it will get called back at exactly one millisecond. The ONLY guarantee is that AT LEAST one millisecond has passed since you called Thread.sleep();. In reality, the processor cannot process the code fast enough to play a beep sound every millisecond, which is why you see the delay. If you want a dramatic example, make a home-made timer class and try making it count one millisecond for a full minute, you will see that the timer is off by quite a bit.
The person who really deserves the answer credit here is Max Beikrich, Midi is the only way you are going to be able to produce the output you are looking for.
I have far more experience as a musician than a programmer but I just finished a metronome application I started a while back, I had put the project on hold for a while because I couldn't figure out why I was having the same problem you are. Yes Thread.sleep() can be unreliable but I'm managed to make a good metronome using that method.
I saw you mentioned trying an ExecutorService I don't think using concurrent classes will solve your problem. My guess is its a system resource issue, I'm pretty certain MIDIs are the way to go with a metronome. I force my students to practice with a metronome and I've used many, I haven't ever been too concerned with the audio quality of the ticks, timing is far more important and MIDIs are going to be much faster than any other audio file. I used the javax.sound.midi library from the Sound API. I suspect that will solve your problem.
You may notice your ticks are uneven when it works properly, this is due to the Thread.sleep() method not being very reliable. How I solved that problem was by doing all my calculations in nanoseconds using the System.nanoTime() method instead of the System.currentTimeMillis() method, just don't forget to convert back to milliseconds before passing the sleep time into the Thread.sleep() method.
I don't want to post the code for my metronome here in case you want to figure it out on your own but if you'd like to see it just send me an e-mail kevin.bigler3#gmail.com and I'd be happy to send it to you. Good luck.
I'm writing an AI-testing Framework for a competition. Participants submit a Bot class which matches a given Interface. Then all the bots play a turn-based game. On every turn, I want to do the following:
For every bot B:
start a thread that runs at most N cycles and does B.getNextMove()
wait for all threads to complete
Make all moves (from each bot).
My difficulty comes in saying "at most N cycles". I can limit all the bots by time (say half a second per turn) but this means that some can get more processor cycles than others and doesn't permit a strict "your bot should be able to make its decision re: a turn in X time" requirement in the competition.
As stated, this is in Java. Any ideas? I've been looking at concurrency and locking but this doesn't feel like the right direction. Also, it's possible to not run the bots in Parralel and then use time for the restriction (given that the computer isn't running anything else at the time), but this would be undesirable as it would significantly slow down the speed at which we could have results from the games.
I'd make an interface with the bot to have them do 1 iteration of their algorithm,and do a simple count.
If you need hard time/cpu limits there arn't that many(easy) ways to manage that in java.
You can't measure cpu cycles with java, but you can measure CPU time - which is a vast improvement over using just wall clock time.
To get the cpu time of the current thread you'd use (from the standard java.lang.management package)
ThreadMXBean tm = ManagementFactory.getThreadMXBean();
long cpuTime = tm.getCurrentThreadCpuTime();
Since you're controlling the bot execution and explicitly calling next yourself, why not just count the iterations? e.g.
public class Botcaller extends Thread
{
private Bot bot;
int cycles_completed;
public static final int MAX_ALLOWED_CYCLES=...;
public void run()
{
while (cycles_completed <MAX_ALLOWED_CYCLES)
{
bot.move;
cycles_completed++;
yield()
}
}
}
I think it will be very difficult to control threads at this low a level from Java. I no of know way to stop a thread safely that is running.
Another option is to let each bot run in whatever time it wants. Have one thread per bot but poll the location in a master thread every second. If they haven't updated location in that "round" then they miss out and have to wait for the next one. Make sure that the world state that each bot sees is the one controlled by the master thread.
The nice thing about this approach is that it lets bots sacrifice rounds if they want to do something more complicated.
I think Robocode does something similar... you may want to look there.