2D game on Android SurfaceView runs slowly on touch - android

I am building a 2D game with Android SurfaceView. When I touch the screen the game animation runs slowly. Why, and how can I avoid this?
The touch events are stubs just like onTouchEvents(MotionEvents ev){ empty };. All of the game logic and graphics draw code are in run() in an extends Thread class.

Sleeping the UI thread for 16-20ms will keep the touch event handling code from being called too many times per second.
Example:
#Override
public boolean onTouchEvent(MotionEvent event) {
//Event handling logic
try {
Thread.sleep(16);
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
Touch events are dispatched as quickly as the UI thread can read them, by sleeping the thread you are able to skip a number of event dispatches. (Though not a noticeable amount for your game logic or the user)

Have you looked at the tutorials at http://www.droidnova.com ? They are good intro game tuts and ran very quickly when I did them. If they run slowly on your device with touch it is probably not a dev issue

#Override
public void run ( )
{
while(irunning)
{
while(paused)
{
sleep(2);
synchronized ( holder )
{
canvas = holder.lockCanvas(null);
//updateEvents();
//updatePsgstate();
//updateRole();
sortImages();
drawBgland();
drawImages();
drawAdminicle();
holder.unlockCanvasAndPost(canvas);
}
}
sleep(10);
}
}
#Override
public boolean dispatchTouchEvent ( MotionEvent ev )
{
try
{
Thread.sleep( 32 );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
synchronized ( ev )
{
Log.i( "T" , "onTouch" );
}
return true;
}
#Override
public void surfaceCreated(SurfaceHolder holder)
{
mThread.start();
// if (hasFocus())
// {
// return;
// }
// else
// {
// requestFocusFromTouch();
// }
}
this is base method that i used.
that's my code. any problem about it ?

Related

(View.INVISIBLE) before Timer.sleep() not working

I have several buttons I want to make INVISIBLE for a short while then make them VISIBLE again. The (View.INVISIBLE) before Timer.sleep() does not work. I have yet to figure this out. Any ideas?
Thanks, Steve
private void commonBtnHandler(Button btn) {
try {
btn.setVisibility(View.INVISIBLE);
Thread.sleep(250);
btn.setVisibility(View.VISIBLE);
} catch (Exception e) {
e.printStackTrace();
}
}
You should not do Thread.sleep() on the UI/main thread. It will cause the UI to freeze & ANR
Try :
btn.setVisibility(View.INVISIBLE);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
btn.setVisibility(View.VISIBLE);
}
}, 250);
Also 250 ms is a very small amount of time.
btn.setVisibility(View.INVISIBLE);
new Thread() {
public void run() {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setVisibility(View.VISIBLE);
}
});
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
always put the runOnUiThread when need to change the UI in runtime, This is helps to you.
Thanks for all the input.
I tried all the suggestions with a 3000 millisecond delay but still did not see a blink.
Also, I was wondering if I was blocking the UI thread. I thought the INVISIBLE would complete before the sleep() took effect.
Summary: I wrote a loop to make the call 10 times. The delay seems to be ignored in all cases. I appreciate everyone’s help. It looks like I need to rethink how this should work. I wouldn’t think this would be much different than how a game programmer would insure synchronous operations.
Addressing this issue in another way I did not INVISIBLE the button but temporarily changed the color using MotionEvent within a setOnTouchListener. When pressed the button changes color and when released reverts back to the original color. Works great!
mBtn.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch ( event.getAction() ) {
case MotionEvent.ACTION_DOWN:
mBtn.setBackgroundColor(getResources().getColor(R.color.colorLightOrange));
break;
case MotionEvent.ACTION_UP:
mBtn.setBackgroundColor(getResources().getColor(R.color.colorOrange));
break;
}
return true;
}
});

execute sleep() onTouchEvent or Control frame rate in surfaceview (android )

Please check this link. Following code is from this link. I am not sure why it says we have to use thread sleep to limit number of touch events.
I have a surfaceview and gamethread which processes events pushed by touch event. Is this sleep required or should I handle the sleep in gamethread instead by controlling framerate.
try {
Thread.sleep(16);
} catch (InterruptedException e) {
}
return true;
}
whole code
#Override
public boolean onTouchEvent(MotionEvent event) {
// we only care about down actions in this game.
try {
// history first
int hist = event.getHistorySize();
if (hist > 0) {
// add from oldest to newest
for (int i = 0; i < hist; i++) {
InputObject input = inputObjectPool.take();
input.useEventHistory(event, i);
gameThread.feedInput(input);
}
}
// current last
InputObject input = inputObjectPool.take();
input.useEvent(event);
gameThread.feedInput(input);
} catch (InterruptedException e) {
}
// don't allow more than 60 motion events per second
try {
Thread.sleep(16);
} catch (InterruptedException e) {
}
return true;
}
Your link points to an article that has been posted in 2009, you should really try to find one that is more up to date.
The code itself looks wrong, the author explains that his code is designed to avoid blocking the UI thread but then calls Thread.sleep(16) in onTouchEvent() which is called from the UI thread and blocks it.
What about this example? I haven't read it in detail, but the code looks much better : https://www.codeproject.com/Articles/827608/Android-Basic-Game-Loop

Ontouch functionality

I am making an app where when you hold a button, a textview with numbers increases (until you let go).
I tried using the OnTouch, but that doesn't increase the number unless you move your finger in the button. I tried looking at some answered questions here in stackoverflow and implementing the solutions suggested, but it seems to just crash now...
The ontouch listener:
upb.setOnTouchListener(new View.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
/* Button pressed */
if(event.getAction() == MotionEvent.ACTION_DOWN){
startIncreasing();
}
if(event.getAction() == MotionEvent.ACTION_UP){
stopIncreasing();
}
return true;
}
private void startIncreasing(){
setIsIncreasing(true);
new Thread(new Runnable() {
public void run() {
while(isIncreasing()){
if(speed<12){ //max speed determined here
speed++;
speedtext.setText(speed + " km/h");
downb.setEnabled(true);
homeb.setEnabled(false);
revb.setEnabled(false);
//send signal to speed up
}
else {
speedtext.setText("MAX " + speed + " km/h");
upb.setEnabled(false);
}
}
}
}).start();
}
});
Later on in the code:
synchronized private void stopIncreasing(){
setIsIncreasing(false);
}
synchronized private boolean isIncreasing(){
return continueIncreasing;
}
synchronized void setIsIncreasing(boolean newSetting){
continueIncreasing = newSetting;
}
Anybody that can spot what I am doing wrong? Or should I do this in a completely different way?
Thank you for your help
Without seeing logs, I believe your app crashes since you're updating the TextView from a background thread (in speedtext.setText(speed + " km/h");).
Updating UI elements must be done from the UI thread (main).
You can use the runOnUiThread() method for doing such updates from the UI thread.

Android - two actions in app at the same time

I am developing app and I need that my app will be doing two actions at the same time. For example - I can drag marker and the map will be scrolling at the same time.
I tried to update map while dragging marker, everything would be okay, except thing that when thread starts, maps starts scrolling continuously and I cand do anything more. Here is the code, I call it in onCreate() method. I tried to do Runnable and AsyncTask and the results were the same. Any suggestions?
private void update() {
new Thread() {
public void run() {
while (true) {
runOnUiThread(new Runnable() {
#Override
public void run() {
while (drag)
mMap.animateCamera(CameraUpdateFactory.scrollBy(10, 0), 2, null);
}
});
try {
Thread.sleep(2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
}
You don't have the code to interrupt your thread. That's why your map keep scrolling. Try to use drag event to drive this animation, and add some code to terminate the thread at some point.

Android : game loop pause/resume issue

I am able to pause/resume my game by making my game thread(which holds/synchronized with surfaceview) wait/notifyAll. This all runs well using the in game pause button.
However, when I click home/back button I am able to pause my game, but when I resumes my game by clicking on its icon, I receive non responsive game screen back to me.
I have put logs on OnResume() method but nothing gets printed in LogCat!
If I click on my game screen I get error dialog to "Force Close" or "Wait" on my game activity.
Why I am getting this non responsive screen as if my application Hangged after pause ?
How can I handle physical buttons in same way as inGame pause/resume button ?
here is my logcat view of the operation. you can see onResume sop not getting printed similar to onPause.
EDIT : Code called by my pause/resume button and by onPause/onResume functions
where "this" is thread class itself
protected void setPause(){
synchronized (this) {
isPaused = true;
}
}
protected void setResume(){
synchronized (this) {
isPaused = false;
this.notifyAll();
}
}
Game Loop Code :
synchronized (this) {
while (running) {
if (isPaused) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
Canvas c = null;
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
view.onDraw(c);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS
- (System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
This how I am calling it from surface view :
public void surfaceCreated(SurfaceHolder holder) {
// start the game loop
System.out.println("Starting Game Loop #########");
if(isPaused){
System.out.println("GamePaused");
gameLoopThread.setResume();
}
else{
System.out.println("Game Starting");
gameLoopThread.setRunning(true);
}
gameLoopThread.start();
}
EDIT 2:
If I Pause my game using pause button and let my phone get locked automatically... after resuming I am able to play normally with out any issue.
As per logs I see surface destroyed is not getting called in this case.
After onResume, your SurfaceView is created again, but it lost all the data it had before (all info needed for onDraw). you have to save the data in surfaceDestroyed or before, and reload it in the onCreate of your surfaceview

Categories

Resources