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
Related
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);
}
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);
i have an object that implements runnable. This object is my gameview, where the world of the game is processed.
Gameview is owned by another class: Game. Game is handling the UI for the gameView, so it is running on the ui-thread.
When the user touches something it is caught by the UI-thread. This is because if the user touches perhaps a skill-icon i need to pass data about what skill it was to the gameView.
My issue is that quite get:
java.util.ConcurrentModificationException
at java.util.Vector$Itr.checkForComodification(Vector.java:1193)
at java.util.Vector$Itr.next(Vector.java:1145)
at com.example.benjamin.dungeondweller.RenderSystem.render(RenderSystem.java:55)
at com.example.benjamin.dungeondweller.GameView.run(GameView.java:90)
at java.lang.Thread.run(Thread.java:764)
When touching the screen. I suspect it is because the method in GameView is still running on the UI thread, not the thread in the gameview.
To clarify here is the method in game (that is running on the UI-thread):
Where the third argument in gameView.touch would be the skill id (currently set to -1)
#Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
gameView.touch(x,y, -1);
break;
}
return true;
}
gamview.Touch:
public void touch(int screenX, int screenY, int skillId) {
int worldX = renderSystem.screenToWorldX(screenX);
int worldY = renderSystem.screenToWorldY(screenY);
renderSystem.clear();
if (map[worldX][worldY] != 1) {
ArrayList<Point> route = calculateRoute(new Point(0,0), new Point(worldX,worldY));
for (Point p : route) {
renderSystem.addSprite(R.drawable.guy, p.x, p.y);
}
}
(Currently only removing every sprite on the screen and adds new sprites)
When the crash occurs, the log refers to the run method in gameView:
#Override
public void run() {
while (running) {
if (!surfaceHolder.getSurface().isValid()) {
continue;
}
long startTime = System.currentTimeMillis();
int frameSkipped = 0;
//update();
Canvas canvas = surfaceHolder.lockCanvas();
if (canvas != null) {
canvas.drawARGB(255,65,65,65);
renderSystem.render(canvas); <---------- CRASH HERE
surfaceHolder.unlockCanvasAndPost(canvas);
}
long updateTime = System.currentTimeMillis() - startTime;
int sleepTime = (int)(FRAME_PERIOD - updateTime);
if (sleepTime > 0) {
try {
Message msg = new Message();
msg.obj = MAX_FPS;
msg.what = UPDATE_FPS;
handler.dispatchMessage(msg);
Thread.sleep(sleepTime);
} catch (InterruptedException e) {}
}
while (sleepTime < 0 && frameSkipped < MAX_FRAME_SKIPS) {
Message msg = new Message();
msg.obj = 1000 / updateTime;
msg.what = UPDATE_FPS;
handler.dispatchMessage(msg);
// update();
sleepTime+=FRAME_PERIOD;
frameSkipped++;
}
}
}
I think the issue is that the run method and touch method in GameView is running on different threads but i cant say for certain. How do i make it so that gameView.touch is running on the same thread as gameView.run?
Edit: formated code.
Edit: So to clarify further, i have one thread that's iterating the vector and one that tries to remove items in it. How do i make it so that the thread that removes items in the vector runs on the same thread as the one that iterates over it?
public void counter(){
new CountDownTimer(20000, 1000){
#Override
public void onTick(long millisUntilFinished) {
progressBar.setProgress(Integer.parseInt(String.valueOf(millisUntilFinished/1000)));
}
#Override
public void onFinish() {
gameOver();
}
}.start();
}
I am trying to write a game in which player gets 20 seconds to play. A timer starts at start of the game and if timer reaches 0, player looses. If player presses button with correct answer, i want time to increase by 3 seconds. But I don't know how to add time in the count down timer whenever player hits correct answer. I tried everything but couldn't find a way. If there is another method to achieve this, please tell me. Thank you
Change your code like this:
private int globalCount = 0; // Initialize this in Global scope of class.
public void counter(int timeCount){
globalCount = 0;
new CountDownTimer(timeCount, 1000){
#Override
public void onTick(long millisUntilFinished) {
progressBar.setProgress(Integer.parseInt(String.valueOf(millisUntilFinished/1000)));
}
#Override
public void onFinish() {
if (globalCount == 0) {
gameOver();
} else {
conter(globalCount);
}
}
}.start();
}
One last thing you have to do is:
globalCount += 3000;
every time when user pressed the right answer button. Hope this will help!
In Android normal countdown timer is used for decrease order. so you can use logic using normal if-else condition.
if (sec==59){
sec = 0;
min = min+1;
String text = String.format(Locale.getDefault(),"%02d min: %02d sec",min,sec);
editText.setText(text);
}else {
sec = sec+1;
String text = String.format(Locale.getDefault(),"%02d min: %02d sec",min,sec);
editText.setText(text);
}
}
You can get complete code using this blog
I write some timer. and I want to display it in textview after start button is clicked.
What I did.
Every time I
timer = new Thread(new Runnable() {
#Override
public void run() {
while (!stopedButton ) {
time = "";
if (timerMinutes >= 60) {
timerMinutes = 0;
timerHours++;
}
if (timerHours < 10)
time = "0" + String.valueOf(timerHours) + ":";
else
time = String.valueOf(timerHours) + ":";
if (timerMinutes < 10)
time += "0" + String.valueOf(timerMinutes);
else
time += String.valueOf(timerMinutes);
runOnUiThread(new Runnable() {
public void run() {
if (!stopedButton) {
mTimeFromStartValue.setText(time);
timerMinutes++;
} else {
timerMinutes = 0;
timerHours = 0;
}
}
});
Log.e(TAG, ""+timerHours);
Log.e(TAG, ""+timerMinutes);
Log.e(TAG, time);
try {
Thread.sleep(1 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
so it works fine, but every time after stop and then start and after doing it many times my timer starts working fast. I try to avoid that kind of situation and I thought that i don't need to create new timer every time. But I need to have working timer after stop start too.
I wrote some code like this:
if(timer.isAlive()){
timer.resume();
}else{
timer.start();
}
But I have got this exception: java.lang.IllegalThreadStateException: Thread already started
so how to solve this ?
You need to create new Thread instance to start new thread. Also You need do use interrupt() method of Thread class.
Use this code to finish Your thread:
#Override
public void run() {
while (true) {
// Your code here
if(isInterrupted ()){
return;
}
}
}
Use this code when stop button was clicked:
timer.interrupt();
timer.join();