0

How do you fix the position of an image drawn onto a canvas with a large scrollable background?

picture this: the background image is that of a room, the object images are bed, door etc. the object images are drawn on top of the background.

when i scroll the background, the objects should move with respect to the background image, correct? the problem is the object images also move but the position doesn't stay the same, i.e they shift from their original positions.

here is my full class implementation.

Bitmap bmImage;
SpriteAnim8 anim;
MThread thread;
PersonAnimated person, person2;
Canvas canvas = new Canvas();

Rect displayRect = null;
Rect scrollRect = null;
int scrollRectX = 0, scrollRectY = 0;
float scrollByX = 0, scrollByY = 0;
float startX = 0, startY = 0;
int initX = 200, initY = 200;

float a = initX, b = initY;

public MGamePanel(Context context) {
    super(context);

    // adding the callback (this) to the surface holder to intercept events
    getHolder().addCallback(this);

    // create Person and load bitmap
    person = new PersonAnimated(BitmapFactory.decodeResource(getResources(), R.drawable.dad_anim),
            10, 200 /* initial position */,
            45, 56 /* width and height of sprite */,
            5, 10); /* FPS and number of frames in the animation */
    // Destination rect for our main canvas draw
    displayRect = new Rect(0, 0, SpriteAnim8.displayWidth, SpriteAnim8.displayHeight);

    // Scroll rect: this will be used to 'scroll around' over the bitmap
    scrollRect = new Rect(0, 0, SpriteAnim8.displayWidth, SpriteAnim8.displayHeight);

    // Load a large bitmap
    bmImage = BitmapFactory.decodeResource(getResources(), R.drawable.l1_plain);

    // create the game loop thread
    thread = new MThread(getHolder(), this);

    // make the GamePanel focusable so it can handle events
    setFocusable(true);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    // at this point the surface is created and we can safely start the game
    // loop
    thread.setRunning(true);
    thread.start();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    Log.d(TAG, "Surface is being destroyed");
    // tell the thread to shut down and wait for it to finish
    // this is a clean shutdown
    boolean retry = true;
    while (retry) {
        try {
            thread.setRunning(false);
            ((Activity) getContext()).finish();
            retry = false;
        } catch (Exception e) {
            // try again shutting down the thread

        }
    }
    Log.d(TAG, "Thread was shut down cleanly");
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        // delegating event handling to the person

         startX = event.getRawX();
         startY = event.getRawY();

        // }
         case MotionEvent.ACTION_MOVE:

        float x = event.getRawX();
        float y = event.getRawY();
        // Calculate move update.
        mScrollByX = x - mStartX + mOldScrollByX; // move update x increment
        mScrollByY = y - mStartY + mOldScrollByX; // move update y increment

        onDraw(canvas);

        break;
    case MotionEvent.ACTION_UP:
        mOldScrollByX = mScrollByX;
        mOldScrollByY = mScrollByY;
        break;
    }
    return true;
}

public void render(Canvas canvas) {

     Paint paint = new Paint();
     canvas.drawBitmap(bmImage, scrollRect, displayRect, paint);
    person.draw(canvas);

}

@Override
protected void onDraw(Canvas canvas) {
    int newScrollRectX = scrollRectX - (int) scrollByX;
    int newScrollRectY = scrollRectY - (int) scrollByY;

    // Prevent scrolling off the left or right edges of the bitmap.
    if (newScrollRectX < 0) {
        newScrollRectX = 0;
    } else if (newScrollRectX > (bmImage.getWidth() - SpriteAnim8.displayWidth)) {
        newScrollRectX = (bmImage.getWidth() - SpriteAnim8.displayWidth);
    }

    // Prevent scrolling off the top or bottom edges of the bitmap.
    if (newScrollRectY < 0) {
        newScrollRectY = 0;
    } else if (newScrollRectY > (bmImage.getHeight() - SpriteAnim8.displayHeight)) {
        newScrollRectY = (bmImage.getHeight() - SpriteAnim8.displayHeight);
    }

    // set the updated scroll rect coordinates.
    scrollRect.set(newScrollRectX, newScrollRectY, newScrollRectX
            + SpriteAnim8.displayWidth, newScrollRectY
            + SpriteAnim8.displayHeight);


    // Reset current scroll coordinates to reflect the latest updates so we
    // can repeat
    scrollRectX = newScrollRectX;
    scrollRectY = newScrollRectY;

    person.setX(person.getX() + scrollByX);
    person.setY(person.getY() + scrollByY);

}

is this correct?

animuson
  • 53,861
  • 28
  • 137
  • 147
Blacklight119
  • 17
  • 1
  • 7

2 Answers2

0

Not sure about your code, but you can use a FrameLayout with background that you want for room and add ScrollView as its child, which will contain the other objects which are scrollable.

HTH !

Karan
  • 12,724
  • 6
  • 40
  • 33
0

Here is a code how to scroll a picture/image which is drawn on canvas:

//define points on the custome view class level
PointF touchStart = new PointF();
PointF picStart = new PointF();
PointF prevPicStart = new PointF();

Handle the touch and remember the previous poistion of the picture

@Override
public boolean onTouchEvent(MotionEvent ev) {

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN: {

  touchStart.set(ev.getX(), ev.getY());


  break;
}

case MotionEvent.ACTION_MOVE: {

  float newX = ev.getX() - touchStart.x + prevPicStart.x;
  float newY = ev.getY() - touchStart.y + prevPicStart.y;

  //assuming the the picture is bigger than the screen                      
  if ((newX <= 0 && newX > 0 - pic.getWidth() + screenW)){
    picStart.x = newX;                 
  }

  if ((newY <= 0 && newY > 0 - pic.getHeight() + screenH)){
    picStart.y = newY;
  }

  invalidate();
  break;                            
}           

case MotionEvent.ACTION_UP:

  prevPicStart.x = picStart.x;
  prevPicStart.y = picStart.y;
  break;

}
return true;
}

In onDraw

canvas.drawBitmap(pic, picStart.x, picStart.y, null);
Lumis
  • 21,517
  • 8
  • 63
  • 67
  • Probably you will need to add some limits to picStart point so that the image canot be scrolled out of the screen or an area... but this depenends on what you want to do. – Lumis Apr 01 '11 at 07:16
  • @Lumis it works fine when i scroll to the right, but when i scroll left, up or down, the objects go haywire and out of the screen... and im not using canvas.drawBitmap(), still using getX()+picStart.X i cant figure out why this is happening... ur logic seems sound but there is still a problem – Blacklight119 Apr 01 '11 at 10:32
  • I've updated the full class code so that u can have a better understanding of how it works... – Blacklight119 Apr 01 '11 at 10:52
  • When you glide your finger over the screen onDraw will be called about 60 times per second, which means that a statement like mDad.setX((mDad.getX() + mScrollByX)); can make mDad.x grow huge in a second because it is adding on itself. What you need to do is to create a simple working code for just one object and when you are happy with it keep adding more code so if something goes wrong you know where it happend. – Lumis Apr 01 '11 at 11:21
  • I have updated my post to include limits for the image. Why don't you just make the example I gave you working with the one image? Then move to the next step. You only need surface view and a thread when you make a continous animations. So your other problem may be that you call onDraw from two places, instead just one, which should be the thread. – Lumis Apr 01 '11 at 12:04
  • @Lumis i added a `canvas.translate(picStart.x, picStart.y)` which seemed to make the objects move along with the background but now i have a new problem...their coordinates remain the same. thing is if i have an object at (497, 110) and i translate the canvas, the new coords are say (478, 110), it still shows (497, 110)...any suggestions? – Blacklight119 Apr 06 '11 at 06:39
  • You need to place translate between canvas.save() and canvas.restore(). Study this example of mine: http://stackoverflow.com/questions/4938822/how-can-i-use-the-animation-framework-inside-the-canvas/4946893#4946893 – Lumis Apr 06 '11 at 13:07
  • I think that every object should have its coordinates stored. So to move objects you use a loop and change their x and y accordingly. I personally would not use canvas.translate at all, it just make things more confusing. – Lumis Apr 07 '11 at 20:23