I'm working on a tank-game and I have a TextView which represents the shot. Now I want to display the TextView at the specific point and remove it after a second that it looks like the shot goes further step by step. But when I add a countdown or a Thread.sleep the program stops for a second but the TextView doesn't disappear. i want to move the TextView over the screen and after every iteration of my for loop i want to wait a second and then rearrange it again?
Here is the code :
public void shot(float power, float winkel, Button button) {
if(winkel>90) {
winkel = winkel - 10;
}else if(winkel<90){
winkel = winkel +10;
}
for (double i = 0; i<100;i = i+ 1) {
final TextView textView = new TextView(context);
textView.setText(".");
double x = tanks.get(currentTank).getxPos()+(i*power*Math.cos(winkel *(Math.PI/180)));
double y = tanks.get(currentTank).getyPos()+(-1*(i*power*Math.sin(winkel *(Math.PI/180))));
double gravity = (-1*((9.81/2)*Math.pow(i,2)));
y = (y-gravity);
textView.setX((float) x);
textView.setY((float) y);
layout.addView(textView);
for (int j = 0;j<tanks.size();j++){
if(textView.getX()>tanks.get(j).getxPos()&&textView.getX()<tanks.get(j).getxPos()+100){
if(textView.getY()>tanks.get(j).getyPos()&&textView.getY()<tanks.get(j).getyPos()+100){
float k = tanks.get(j).getxPos()-textView.getX();
if(k<0){
k = k*-1;
}
makeDamage(k,tanks.get(j));
}
}
}
new CountDownTimer(2000,1000){
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
layout.removeView(textView);
}
}.start();
}
newTurn();
}
I want to pause the program after adding the TextView for one second and the remove it. The program stops but the TextView doesn't disappear till the for-loop finished. Then all TextViews disappear.
Problem solved:
i've added all positions in a array and then this
public void drawShot(final Button firework, final ArrayList<TextView> toDraw){
final int[] i = {0};
final Handler mHandler = new Handler();
firework.setOnClickListener(new View.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onClick(View v) {
firework(firework,toDraw.get(i[0]).getX(),toDraw.get(i[0]).getY());
}
});
Runnable runnable = new Runnable() {
#Override
public void run() {
layout.addView(toDraw.get(i[0]));
if(!check(toDraw.get(i[0]))) {
mHandler.postDelayed(this, (long) 1);
}
i[0]++;
}
};
// start it with:
mHandler.post(runnable);
}
probably need to run the remove command on main thread
Handler mainHandler = new Handler(context.getMainLooper());
Runnable myRunnable = new Runnable() {
#Override
public void run() {
layout.removeView(textView);
}
};
mainHandler.post(myRunnable);
Related
I am building an obstacles game and i want to show on screen multiple obstacles. The idea of "moving" the obstacles is to set the shapeable image view on and off until it comes to the bottom of the screen. these are all the relevant methods:
on create:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game_screen);
gm = new GameManager();
findViews();
game_FAB_left.setOnClickListener(v -> moveLeft());
game_FAB_right.setOnClickListener(v -> moveRight());
initCharacterPositions();
startTimer();
playBackgroundMusic();
threadPool = Executors.newFixedThreadPool(2);
startTime = System.currentTimeMillis();
}
the timer with a 1 second delay
private Timer timer;
private void startTimer() {
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(()->{
updateTimerUI();
runObstaclesTasks();
});
}
},DELAY,DELAY);
}
the thread pool execution:
private void runObstaclesTasks() {
threadPool.execute(new Runnable() {
#Override
public void run() {
createObstacle();
}
});
}
creating an obstacle and calling the movement function
private void createObstacle() {
Obstacle o = new Obstacle();
int index = getRandomNum(0,NUMBER_OF_POSITIONS);
LinearLayout chosenLayout = (LinearLayout) game_LL_obstaclesLayout.getChildAt(index);
int numberOfObstaclesPosition = gm.getNumberOfObstaclesPosition();
obstacleMovement(o, index, chosenLayout, numberOfObstaclesPosition);
}
the loop that move the obstacle. there is a delay (Thread.sleep) to make the movement effect (visible-invisible):
public void obstacleMovement(Obstacle o, int index, LinearLayout chosenLayout, int numberOfObstaclesPosition) {
for (int i = 0; i < numberOfObstaclesPosition; i++) {
ShapeableImageView obstacleImg = (ShapeableImageView) chosenLayout.getChildAt(o.getPosition());
showObstacle(obstacleImg);
if(gm.isCollision(index, o.getPosition())){
setLifeImages();
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
String msg = "Ouch! " + String.valueOf(gm.getLifeCount()) + " lives left";
toast(msg);
gm.vibrate(v);
}
delay();
hideObstacle(obstacleImg);
o.setNextPosition();
}
}
game demonstration
I am trying to learn coding. So I decided to make a little project but i stuck.
I am trying to make a CountDownTimer. I have 3 different times. For example first one is 10 sec, second one 5 sec and the third one is 7 sec. So I wanna make an app that start the count from 10 sec and when it finish it start the count from second timer and then third one.
public class MainActivity extends AppCompatActivity {
private Button mStartButton;
private Button mResetButton;
private Button mStopButton;
private TextView mTextViewCountDown;
private TextView mTextViewCounter;
private CountDownTimer mCountDownTimer;
private int countme = 0 ;
private int [] array = new int[3];
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mStartButton = findViewById(R.id.button_start);
mStopButton = findViewById(R.id.button_stop);
mResetButton = findViewById(R.id.button_reset);
mTextViewCountDown = findViewById(R.id.text_view_countdown);
mTextViewCounter = findViewById(R.id.text_s);
array[0]=10000;
array[1]=5000;
array[2]=70000;
mStartButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
for(int i = 0; i<3; i++){
mCountDownTimer = new CountDownTimer(array[i], 1000) {
#Override
public void onTick(long millisUntilFinished) {
mTextViewCountDown.setText(""+ millisUntilFinished/1000);
}
#Override
public void onFinish() {
countme++;
if(countme / 3 == 3){
mCountDownTimer.cancel();
}else{
start();
} } }.start();
}
}
}); } }
I don't think for loop is right for my problem. It does not increase variable i once, it increase in every ontick i guess. As a beginner, I couldn't figure out what should I do.
You do not need for loop try something like this:
private void startCountDowntimer(long millis, int count) {
count ++;
int finalCount = count;
new CountDownTimer(millis, 1000) {
#Override
public void onTick(long millisUntilFinished) {
mTextViewCountDown.setText(""+ millisUntilFinished/1000);
}
#Override
public void onFinish() {
if (finalCount == 1) {
startCountDowntimer(5000, 1);
} else if (finalCount == 2) {
startCountDowntimer(7000, 2);
} else {
//all finished
}
}
}.start();
}
and on the button click:
mStartButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startCountDowntimer(10000, 0);
}
});
I am trying to display values inside ArrayList on single line textView one by one after some interval. How to achieve this without blocking the main thread?
I have written code which is able to do this with Thread.sleep but, after a few seconds of running, activity is getting crashed. I have used For Loop & Thread.sleep to iterate every ArrayList value after some interval.
When activity crashes, I am getting IndexOutOfBondException after a few seconds of running.
public void errorRepeater() {
Thread t = new Thread() {
#Override
public void run() {
// !isInterrupted()
while (!isInterrupted()) {
for (xz = 0; xz < errorList.size(); xz++) {
try {
Thread.sleep(2000); //1000ms = 1 sec
runOnUiThread(new Runnable() {
#Override
public void run() {
String sErrorList = errorList.get(xz);
String sErrorListOkBox = errorListOkBox.get(xz);
Log.i("MQTT sErrorList", sErrorList);
TextView tvC1HPLP = findViewById(R.id.errormsg);
tvC1HPLP.setText(sErrorList);
TextView tvok = findViewById(R.id.ok);
tvok.setText(sErrorListOkBox);
rl.setBackgroundResource(R.drawable.errorred);
tvC1HPLP.setTextColor(Color.RED);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
t.start();
}
textView should display values inside ArrayList one by one without crashing activity.
Just for reference, you can try something like this.
// You can define those both textview globally.
TextView tvC1HPLP = findViewById(R.id.errormsg);
TextView tvok = findViewById(R.id.ok);
Handler mHandler = new Handler();
final Runnable runnable = new Runnable() {
int count = 0;
#Override
public void run() {
String sErrorList = errorList.get(count%errorList.size);
String sErrorListOkBox = errorListOkBox.get(count%errorListOkBox.size);
tvC1HPLP.setText(sErrorList);
tvok.setText(sErrorListOkBox);
rl.setBackgroundResource(R.drawable.errorred);
tvC1HPLP.setTextColor(Color.RED);
count++;
mHandler.postDelayed(this, 4000); // four second in ms
}
};
mHandler.postDelayed(runnable, 1000);
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
take = getIntent();
levelone = take.getIntArrayExtra("level1");
take = getIntent();
leveltwo = take.getIntArrayExtra("level2");
take = getIntent();
levelthree = take.getIntArrayExtra("level3");
colors[0] = (R.drawable.blue1);//Suppose to give integer value for the colors
colors[1] = (R.drawable.purple1);
colors[2] = (R.drawable.yellow1);
colors[3] = (R.drawable.green1);
colors1[0] = (R.drawable.blue);//Suppose to set the colors back to origin
colors1[1] = (R.drawable.purple);
colors1[2] = (R.drawable.yellow);
colors1[3] = (R.drawable.green);
purple = findViewById(R.id.purplee); //1
green = findViewById(R.id.greenn);//2
yellow = findViewById(R.id.yelloww);//3
blue = findViewById(R.id.bluee);//4
for (int i = 0; i < btn.length; i++) {
buttons[i] = findViewById(btn[i]);
buttons[i].setOnClickListener(this);
}
/*new CountDownTimer(5000,1000)//5000=5sec to wait and 1000=1sec for interval
{
// loop for timer
#Override
public void onTick(long l) {
Toast.makeText(Main.this, ""+l/1000, Toast.LENGTH_SHORT).show();
}
//what happend after finish 5 sec
#Override
public void onFinish() {
Intent go=new Intent(Main.this,Start.class);
startActivity(go);
}
}.start();*/
new CountDownTimer(2000,500)//5000=5sec to wait and 1000=1sec for interval
{
// loop for timer
#Override
public void onTick(long l) {
buttons[1].setBackgroundResource(colors1[1]);//purple Butttons[1]
buttons[2].setBackgroundResource(colors1[2]);//Yellow Buttons[2]
buttons[3].setBackgroundResource(colors1[3]);//Green Buttons[3]
buttons[0].setBackgroundResource(colors1[0]);//Blue Buttons[0]
}
//what happend after finish 5 sec
#Override
public void onFinish() {
}
}.start();
I want to change the buttons color by delay so I ran a couple of options to do so and none of them worked, I mean I didn't see the delay and the color of the buttons didn't change as it supposed to so how should I do that? In the code, I have tried something but it didn't work so if you have any ideas I will be happy to hear.
You can use a handler
Handler handler = new Handler();
for(int i=0; i<btn.size; i++){
handler.postDelayed(new Runnable() {
#Override
public void run() {
buttons[i].setBackgroundResource(colors1[i]);
}
},1000); // Delay every "1" second
}
//Write This Code Inside onCreate Methode
Timer timer = new Timer();
MyTimer myTimer = new MyTimer();
timer.schedule(myTimer, 1000, 1000);
//Make this Class Outside onCreate Methode
class MyTimer extends TimerTask {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
Random random = new Random();
for (int i = 0; i < btn.size; i++) {
buttons[i].setBackgroundColor(Color.argb(255, random.nextInt(256), random.nextInt(256), random.nextInt(256)));
}
}
});
}
}
My Code should frequently update a number (not only show the result, delay of 100) from a loop in an EditText after you click on a button.
Old Code:
button2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
while (repeat > 0) {
num1 = new Random().nextInt(6)+1;
edit1.setText(String.valueOf(num1));
repeat = repeat - 1;
rep.setText(String.valueOf(repeat));
}
}
});
Now I have this:
final Handler randomHandler = new Handler();
final Runnable randomUpdate = new Runnable() {
#Override
public void run() {
num1 = new Random().nextInt(6) + 1;
edit1.setText(String.valueOf(num1));
repeat--;
rep.setText(String.valueOf(repeat));
randomHandler.postDelayed(this, 1000);
}
};
btnpl5.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
repeat = repeat + 5;
rep.setText(String.valueOf(repeat));
button2.setClickable(true);
button2.setEnabled(true);
}
});
button2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
randomUpdate.run();
button2.setClickable(false);
button2.setEnabled(false);
}
Problem: it won't stop after repeat is 0 (it goes on -1 -2 -3 -4 ..)?
You must always be on the UI thread when calling any method on any
view. If you are doing work on other threads and want to update the
state of a view from that thread, you should use a Handler.
Try this,
handler.postDelayed(new Runnable(){
#Override
public void run() {
num1 = new Random().nextInt(6)+1;
// get previous value and append new generated
edit1.setText(edit1.getText().toString()+String.valueOf(num1));
}
}, (1000)); // run this method in every 1000 milliseconds
This may help you.
You can use an AsyncTask to delay in the background, and publishProgress() to update the UI.
class TextDisplayTask extends AsyncTask<Integer, Integer, Void> {
private int DELAY_MILLIS = 100; // ... set your delay here
#Override
protected Void doInBackground(Integer... params) {
for (int i = 0; i < params[0]; i++) {
int num = new Random().nextInt(6) + 1;
publishProgress(num);
Thread.sleep(DELAY_MILLIS);
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
edit1.setText(String.valueOf(values[0]));
}
}
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
new TextDisplayTask().execute(20); // show a number 20 times
}
});