Below is a peice of code where on click the player will make their move by placing the X counter and then the computer will make their move by placing a O counter. The
only issue with this code currently is that when the player places their X counter, the O counter is placed as well at the same time. So it looks like both the player
and the computer has made their moves at the same time and that happens everytime the player makes their move.
What I want to ask, is it possible to include like a 2 second time delay so that the player will place their X and then after 2 seconds the computer will place their O?
Thanks in advance
#Override
public void onClick(View v) {
if (!((Button) v).getText().toString().equals("")) {
return;
}
if (playerOneMove) {
((Button) v).setText("X");
((Button) v).setTextColor(playerX);
computerMove();
}
}
private void computerMove() {
String[][] field = new String[3][3];
Random random = new Random(); //you may want to declare this as a class field
List<Button> emptyButtons = new ArrayList<>();
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
field[i][j] = buttons[i][j].getText().toString();
if (field[i][j].equals("")) {
emptyButtons.add(buttons[i][j]);
}
}
}
Button selectButton;
for (int i = 0; i < 3; i++) {
if (field[i][0].equals(field[i][1])
&& field[i][2].equals("")){
//prevent win/win on rows by selecting the correct button here
}
else if (field[i][0].equals(field[i][2])
&& field[i][1].equals("")){
//prevent win/win on rows by selecting the correct button here
}
else if (field[i][1].equals(field[i][2])
&& field[i][0].equals("")){
//prevent win/win on rows by selecting the correct button here
}
else {
selectButton = emptyButtons.get(random.nextInt(emptyButtons.size()));
}
selectButton.setText("O");
selectButton.setTextColor(playerO);
}
You could put computer logic inside handler or timer task: How to call a method after a delay in Android
but you also need some flag, that will block user placing X while you are waiting for computer to make it move.
i edited your onclick with the delay and i think you gonna need some sort of the flag wich blocks user until computer makes the move !
#Override
public void onClick(View v) {
if (!((Button) v).getText().toString().equals("")) {
return;
}
if (playerOneMove) {
((Button) v).setText("X");
((Button) v).setTextColor(playerX);
//2000 is your delay in mills format
v.postDelayed(new Runnable() {
#Override
public void run() {
computerMove();
}
},2000)
}
}
and i think it would be good idea to use some random number between 1sec to 3sec for delay and not the constant delay it creates better experience for user
You can check out the Handler and Runnable class in android. You can delayed the time of a method as required.
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 100ms
}
}, 100);
Related
I'm creating a TicTacToe game and currently, after someone wins, I have a postDelayed function that triggers after 5 milliseconds. During these 500 milliseconds, I can draw the winning character as well as display the winning animation. I was wondering if it was possible to make the user wait a mandatory 500 milliseconds and then tap to continue after the delay. Is this possible?
private void player1Wins() {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
buttons[i][j].setEnabled(false);
}
}
player1Points++;
textViewPlayer1.setText(Integer.toString(player1Points));
Toast.makeText(this, "Player 1 has won", Toast.LENGTH_SHORT).show();
final Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
resetBoard();
}
};
handler.postDelayed(r, 500);
winAnimation(winCondition);
}
'Yeah you can do it. You can hide the button from xml in its properties like.'
android:visibility="gone";
'in your postDelayed Function after 5 miliseconds you can show this button to user like'
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
button.setVisibility(view.VISIBLE);
}
},500);
'and set it's click listener whatever you want'.
'Hope you get the solution.'
So I want to check if nodes are in certain range and if so, draw them or not.
The nodes are checked inside a timer, so a thread is created. Only issue right now is that method setRenderable() have to be called from UI thread. So is there a way to bypass that ? I need this to update in certain interval that's why I create timer.
public void updateNodes()
{
Camera camera = arFragment.getArSceneView().getScene().getCamera();
timer = new Timer();
timer.schedule(new TimerTask(){
int last = 0;
int copy_last = 0;
#Override
public void run(){
Vector3 camera_position = camera.getWorldPosition();
// We're checking all nodes for distance between them
for(Node al : copied_nodes_list){
if(last<copy_last) last++;
else if(countDistanceOfNodes(al,camera_position)<3.0 && copy_last >= last) {
al.setRenderable(andyRenderable);
last++;
copy_last = last;
}
else {
al.setRenderable(andyRenderable);
}
}
last = 0;
}
},0,250);
}
Create a variable in your class.
Set the value when the object is initialized or write a setter against that variable.
Within the run function, check against the condition against that variable and write the business rules accordingly.
Okay, so there's function in android called runOnUiThread(); Which basically doing whats it's called. I attach the working code.
public void updateNodes()
{
Camera camera = arFragment.getArSceneView().getScene().getCamera();
Timer timer = new Timer();
timer.schedule(new TimerTask(){
int last = 0;
int copy_last = 0;
#Override
public void run(){
Vector3 camera_position = camera.getWorldPosition();
// We're checking all nodes for distance between them
for(Node al : copied_nodes_list){
camera_position = camera.getWorldPosition();
if(last<copy_last) last++;
else if(countDistanceOfNodes(al,camera_position)<3.0 && copy_last >= last) {
runOnUiThread(new Runnable(){
#Override
public void run(){
al.setRenderable(andyRenderable);
}
});
last++;
copy_last = last;
}
else {
runOnUiThread(new Runnable(){
#Override
public void run(){
al.setRenderable(null);
}
});
}
}
last = 0;
}
},0,100);
}
How can I make an android app that generates a random word every 1 second?
Here is my code:
new Timer().scheduleAtFixedRate(new TimerTask(){
public void run()
{
started = true;
word = "";
for (int i = 0; i < lenght+1; i++)
{
int j = rand.nextInt((max-min) + 1) + min;
word += tr.Translate(j);
}
txt.setText(word);
}
}, 0, 5000);
It seems that my app stops every time it must change the text of the TextView("txt"); how can I make this work?
Undoubtfully, run this within a Thread. Doing this, it will generate the words in background and once it already has, the main UI thread must just append the content to the txt instance.
new Thread(
new Runnable() {
public void run() {
// your stuff
}
}
).start()
To assign the result to the txt object, you'll probably be unable to do it within this thread. To do so, you'll need to declare a Handler in your Activity and use that handler within your thread, so it uses sendMessage() to the main Activity and the Activity just sets the text.
More on this here and here.
---- EDIT ----
As #FD_ says, there is another way to do the update without the use of a Handler. You would just need to call the runOnUiThread() method, something like this:
runOnUiThread(new Runnable() {
public void run() {
txt.setText(your_new_text);
}
});
Another way is using an AsyncTask, which is (talking vaguely) an "evolution" of a thread which makes a lot of stuff for you. More on AsyncTasks here.
---- EDIT ----
This would be one of the ways:
new Thread(
new Runnable() {
public void run() {
new Timer().scheduleAtFixedRate(new TimerTask() {
public void run() {
started = true;
word = "";
for (int i = 0; i < lenght+1; i++)
{
int j = rand.nextInt((max-min) + 1) + min;
word += tr.Translate(j);
}
// This will update your txt instance without the need of a Handler
runOnUiThread(new Runnable() {
public void run() {
txt.setText(word);
}
});
}
}, 0, 5000);
}
}).start();
try this:
int i = 0;
public void changeString() {
started = true;
word = "";
int j = rand.nextInt((max - min) + 1) + min;
word += tr.Translate(j);
txt.setText(word);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (i < lenght + 1) {
changeString();
i++;
}
}
}, 1000);
}
You can do this using timer as well
int i=0;
new Timer().scheduleAtFixedRate(new TimerTask(){
public void run()
{
started = true;
word = "";
int j = rand.nextInt((max-min) + 1) + min;
word += tr.Translate(j);
txt.setText(word);
i++
}
}, 0, 5000);
try the above. The mistake you were making is using a for loop inside run instead use loop run method it-self.
I am working a schoolproject where we are making a bomberman game. There are 2 bombermans on the playfield, the User and the AI.
When the user places a bomb and walks off it, the bomb flashes and explodes when it's time is over.
However this doesn't works with the AI.
When the AI places a bomb and walks off it and when it supposed to flash and then explode the app crashes by leaving this error:
FATAL EXCEPTION: Timer-0
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
The CountDownTimer code is the following.
public void explodeAIBomb(){
//Starts countdown 2-4 seconds
new CountDownTimer(new Random().nextInt(2000) + 2000, 300) {
//test for onTick; bomb flashes
boolean test = false;
public void onFinish() {
//on explosion{
gameBoard[locateAIX][locateAIY] = new Blast();
explosionSide(locateAIX, locateAIY);
explosionVert(locateAIX, locateAIY);
updateView();
//Clear all blasts after 1 second
new CountDownTimer(1000, 1000){
public void onFinish(){
for (int x = 0; x < XasLength + 1; x++) {
for (int y = 0; y < YasLength + 1; y++) {
if(gameBoard[x][y] != null){
if(gameBoard[x][y].getTileId() == BLAST || gameBoard[x][y].getTileId() == BLAST_SIDE || gameBoard[x][y].getTileId() == BLAST_VERT){
gameBoard[x][y] = null;
}
}
}
}
aiBombPlanted = false;
updateView();
}
#Override
public void onTick(long millisUntilFinished) {
}
}.start();
updateView();
}
//Flashes the bomb every 0.3 second
public void onTick(long millisUntilFinished) {
if(test){
loadTile(BOMB, r.getDrawable(R.drawable.bomb));
test = false;
}
else{
loadTile(BOMB, r.getDrawable(R.drawable.bomb2));
test = true;
}
updateView();
}
}.start();
}
Somewhere you are doing UI work from a worker thread. You need to call stuff dealing with the UI from within the main thread.
I think same question has been answered before.
stackoverflow.com/questions/6354740/how-is-countdowntimer-accessing-ui-inside-ontick-method
I'm trying to use threads to run a lenghty operation in the background and update the UI.
Here's what i'm trying to do:
on a button click, display a popupjframe with a message "Inserting into DB"
create a new thread to insert 1000s of entries into a database.
when the entries are inserted, i want the popupjframe to disappear and display a joptionpane with yes, no buttons
on clicking the yes button i want to display another frame with a report/details about the insertion process
Here's my code:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
//display popupframe first
jFrame1.pack();
jFrame1.setVisible(true);
jFrame1.setLocationRelativeTo(getFrame());
Thread queryThread = new Thread() {
public void run() {
runQueries();
}};
queryThread.start();
}
//runqueries method inserts into DB
private void runQueries() {
for (int i = 0; i <= 50000; i++) {
insertintoDB();
updateProgress(i);
}
}
//update the popupjframe
private void updateProgress(final int queryNo) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (queryNo == 50000) { //means insertion is done
jFrame1.setVisible(false);
int n = JOptionPane.showConfirmDialog(getFrame(), menuBar, null, JOptionPane.YES_NO_OPTION);
if (n == 1) { //NO option was selected
return;}
else
//display another popupframe with details/report of inserting process
}});
}
Is my approach correct??
How and when do i stop/interrupt the "queryThread"??
Is it correct if i make the popupjframe in the runqueries method itself (after the for loop) and display the joptionpane??
Thanks in advance.
Look at the documentation for SwingWorker. It does exactly what you are trying to do. Create a subclass, and call runQueries from doInBackground(), and then do what your runnable does (minus the if queryNo check) in done(). There are third party versions of this class if you are not using java 1.6.
class DbSwingWorker extends SwingWorker<Void, Integer> {
#Override
protected Void doInBackground() throws Exception {
for (int i = 0; i <= 50000; i++) {
insertintoDB();
publish(i); //if you want to do some sort of progress update
}
return null;
}
#Override
protected void done() {
int n = JOptionPane.showConfirmDialog(getFrame(), menuBar, null, JOptionPane.YES_NO_OPTION);
if (n == 1) { //NO option was selected
return;
} else {
//display another popupframe with details/report of inserting process
}
}
}
The original, non-1.6 version can be found here: https://swingworker.dev.java.net/