0

I have a puzzle game where pieces are dragged around the screen but can not overlap. If they attempt to overlap, their position is changed back to where they were not overlapping and the UI is redrawn with invalidate(). This is working well except when the activity is destroyed and rebuilt like when closing the app and restarting it or when the orientation is changed.

What seems to happen is that the position variables that I use for collisions (x,y,right,bottom, etc.) are not reset to how they were initialized in the constructor. Pieces collide with invisible objects, snap to seemingly random positions, or move erratically.

The only ways to fix it are to manually kill the app (like with a task killer) or re-install it. Then it will work fine until the game activity is created a second time. What am I doing wrong? Any ideas? Here's how the piece are added in the onCreate() inside my GameView class:

Pieces redtiki = new Pieces(this,0,0,R.drawable.tikired);
...
board.addView(redtiki);

And this is a portion of my Pieces class:

public class Pieces extends View{

private int x;
private int y;
private int width;
private int height;
private int right;
private int bottom;
private int initialX;
private int initialY;
private Bitmap sizedBitmap;
private Bitmap sourceBitmap;
private int boardSize = 6;
public static ArrayList<Pieces> aPieces = new ArrayList<Pieces>();
//private final Paint mPaint = new Paint();

public Pieces(Context context, int x, int y, int img){
    super(context);
    this.x = x;
    this.y = y;
    sourceBitmap = BitmapFactory.decodeResource(getResources(), img);
    aPieces.add(this);
    initialX=x;
    initialY=y;
}

private void sizePiece(){
    int scaledWidth;
    int scaledHeight;
    int h = sourceBitmap.getHeight();
    int w = sourceBitmap.getWidth();

    if (h>w){
        scaledWidth = 1;
    }else if (w>h){
        scaledWidth = w/h;
    }else{
        scaledWidth = 0;
    }
    if (h>w){
        scaledHeight = h/w;
    }else if (w>h){
        scaledHeight = 1;
    }else{
        scaledHeight = 0;
    }

    int dstWidth = (((((View) getParent()).getWidth())*scaledWidth)/boardSize)-1;//TODO make sure that -1 is necessary for
    int dstHeight = (((((View) getParent()).getHeight())*scaledHeight)/boardSize)-1;//fitting all pieces on the board

    sizedBitmap = Bitmap.createScaledBitmap(sourceBitmap, dstWidth, dstHeight, true);
    width = sizedBitmap.getWidth();
    height = sizedBitmap.getHeight();
    right = x+width;
    bottom = y+height;
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    sizePiece();
    canvas.drawBitmap(sizedBitmap, x, y, null);
}

@Override
public boolean onTouchEvent(MotionEvent event){

    float eventX = event.getX();
    float eventY = event.getY();

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        //check if touch is on piece
        if (eventX > x && eventX < (x+width) && eventY > y && eventY < (y+height)){
            initialX=x;
            initialY=y;
            break;
        }else{
            return false;
        }
    case MotionEvent.ACTION_MOVE:
        //determine if piece should move horizontally or vertically
        if(width>height){
            for (Pieces piece : aPieces) {
                //if object equals itself in array, skip to next object
                if(piece==this){
                    continue;
                }
                //check if there the possibility for a horizontal collision
                if(this.isAllignedHorizontallyWith(piece)){
                    //check for and handle collisions while moving left
                    if(this.isRightOf(piece)){
                        if(eventX>piece.right+(width/2)){
                            x = (int)(eventX-(width/2)); //move normally
                            /*for(Pieces piece2 : aPieces){
                                if(this.isAllignedHorizontallyWith(piece2)){
                                    if(this.isLeftOf(piece2)){
                                        if(eventX<piece2.x-(width/2)){
                                            x = (int)(eventX-(width/2));
                                            continue;
                                        }else{
                                            x = piece2.x-width-1;
                                        }
                                    }
                                }
                            }*/
                            continue;
                        }else{
                            x = piece.right+1;
                        }
                    }
                    //check for and handle collisions while moving right
                    if(this.isLeftOf(piece)){
                        if(eventX<piece.x-(width/2)){
                            x = (int)(eventX-(width/2));
                            continue;
                        }else{
                            x = piece.x-width-1;
                        }
                    }
                    break;
                }else{
                    x = (int)(eventX-(width/2));
                }
            }
        }
        if(height>width){
            for (Pieces piece : aPieces) {
                //if object equals itself in array, skip to next object
                if(piece==this){
                    continue;
                }
                //check if there the possibility for a vertical collision
                if(this.isAllignedVerticallyWith(piece)){
                    //check for and handle collisions while moving up
                    if(this.isBelow(piece)){
                        if(eventY>piece.bottom+(height/2)){
                            y = (int)(eventY-(height/2)); //move normally
                            continue;
                        }else{
                            y = piece.bottom+1;
                        }
                    }
                    //check for and handle collisions while moving down
                    if(this.isAbove(piece)){
                        if(eventY<piece.y-(height/2)){
                            y = (int)(eventY-(height/2));
                            continue;
                        }else{
                            y = piece.y-height-1;
                        }
                    }
                    break;
                }else{
                    y = (int)(eventY-(height/2));
                }
            }
        }
        invalidate();
        break;

    case MotionEvent.ACTION_UP:
        // end move
        if(this.moves()){
        GameView.counter++;
        }
        initialX=x;
        initialY=y;
        break;
        }
    // parse puzzle
    invalidate();
    return true;
    }
Amplify91
  • 2,690
  • 5
  • 24
  • 32

2 Answers2

1

In your Activity class, implement the methods OnPause(), OnResume().

Use log statements within the above mentioned methods to see whether the positions/coordinates are changed during the closing/opening of the app.

You can save the state of the various components when "OnPause()" is called. When "OnResume()" is invoked (i.e application comes to the foreground) read the saved state and draw the View with the coordinates you read recently.

Please not that "OnCreate()" will only be called once when the Activity is being created. Switching orientations will not invoked "OnCreate()"

You will find a flowchart explaining the Android API documentation. http://developer.android.com/reference/android/app/Activity.html

kensen john
  • 5,439
  • 5
  • 28
  • 36
  • Thanks for your answer. You are right about onCreate() only being called once. I misunderstood about what happens when orientation changes. It does destroy the activity, but it does not call onCreate() again. I am teaching myself programming and while I have learned a fair amount about Android, I am not sure how to use log statements. Do you know of any good resources to get me started? Thanks for your help. – Amplify91 Mar 20 '11 at 06:20
  • 1
    @Amplify91 Log Statements are used to output/print information to the console. [http://developer.android.com/reference/android/util/Log.html] [http://stackoverflow.com/questions/2018263/android-logging] the second link will help you customize/enhance the logging functionality. I would suggest start of with the first link and after you understand/use the concept, you can advance to the second link. – kensen john Mar 20 '11 at 11:41
  • Thanks again for the help! I've fixed my problem and I've learned how to use Log messages too. Thanks for the help and the useful links. – Amplify91 Apr 05 '11 at 00:12
0

I just realized what was wrong. Each time that I create a new Pieces object, it is added to my ArrayList, aPieces. So every time that the orientation changed, or I loaded a new level, it would load all my new pieces and display them, but my old pieces were still in the ArrayList and, therefore, still being checked for collisions. to solve this, before I load each new level (and all the pieces that make up the level), I clear the list with Pieces.aPieces.clear();. Now, it works perfectly.

Amplify91
  • 2,690
  • 5
  • 24
  • 32