I'm creating some little sprites with a bmp inside the constructor of another view as background. But when I click the sprites, that have their onClickListener, the view I'm clicking is the background view.
Some code:
My constructor:
public ToposGameView(Context context) {
super(context);
moles = new ArrayList<MoleSprite>();
setFocusable(true);
setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.i(tag, "Click en GameView");
}
});
gameLoopThread = new GameLoopThread(this);
int id = 0;
for(int x = 0; x<3; x++){
for(int y = 0; y<4 ; y++){
MoleSprite mole = new MoleSprite(this, x*WIDTH/3, HEIGHT/6+y*HEIGHT/6, FRONT);
mole.setId(id);
id++;
moles.add(mole);
}
}
holder = getHolder();
holder.addCallback(new Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
boolean retry=true;
gameLoopThread.setRunning(false);
while(retry){
try{
gameLoopThread.join();
retry=false;
}catch(InterruptedException i){
}
}
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
});
}
Sprite's constructor:
public MoleSprite(ToposGameView gameView, int x, int y, int direction) {
super(gameView.getContext()); //TODO
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.bad1);
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight() / BMP_ROWS;
this.x=x;
this.y= y;
this.setClickable(true);
this.setFocusable(true);
this.setFocusableInTouchMode(true);
setOnClickListener(this);
setOnTouchListener(this);
//I don't know what else to do!
}
It's my first question, please ask me for more info.
Edit1:
public class MoleSprite extends View implements OnClickListener, OnTouchListener{
public class ToposGameView extends SurfaceView{
Your mixing Surface drawing with View drawing. Surfaces are great for rapid asynchronous redraws (such as games), but they are not View containers. That is, there is no addView method on SurfaceView that is required for events and layouts.
As such, you will need to implement onClick handling on your SurfaceView and manually implement the detection of which Sprite is being clicked (e.g., is the click event within the sprite's x/y/width/height bounding box).
Also, it doesn't make sense for MoleSprite to extend View if used this way. I expect you'll want to make your own Sprite base class to support the bounding boxes and drawing callbacks. You can also add the onClick(..) interface to the Spirte base class, but you'll probably also want to keep separate lists for drawable/moveable/clickable items to optimize your list iterations as you develop your game.
Good luck!
i don't know what your GameLoopThread is doing, but it should be calling your surface's onDraw method, and updatePhysics method.
the update physics will loop through your sprites and give them information, like the current game time, so they can move the proper distance, change the animation frame, or whatever.
for a sprite base class I use something like this (but mine handles animations, accelerations and other stuff):
public class Sprite {
private Rect mScreenRect;
public Sprite() {
// init some stuff here, if you need it
// especially, somewhere in your init functions
// set your bounding rect
this.mScreenRect = Rect(xl, yt, xr, yb);
}
setStuff(int thing) {
// like setX(), setY()
}
// here is the good stuff
public boolean isTouched(int x, int y) {
if(mScreenRect.contains(x, y))
return true;
else
return false;
}
// also include a function to draw the graphic
public void drawGraphic(Canvas canvas) {
canvas.drawBitmap(mBitmap, mScreenRect.left, mScreenRect.top, null);
}
}
then, in your surface view you need to use the:
#Override
public boolean onTouchEvent(MotionEvent event) {
// this setup will move the sprite on the screen
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(sprite.isTouched(event.getX(), event.getY()) {
// do your stuff
}
break;
case MotionEvent.ACTION_MOVE:
// handle the moving pointer
sprite.setCoords(event.getX(), event.getY());
break;
case MotionEvent.ACTION_UP:
// handle the exiting pointer
sprite.setCoords(event.getX(), event.getY());
break;
}
}
then in the surface view again:
#Override
public void onDraw(Canvas canvas) {
sprite.drawGraphic(canvas)
}
there are other posts that cover this in a more detailed manner, but this will get you started.
Related
This is my code.
On swipe to the top is performed:
for(int it = 0;it<4;it++){
myBoard.step_up();
invalidate();
}
int ad = myBoard.merge_up();
invalidate();
for(int it = 0;it<4;it++){
myBoard.step_up();
invalidate();
}
step_up and merge_up methods change the values of myBoard. The onDraw method draws the screen according to the myBoard values. But i do not see intermediate results of movements! Just start postition and then end position, the same as in the following code:
for(int it = 0;it<4;it++){
myBoard.step_up();
}
int ad = myBoard.merge_up();
for(int it = 0;it<4;it++){
myBoard.step_up();
}
invalidate();
How to deal this problem? It is very important for me
Update:
The code from onCreate:
GraphicsView myview=new GraphicsView(this);
setContentView(myview);
GraphicsView entire code is too big. The part of it:
public GraphicsView(Context context) { super(context);
this.setOnTouchListener(new OnSwipeTouchListener(getApplicationContext()) {
public void onSwipeTop() {
//above code
}
//other methods
}
protected void onDraw(Canvas canvas)
{
//draw
}
}
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!
I am experimenting with drawing on a canvas using a thread to create a simple game engine but I'm having some weird issues I cannot explain.
The purpose of this "game" is to draw a circle every second on the canvas.
This works, but not the way I want it to work, it seems the app is switching between two canvasses and adding a circle to each canvas so you get a switch between two canvasses every second with the same number of circles but in a different place on the canvas.
I don't know what I'm doing wrong, but I'm not that familiar with Treadding, has it something to do with how many cores my android device has or something like that?
My code is shown below, so I just use a launchthread which uses a layoutfile that links to the animationthread which starts a thread and draws a circle on the canvas every second.
(You can ignore the touchevent, it isn't uses yet).
The project exists out of a main launchthread:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
which uses this layout file:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.androidtesting.AnimationView
android:id="#+id/aview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</FrameLayout>
And my Surfaceview class with an inner Thread class:
class AnimationView extends SurfaceView implements SurfaceHolder.Callback {
private boolean touched = false;
private float touched_x, touched_y = 0;
private Paint paint;
private Canvas c;
private Random random;
private AnimationThread thread;
public AnimationView(Context context, AttributeSet attrs) {
super(context, attrs);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
thread = new AnimationThread(holder);
}
class AnimationThread extends Thread {
private boolean mRun;
private SurfaceHolder mSurfaceHolder;
public AnimationThread(SurfaceHolder surfaceHolder) {
mSurfaceHolder = surfaceHolder;
paint = new Paint();
paint.setARGB(255,255,255,255);
paint.setTextSize(32);
}
#Override
public void run() {
while (mRun) {
c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
doDraw(c);
sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
private void doDraw(Canvas canvas) {
//clear the canvas
//canvas.drawColor(Color.BLACK);
random = new Random();
int w = canvas.getWidth();
int h = canvas.getHeight();
int x = random.nextInt(w-50);
int y = random.nextInt(h-50);
int r = random.nextInt(255);
int g = random.nextInt(255);
int b = random.nextInt(255);
int size = 20;
canvas.drawCircle(x,y,size,paint);
canvas.restore();
}
public void setRunning(boolean b) {
mRun = b;
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public boolean onTouchEvent(MotionEvent event) {
touched_x = event.getX();
touched_y = event.getY();
int action = event.getAction();
switch(action){
case MotionEvent.ACTION_DOWN:
touched = true;
break;
case MotionEvent.ACTION_MOVE:
touched = true;
break;
default:
touched = false;
break;
}
return true;
}
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
thread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
}
it seems the app is switching between two canvasses
Yes, this is how it works. It is called double buffering and you need to redraw all the frame each time:
The content of the Surface is never preserved between unlockCanvas() and lockCanvas(), for this reason, every pixel within the Surface area must be written.
So you need this line canvas.drawColor(Color.BLACK) to be uncommented in your code.
And you shouldn't call Thread.sleep(1000) while canvas is locked, it will cause starvation issue.
It sounds like you have this working, but I did just notice a small error that I should point out.
You called canvas.restore() without calling canvas.save() beforehand.
From the Android developer reference for Canvas: "It is an error to call restore() more times than save() was called."
I don't see any reason for you to call canvas.save() in your case, therefore you should remove the call to canvas.restore().
Well, I'll try to explain exactly what I pretend:
I want to draw a bitmap in a canvas in random positions according to the coordinates of the screen on touch, and I want a message(text) to be displayed everytime the user touches the screen.
So, if a draw the text in the same thread than I do for the bitmap, it will appear and dissapear right after, and I want it to stay in the screen for a few seconds and the dissapear. My first idea was to use Thread.sleep(), but for that I have to create a thread only for the text, or I will mess with the Bitmap too.
I've been trying to use multithreading in the same canvas, but I don't know how. Can someone please explain to me...
That's some of the code i've got so far:
private void init() {
// CREATE SURFACEHOLDER AND ADD THIS CLASS AS HIS CALLBACK
enemyHolder = getHolder();
enemyHolder.addCallback(this);
scoreHolder = getHolder();
scoreHolder.addCallback(this);
hasSurface = false;
}
public void resume() {
if (surfaceViewThread == null) {
surfaceViewThread = new SurfaceViewThread(); // CREATE A NEW
// THREAD
if (hasSurface)
surfaceViewThread.start(); // START OUR THREAD
}
if (secondThread == null) {
secondThread = new SecondThread();
if (hasSurface)
secondThread.start();
}
}
public void surfaceCreated(SurfaceHolder holder) {
hasSurface = true;
if (surfaceViewThread != null)
surfaceViewThread.start();
if (scoreShow == 1) {
if (secondThread != null)
secondThread.start();
}
}
// THREAD
private final class SurfaceViewThread extends Thread {
private boolean done;
SurfaceViewThread() {
super();
done = false;
}
#Override
public void run() {
// TODO Auto-generated method stub
super.run();
SurfaceHolder surfaceHolder = enemyHolder;
while (!done) {
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(enemy1, enemy1X, enemy1Y, null); // DRAW
// FIRST
// ENEMY
// SECOND THREAD
private final class SecondThread extends Thread {
private boolean done;
SecondThread() {
super();
done = false;
}
#Override
public void run() {
// TODO Auto-generated method stub
super.run();
SurfaceHolder surfaceHolder = scoreHolder;
while (!done) {
Canvas canvas = surfaceHolder.lockCanvas();
Paint paint = new Paint();
paint.setColor(Color.BLACK);
canvas.drawText("xD", 50, 50, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
scoreShow = 0;
}
}
Do you need to use a SurfaceView? It seems like a hard work way of doing things.
I've just done something similar by creating a custom view class and overriding the onDraw method. Then use canvas.save() and canvas.restore(). Here's the relevant bits of my onDraw.
#Override
public void onDraw(Canvas canvas) {
canvas.save();
// scale the canvas
canvas.scale(scaleFactor, scaleFactor); //, mid.x, mid.y);
// and translate...
canvas.translate(translateX / scaleFactor, translateY / scaleFactor);
super.onDraw(canvas);
// draw the lights
for(Light light:lights){
if (light.isOn){
canvas.drawCircle(light.getX(),light.getY(), light.getDiameter() / scaleFactor,light.paint);
}
}
canvas.restore();
}
The lights are turned on and off by a separate thread back in the activity which has inflated the view. They stay on screen as long as they are on.
Cheers
Here's some incomplete pseudo code to do what you've described. There are plenty of good examples around for each of these elements to help you fill in the blanks.
public class MyCustomView extends View {
int touchPointX;
int touchPointY;
private String mText;
public MyCustomView(Context context) {
// do initialisation stuff
}
public setText(String text){
mText = text;
this.invalidate();
}
#Override
public void onDraw(Canvas canvas) {
canvas.save();
super.onDraw(canvas);
canvas.drawBitmap(touchPointX, touchPointY, bitmap)
if (!mText.equals(""){
canvas.drawText(touchPointX, touchPointY + 10, mText)
}
canvas.restore();
}
}
public class MyActivity extends Activity implements OnTouchListener{
private Handler mHandler = new Handler();
private MyCustomView mCustomView;
#Override
protected void onCreate(Bundle savedInstanceState) {
mCustomView = (MyCustomView) findViewById(r.id.myCustomView);
}
#Override
public boolean onTouch(View v, MotionEvent rawEvent) {
// get x and y of touch
mCustomview.touchPointX = x;
mCustomview.touchPointY = y;
mCustomView.setText("Screen touched");
// clear the text after 5 seconds
mHandler.postDelayed(clearText, 5000);
// redraw the view
mCustomView.invalidate();
}
private void clearText(){mCustomView.setText("");}
}
I am creating a boardgame for Android and I have an animation that I wish to do when a specific motion event occurs.
I have a Boardview class which draws on a surfaceview with bitmaps and this shows the user the board.
When a motion event happens, this code executes
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Intent animate = new Intent(Tempboardview.this, Moving.class);
animate.putExtra("xOld", oldStones.get(i).getx());
animate.putExtra("yOld", oldStones.get(i).gety());
animate.putExtra("xNew", newStones.get(i).getx());
animate.putExtra("yNew", newStones.get(i).gety());
animate.putExtra("color", 0);
startActivity(animate);
}
}
where newStones and oldStones are simply ArrayList objects and gety() and getx() return doubles.
This is my Moving class
public class Moving extends Activity {
private static final String TAG = "Animation";
double xOld = 0, yOld = 0, xNew = 0, yNew = 0, color = 0;
/** Called when the activity is first created. */#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
LayoutInflater inflater = getLayoutInflater();
addContentView(inflater.inflate(R.layout.move, null),
new ViewGroup.LayoutParams(800, 480));
final ImageView image = (ImageView) findViewById(R.id.stoneimager);
image.setVisibility(View.GONE);
image.bringToFront();
Bundle extras = getIntent().getExtras();
if (extras != null) {
xOld = extras.getDouble("xOld");
yOld = extras.getDouble("yOld");
xNew = extras.getDouble("xNew");
yNew = extras.getDouble("yNew");
color = extras.getDouble("color");
}
Animation animate = new TranslateAnimation((float) xOld, (float) xNew, (float) yOld, (float) yNew);
animate.setDuration(1000);
animate.setStartOffset(0);
animate.setInterpolator(new LinearInterpolator());
animate.setRepeatCount(0);
animate.setFillAfter(true);
animate.setZAdjustment(Animation.ZORDER_TOP);
Animation.AnimationListener listener = new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
Log.d("boardtag", "animation started");
image.setVisibility(View.VISIBLE);
image.bringToFront();
}
#Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationEnd(Animation animation) {
// TODO Auto-generated method stub
image.setVisibility(View.GONE);
finish();
}
};
animate.setAnimationListener(listener);
Log.d("boardtag", "animation started");
image.startAnimation(animate);
}
}
The problem is the animation is not able to take place while the board is still displayed.
I have used the android manifest to change the theme of .Moving to Transparent, but this did not work.
Any advice would be appreciated.
This is probably going to come off more harsh than I intend, but I think you are completely abusing the Intent/Activity features. You need to seriously consider redesigning your UI layer to be more closely coupled with the active Activity.
What you have above should be painfully slow since motion events are common and Activity creation and Intent dispatching is expensive (relatively). What you need is a single main "game" Activity that is tightly coupled with a SurfaceView (probably OpenGL since this has animations and it's a game). This activity would take user input (UI events) and translate them into drawing commands for your surface view directly.