ACTION_CANCEL generated and lose data - android

I’m working on a 2D game for Android that uses 3 fingers, one/two are on the screen the others are touched and released. Some types of finger usage, some quickly. that is a game where the character walk/run, jump, shot…
My problem is that works fine but sometime is generated the ACTION_CANCEL and I lose the fingers data.
For example, if I press concurrently the 3 fingers I detect on onTouchEvent: ACTION_DOWN, ACTION_POINTER_DOWN (1), ACTION_POINTER_DOWN (2), ACTION_CANCEL.
But also during playing normally, sometime ACTION_CANCEL is generated. Fingers are on the screen but data MotionEvent are all cancelled.. the next touch restart from ACTION_DOWN. So I can't manage the game.
Someone know how to solve my problem? Thanks
I use this (general) code:
public class world extends Activity {
GLSurfaceView glSurfaceView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
this.glSurfaceView = new worldGL(this);
setContentView(this.glSurfaceView);
}
}
class worldGL extends GLSurfaceView {
world activity;
world_r renderer;
public worldGL(Context context){
super(context);
this.activity = (world) context;
this.renderer = new world_r(context);
setRenderer(this.renderer);
//...
}
#Override
public boolean onTouchEvent(MotionEvent e) {
//...
return true;
}
}
public class world_r implements Renderer {
public world_r(Context context) {
//...
}
#Override
public void onSurfaceChanged(GL10 gl, int w, int h) {
//...
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//...
}
#Override
public void onDrawFrame(GL10 gl) {
//...
}
}

Related

Android SurfaceView with drawBitmap(Matrix) leaves blinking ghost image

To preface, I'm probably going to work with Views instead of SurfaceView given this weird interaction, but my curiosity is getting the better of me and I want to know what's going on.
So I have a matrix class variable. I run matrix.setTranslate() once, and every other frame I say matrix.setTranslate(). After this I call canvas.drawBitmap(, matrix, null). After 100 frames, I stop drawing the bitmap.
Here's the code:
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
// matrix = new Matrix(); //Doesn't matter if I add this.
// matrix.reset(); //This doesn't matter either.
if (!once) {
matrix.setTranslate(100, 100);
} else {
matrix.setTranslate(800,800);
}
once = true;
if (++timer < 100) {
canvas.drawBitmap(ball, matrix, null);
}
}
What I expect to happen: Three possibilities.
Only the bottom right bitmap is visible since the entire screen was invalidated
Both bitmaps are visible because SurfaceView was smart with the dirty rectangle
Nothing is shown because nothing was drawn.
What actually happens: The top left bitmap blinks, bottom right bitmap displays solidly.
I'm pretty sure I have all of my bases covered:
All class variables are properly set in the constructor.
SurfaceView.onDraw() is called every 33 millis in its own thread.
Thread calls lockCanvas, then onDraw, then unlockCanvasAndPost
So, what's going on here? And bonus question, do these ghost images consume any extra resources and how can I clear them?
Rest of the code, mostly boilerplate:
public class FullscreenActivity extends Activity {
GameSurface ball;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ball = new GameSurface(this);
setContentView(ball);
}
}
class GameSurface extends SurfaceView implements SurfaceHolder.Callback {
GameThread thread;
boolean once = false;
Bitmap ball;
Matrix matrix;
int timer = 0;
public GameSurface(Context context) {
super(context);
ball = BitmapFactory.decodeResource(getResources(),R.drawable.football);
matrix = new Matrix();
getHolder().addCallback(this);
setFocusable(true);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
// matrix = new Matrix(); //Doesn't matter if I add this.
// matrix.reset(); //This doesn't matter either.
if (!once) {
matrix.setTranslate(100, 100);
} else {
matrix.setTranslate(800,800);
}
//matrix.postRotate(timer); //For even more weirdness...
once = true;
if (++timer < 100) {
canvas.drawBitmap(ball, matrix, null);
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread = new GameThread(getHolder(), this);
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
class GameThread extends Thread {
private SurfaceHolder surfaceHolder;
private GameSurface gameView;
private boolean run = false;
public GameThread(SurfaceHolder surfaceHolder, GameSurface gameView) {
this.surfaceHolder = surfaceHolder;
this.gameView = gameView;
}
public void setRunning(boolean run) {
this.run = run;
}
#Override
public void run() {
Canvas c;
while (run) {
c = null;
try {
Thread.sleep(33);
}
catch(InterruptedException e) {}
try {
c = surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
gameView.onDraw(c);
}
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}

libgdx: main menu doesn't show game class libgdx

I am a newbie in libgdx and I have a little problem with screens and main menu.
I have a mainmenu class and it work with click on actors. The code for click is:
pulsanteplay.addListener(
new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, `float y, int pointer, int button) {
System.out.println("click play");
game.setScreen(new GameClass());
return false;
}
});
and it works. If I call Gdx.app.exit(); it works. If I call the next class, works
public class SplashScreen implements Screen {
private SpriteBatch batch;
private Texture ttrSplash;
private Timer timer;
private MainMenu mainMenuScreen;
public SplashScreen() {
super();
batch = new SpriteBatch();
ttrSplash = new Texture("quadrato.png");
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(ttrSplash, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.end();
}
#Override
public void hide() { }
#Override
public void pause() { }
#Override
public void resume() { }
#Override
public void show() { }
#Override
public void resize(int width, int height) { }
#Override
public void dispose() {
ttrSplash.dispose();
batch.dispose();
}
When I call a class that extends game and have a render method don't work. The screen don't change but the events of the game class are really generated.
Someone could explain me why this? How do I fix this bad behavior?
Thanks for your attention
Have that class that extends Game just implement Screen and put your code in it's corresponding methods. A screen offers everything a Game does so you should have no trouble converting. your onCreate code can be put in the show method or the constructor of your new Screen class. Now just call setScreen() to show this screen.

LIBGDX Camera doesn't move

My game sets this screen and I see the actor that I create.
However can anyone tell me why the camera doesn't seem to be moving? I would expect the actor to move to the right as I pressed the Left key.
The Gdx.input.isKeyPressed(Input.Keys.LEFT) does resolve to true and the translate function does get called.
public class MainScreen implements Screen {
private Stage mainStage;
private Camera orthCamera;
#Override
public void show() {
orthCamera = new OrthographicCamera();
mainStage = new Stage(new ScreenViewport());
mainStage.getViewport().setCamera(orthCamera);
MyGameActorObject s = new MyGameActorObject();
s.setPosition(100, 100);
mainStage.addActor(s);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0,0,0,1); //sets clear
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
processKeyboardInput();
mainStage.act(delta);
mainStage.draw();
}
private void processKeyboardInput()
{
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
orthCamera.translate(-30, 0, 0);
orthCamera.update();
}
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
mainStage.dispose();
}
}
I am trying to acheieve being able to pan around the 2d game world using keyboard input.
This is the contents of the custom Actor object:
public class MyGameActorObject extends Actor
{
#Override
public void act(float delta) {
super.act(delta);
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
ShapeRenderer r = new ShapeRenderer();
r.begin(ShapeRenderer.ShapeType.Filled);
r.setColor(Color.RED);
r.circle(this.getX() - 50.0f, this.getY() - 50.0f, 100.0f);
r.end();
}
}
I believe I have to add something like
r.setProjectionMatrix(batch.getProjectionMatrix());
in my custom actor object. So the draw function on my object would now be.
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
ShapeRenderer r = new ShapeRenderer();
r.setProjectionMatrix(batch.getProjectionMatrix());
r.begin(ShapeRenderer.ShapeType.Filled);
r.setColor(Color.RED);
r.circle(this.getX() - 50.0f, this.getY() - 50.0f, 100.0f);
r.end();
}
I think your problem is that you haven't set the InputProcessor.
Gdx.input.setInputProcessor(...) is the method you're looking for. Put it in your show() method and pass it an InputProcessor reference. InputProcessor is an interface that goes through all the different types of click-based input and allows you to determine what happens in them. So for instance:
#Override
public boolean keyDown(int keycode)
{
switch(keycode)
{
case Keys.D:
screen.universe.entity_handler.player.moving_right = true;
break;
case Keys.A:
screen.universe.entity_handler.player.moving_left = true;
break;
case Keys.SPACE:
screen.universe.entity_handler.player.jumping = true;
break;
...
}
...
}
The above code is part of an InputProcessor-implementing class for a game I'm making. When the input in-question is pressed (keyDown in this case), the game looks at your input button (the keycode) and sends it through the switch statement.
Keep in mind that you must return true for all the input events that you want to use. That's what the boolean return value for this method is.

Libgdx time lag and delta value issue ( used with Spine to run Skeleton animation)

I am using the Libgdx framework along with Spine to do Skeleton animation using Atlas and exported Json file. In the file there are many animations. I am able to load animations from the json file. But there are 2 issues :
Lag when animation starts : there is a lag of 3-4 seconds before the animation starts. I see a black screen and then the animation works.
Delta - i have some issues with the delta time. Only some animations are running from the default delta value, however if i change ( increment or decrease the delta value), different animations give different results.
Cant understand what to do ? I have searched thoroughly in the internet but haven't found the solution.
I am posting my code below:
This is my Main Class
public class AndroidLauncher extends AndroidApplication
{
SpriteBatch batch;
Texture img;
ShapeRenderer renderer;
TextureAtlas atlas;
Skeleton skeleton;
Animation animation;
float time;
Bone root;
float x,y;
View spine_view;
private Screen curScreen; // the current screen
#Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
//initialize(new Main(20), config);
spine_view=initializeForView(new ApplicationListener()
{
#Override
public void resume()
{
curScreen.resume();
}
#Override
public void resize(int width, int height)
{
}
#Override
public void render()
{
curScreen.render((Gdx.graphics.getDeltaTime()/(1.5f))); //call the rendermethod with the delta time as parameter
}
#Override
public void pause()
{
curScreen.pause();
}
#Override
public void dispose()
{
curScreen.dispose();
}
#Override
public void create()
{
Gdx.graphics.getWidth();
Gdx.graphics.getHeight();
Firstscreen temp = new Firstscreen();//just an example of the first screen to load up
setScreen(temp);
}
}, config);
LinearLayout l1 = (LinearLayout) findViewById(R.id.container);
l1.addView(spine_view);
}
public void setScreen(Screen s) {
if (curScreen != null) {
curScreen.hide();
curScreen.dispose();
}
curScreen = s;
curScreen.show();
}
}
...............................................
And this is the screen Iam rendering
public class Firstscreen implements Screen
{
SpriteBatch batch;
Texture img;
ShapeRenderer renderer;
TextureAtlas atlas;
Skeleton skeleton;
Animation animation;
float time;
Bone root;
float x,y;
int count =0;
#Override
public void render(float delta)
{
// track
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
time += delta;
animation.apply(skeleton,delta,time, false, null);
SkeletonRenderer render = new SkeletonRenderer();
batch.begin();
render.draw(batch, skeleton);
skeleton.updateWorldTransform();
batch.end();
}
#Override
public void resize(int width, int height)
{
}
#Override
public void show()
{
batch = new SpriteBatch();
renderer = new ShapeRenderer();
atlas = new TextureAtlas(Gdx.files.internal("abc.atlas"));
SkeletonJson json = new SkeletonJson(atlas);
// set the scale of skeleton
json.setScale(0.3f);
SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("skeleton.json"));
skeleton = new Skeleton(skeletonData);
skeleton.setToSetupPose();
skeleton.setSkin("Carla");
// set the position of the skeleton to render( here middle)
skeleton.setPosition((Gdx.graphics.getWidth()/2)-(x/2),( Gdx.graphics.getHeight()/2)-(y/2));
//animation = skeletonData.findAnimation("KID-LEVEL 2 - Couch potato");
animation = skeletonData.findAnimation("LEVEL 91- Around a world");
//animation = skeletonData.findAnimation("KID-LEVEL 7 - Super Hero");
}
#Override
public void hide()
{
}
#Override
public void pause()
{
}
#Override
public void resume()
{
}
#Override
public void dispose()
{
batch.dispose();
}
}
That's happens beacuse you are managing a timeline manually.
Use AnimationState instead:
Skeleton skeleton = new Skeleton(skeletonData);
// sctruct for mix animations
AnimationStateData stateData = new AnimationStateData(skeletonData);
// and state
AnimationState state = new AnimationState(stateData);
In some update method (or render, if you prefer update while rendering) call something like this:
state.update(delta);
And in the actual render method:
// apply the state to skeleton
state.apply(skeleton);
// update transformations
skeleton.updateWorldTransform();
// draw then
render.draw(batch, skeleton);
So, AnimationState isn't designed not for managing the delta only, you can play&mix animations using it:
state.setAnimation(0, "LEVEL 91- Around a world", isLoop);
To change animation speed use setTimeScale:
state.setTimeScale(0.5f); // set any time scale you want
Also, you may have some perfomance issues because you calling new SkeletonRenderer() in render method. To fix that, move this code to constructor.

Custom SurfaceView with thread crashes App when Activity is exited

I just made an Activity which uses at "setContentView" a view from a class which extends SurfaceView. The problem is:
It works fine, but when I exit it (BACK key) it crashes. Code:
package ro.etrandafir.mate.appCreator;
import android.app.Activity;
import android.os.Bundle;
import android.content.Context;
import android.view.View;
import android.view.SurfaceView;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.graphics.Color;
import android.graphics.Paint;
public class Sample2 extends Activity implements View.OnTouchListener {
float x = 0, y = 0;
SampleTwoView theView;
public boolean onTouch(View v, MotionEvent event) {
// TODO: Implement this method
x = event.getX();
y = event.getY();
return true;
}
#Override
protected void onPause() {
super.onPause();
finish();
}
#Override
protected void onCreate(Bundle b) {
super.onCreate(b);
theView = new SampleTwoView(this);
theView.setOnTouchListener(this);
setContentView(theView);
}
public class SampleTwoView extends SurfaceView implements Runnable {
Paint p = new Paint();
public SampleTwoView(Context context) {
super(context);
p.setColor(Color.RED);
Thread theThread = new Thread(this);
theThread.start();
}
public void run() {
while (true) {
if (!getHolder().getSurface().isValid()) continue;
Canvas canvas;
canvas = getHolder().lockCanvas();
canvas.drawColor(Color.BLUE);
if ((x != 0) && (y != 0)) canvas.drawCircle(x, y, 40, p);
getHolder().unlockCanvasAndPost(canvas);
}
}
}
}
What can I do? Should I add onDestroy or what?
Thanks in advance,
Matei
The issue you are getting is related to this code:
Canvas canvas;
canvas = getHolder().lockCanvas();
canvas.drawColor(Color.BLUE);
When your activity ends, your thread is still running, but your custom SurfaceView is no longer available, so you will get a null ptr exception. Your existing code can easily be patched by adding a boolean that gets set to false as soon as the onPause fn gets called:
public void run() {
while (booleanThatGetsSetToFalseWhenActivityPauses) {
if (!getHolder().getSurface().isValid()) continue;
Canvas canvas;
canvas = getHolder().lockCanvas();
canvas.drawColor(Color.BLUE);
if ((x != 0) && (y != 0)) canvas.drawCircle(x, y, 40, p);
getHolder().unlockCanvasAndPost(canvas);
}
}
However, I would suggest altering the structure of your application as a whole. This may just be for practice, but I think a more efficient and bug free way of accomplishing your goal would be to simply use a standard SurfaceView and to completely decouple your drawing logic from any custom view.
My redesigned activity is below, but it utilizes a Ball class that is used to maintain the ball's logic, which, in your current code is separately coupled with both the actvity (the coordinates) and the view (the Paint). In this new ball class, a ball has a location (specified by a PointF), a Paint, and a diameter. It also has methods to get most of these variables in addition to setting some.
public class Ball {
private Paint mPaint;
private PointF mCoordinates;
private int mDiameter;
public Ball (int color, int diameter) {
mPaint = new Paint();
mPaint.setColor(color);
mCoordinates = new PointF();
mCoordinates.x = 0;
mCoordinates.y = 0;
mDiameter = diameter;
}
public void setCoordinates (float x, float y) {
mCoordinates.x = x;
mCoordinates.y = y;
}
public PointF getCoordinates() {
return mCoordinates;
}
public Paint getPaint() {
return mPaint;
}
public int getDiameter() {
return mDiameter;
}
/* You did not want to draw the uninitialized ball, so this method checks that */
public boolean hasNonZeroLocation () {
return (mCoordinates.x != 0 && mCoordinates.y != 0);
}
}
I use the Ball class in the activity as shown below. Notice that the redrawing to the canvas now only occurs when a user touches the canvas as opposed to an infinite while loop. This is due to the utilization of the Handler class which posts actions to run to the UI thread. Additionally, now we do not need a custom view, and our ball's logic has been decoupled from the activity and the view.
public class RedBallActivity extends Activity {
Handler mDrawingHandler;
SurfaceView mDrawingSurfaceView;
Ball mBall;
private final Runnable drawRedBallOnBlueSurface = new Runnable() {
#Override
public void run() {
if (!mDrawingSurfaceView.getHolder().getSurface().isValid()) return;
Canvas canvas = mDrawingSurfaceView.getHolder().lockCanvas();
canvas.drawColor(Color.BLUE);
if (mBall.hasNonZeroLocation())
canvas.drawCircle(mBall.getCoordinates().x, mBall.getCoordinates().y, mBall.getDiameter(), mBall.getPaint());
mDrawingSurfaceView.getHolder().unlockCanvasAndPost(canvas);
}
};
private final OnTouchListener mCanvasTouchListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
mBall.setCoordinates(event.getX(), event.getY());
mDrawingHandler.post(drawRedBallOnBlueSurface);
return true;
}
};
#Override
protected void onCreate(Bundle b) {
super.onCreate(b);
mDrawingSurfaceView = new SurfaceView(this);
mDrawingSurfaceView.setOnTouchListener(mCanvasTouchListener);
setContentView(mDrawingSurfaceView);
mBall = new Ball(Color.RED, 40);
mDrawingHandler = new Handler();
}
}
Now, if you actually run this code you will notice that initially the screen is not drawn with a blue background. You might be tempted to simply call mDrawingHandler.post(drawRedBallOnBlueSurface); at the end of the onCreate method, but it is not guaranteed that the SurfaceView will be ready to be drawn upon (see the documentation on this lockCanvas method). If you want the surface to initially be blue, you need to implement a [SurfaceHolder.Callback][2], which needs to be connected to the SurfaceView's SurfaceHolder, and on the surfaceCreated method being called, we know the surface is ready, so we can then call mDrawingHandler.post(drawRedBallOnBlueSurface);
Now, with this added, I change the Activity to implement [SurfaceHolder.Callback][2] as follows:
public class FriendManagerActivity extends Activity implements SurfaceHolder.Callback {
and add this line to the constructor:
mDrawingSurfaceView.getHolder().addCallback(this);
and implement the interface:
#Override
public void surfaceCreated(SurfaceHolder holder) {
mDrawingHandler.post(drawRedBallOnBlueSurface);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
Feel free to ask any questions on my little redesign! While your problem could be easily patched, I felt like the way you were coupling logic with Views was a little bit flawed, and thought a little more info on SurfaceView coding would be helpful.
As someone mentioned it in the above, when your activity ends, your thread is still running, but your custom SurfaceView is no longer available, so you will get a Null Point Exception. Your existing code can easily be patched by adding a boolean that gets set to false as soon as the onPause fn gets called:I had the same problem. To solve it I added the following onPause() to your SampleTwoView class:
// pause method will destroy the Thread
public void pause() {
isRunning = false;
while (true) {
try {
myThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
myThread = null;
}
Then call this onPause() method in your onPause() method of your Sample2 class as follows:
#Override
protected void onPause() {
super.onPause();
SampleTwoView.onPause();
finish();
}
So everytime the onPause() method of your main Activity class is called the Thread will be destroyed.
I hope this will help you.
Cheers!

Categories

Resources