0

Let's say that I have a motion event, that when I hold a key my cannon shoots balls. Everything is okay but I needed to create a while() loop for this inside this event, cause balls were lagging.

The point is here I can't escape this event. The while loop is infinite and I can't listen for ACTION_UP. Is there any way to stop this on ACTION_UP while being in this loop?

EDIT: part of the code:

@Override
public void surfaceCreated(SurfaceHolder holder) {

    game = new Game(holder, resources);
    game.start();
    shootingThread = new Thread(new Runnable() {
        @Override
        public void run(){
            while(running) {
                int size = game.gameLoop.balls.size();
                    if (size == 0) {
                        game.gameLoop.balls.add(new Ball(metrics.widthPixels, metrics.heightPixels, touched_x, touched_y, game.gameLoop.ball_bmp_width, metrics.heightPixels - game.gameLoop.ball_bmp_width / 2));
                    } else if (size > 0 && game.gameLoop.balls.get(size - 1).image_center_y < metrics.heightPixels - game.gameLoop.ball_bmp_width - 50)
                        game.gameLoop.balls.add(new Ball(metrics.widthPixels, metrics.heightPixels, touched_x, touched_y, game.gameLoop.ball_bmp_width, metrics.heightPixels - game.gameLoop.ball_bmp_width / 2));
                }
            // }
        }
    });
    shootingThread.start();

}

@Override
public boolean onTouchEvent(MotionEvent event) {
    // TODO Auto-generated method stub

    touched_x = event.getX();
    touched_y = event.getY();

    int action = event.getAction();
    if (action == MotionEvent.ACTION_DOWN) {
        startShootTime = new Date().getTime();
        running = true;
        shootingThread.run();
        Log.i("", "\n\ndown\n\n");

    } else if (action == MotionEvent.ACTION_MOVE ) {
        touched_x = event.getX();
       touched_y = event.getY();


    } else if (action == MotionEvent.ACTION_UP) {

        Log.i("", "\n\nup\n\n");
        running = false;
    }

    return true;
}

1 Answers1

0

The onTouchEvent method fires events as they come in and should not be blocked. If you want to continuously trigger an action while the user's fingers are down then once you get the ACTION_DOWN event you should kick off a thread (or async task or timer or any other form of action on another thread) which should then add the balls to your game loop. Then in your main thread you'll need to determine if there were changes on the UI and invalidate/draw your updated views.

However, ACTION_MOVE will get fired a lot while the user has their finger down. So you'll have to determine for yourself whether that is fast enough or if you need to move that logic to another thread.

Note that onTouchEvent will fire as fast as you can consume it, so if you run into performance problems it is actually ok to put a small sleep here. You can see documentation of that recommendation here

BoredAndroidDeveloper
  • 1,251
  • 1
  • 11
  • 26
  • I've tried that, but when I implement a new Thread and put this while there is laggs (and I don't know why). Could you tell me how it should be done? Maybe I was just starting it wrong or something. –  Sep 14 '15 at 12:14
  • Are you using a game engine of some sort or a standard activity? I can provide some guidance but if you're experiencing lag then you should profile your code and determine where delays are coming from. – BoredAndroidDeveloper Sep 14 '15 at 13:57
  • Now I have created a new Thread and it should work but I can't change volatile 'running' variable. It just gets stuck in a loop inside run() method (system doesn't see MotionEvent down/up when im in the run()) Maybe I did something wrong O.o I've edited the code in my first post, could you look? And yes, I have two (now three separate threads) for drawing game loop etc. –  Sep 14 '15 at 14:53
  • Just fyi - next time append the code edit as now my answer has no relation to your new question. For this new edit I'm a bit nervous as to the fact of the lack of thread synchronization so you'll want to google that. In addition, once you start the thread and it finishes then the thread is dead. So to make what you have work you would want to do something like creating/starting the thread in the onTouchEvent. The problem with that is that it'll create a ton of garbage collection. Did you profile your code? – BoredAndroidDeveloper Sep 14 '15 at 19:09
  • Honestly I think you could get by with your earlier code by just adding 1 ball on ACTION_MOVE and then ignoring an ACTION_MOVE if it happens within x seconds. That event gets fired a TON when you have your finger down so it would create a ton of balls. – BoredAndroidDeveloper Sep 14 '15 at 19:10
  • But I have an if statement - won't throw a ball when previous is near :) –  Sep 15 '15 at 12:51
  • You have "running = true;" inside of the onTouch but you start the thread in surfaceCreated(). So if it's false before then the thread will just stop when you start it the first time before the user touches the screen. You should never call Thread.run as that just calls the runnable's run method and it'll never exit so you'll be in the same situation that you were before. Look at my second comment, If you want to use this approach you need to create and start the thread when the user touches the screen Although I don't recommend this as creating a thread is not cheap. Also multitouch bugs here – BoredAndroidDeveloper Sep 15 '15 at 17:48