1

I'm obviously missing something big and simple, but I can't find it. I've got surface view with a background image, several moving/movable sprites, and can zoom and pan the image. Everything works fine... except when touching with a second pointer if the canvas is translated.

If the canvas is at 0, 0, no problem. If the canvas is translated, no problem with first pointer. But, if second finger touches, it snaps to 0,0. Lift second finger, and it snaps back to translated.

Seemed like a simple fix - if second pointer, keep translated value. But this is the problem - logging shows that it does keep tx value - it never shows 0,0 anywhere.

I've tried using the if (activePointer != INVALID_POINTER_ID) method & it does same thing. I just can't figure out what is telling the canvas to jump to 0,0 when log shows the translate value has not changed.

Here is a sample of one of my many head-banging tries:

boolean doTouchEvent(MotionEvent ev) { 
        synchronized (gvSurfaceHolder) {
            mScaleDetector.onTouchEvent(ev);    
            float x = ev.getX(0);
            float y = ev.getY(0);

         // get pointer index from the event object
            int pointerIndex = ev.getActionIndex();

            // get pointer ID
            int pointerId = ev.getPointerId(pointerIndex);

            switch (ev.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN:    
                    contact = false;            
                    // mLastTouch handles the finger position for moving the sprites
                    // translate handles where to move the whole screen when NOT touching sprites

                    mLastTouchX = x / mScaleFactor;
                    mLastTouchY = y / mScaleFactor;

                  //We assign the current X and Y coordinate of the finger to startX and startY minus the previously 
                  //translated amount for each coordinates This works even when we are translating the first 
                  //time because the initial values for these two variables is zero.              
                  startX = x - previousTranslateX;
                  startY = y - previousTranslateY;      

                  detectPCTouch();
                  if (contact){
                     mLastTouchX = startX / mScaleFactor;
                     mLastTouchY = startY / mScaleFactor;
                  }testVarDump("Down", pointerIndex, pointerId);        
                  break;

                case MotionEvent.ACTION_POINTER_DOWN:   
                    stopTranslate = true;
                     testVarDump("ACTION Pointer DOWN", pointerIndex, pointerId);
                    break;

                case MotionEvent.ACTION_MOVE:                   
                    x = ev.getX(0);
                    y = ev.getY(0);
                    //testVarDump("ACTION Move", pointerIndex, pointerId);
                    // Only move if the ScaleGestureDetector isn't processing a gesture.
                    if (!mScaleDetector.isInProgress()){
                        if (!contact){
                        translateX = x - startX;
                        translateY = y - startY;
                        mLastTouchX = x / mScaleFactor;
                        mLastTouchY = y / mScaleFactor;
                        }else{
                            translateX = previousTranslateX;
                            translateY = previousTranslateY;
                            mLastTouchX = (x - previousTranslateX) / mScaleFactor;
                            mLastTouchY = (y - previousTranslateY) / mScaleFactor;
                        }
                    }                       
                    break;  

                case MotionEvent.ACTION_POINTER_UP: 
                    contact = false;
                    stopTranslate = true;
                    testVarDump("ACTION Pointer UP", pointerIndex, pointerId);
                    break;

                case MotionEvent.ACTION_UP:                 
                    // All fingers went up, so let's save the value of translateX and translateY into 
                    // previousTranslateX and previousTranslate   
                    if (!contact){                  
                        previousTranslateX = translateX;
                        previousTranslateY = translateY;
                    }else{  
                        translateY = previousTranslateY;
                        translateX = previousTranslateX;
                    }

                    contact = false;
                    stopTranslate = false;testVarDump("ACTION Up", pointerIndex, pointerId);
                    break;

            }               
        }
        return true;
    }

The run block:

@Override
    public void run() {
        while (running) {
            Canvas c = null;
            try {
                c = gvSurfaceHolder.lockCanvas(null);

                synchronized (gvSurfaceHolder) {                        
                    c.save();
                    c.scale(mScaleFactor, mScaleFactor);
                    //If translateX times -1 is lesser than zero, let's set it to zero. This takes care of the left bound
                    if((translateX * -1) < 0) 
                        translateX = 0;             
                    //This is where we take care of the right bound. We compare translateX times -1 to (scaleFactor - 1) * displayWidth.
                    //If translateX is greater than that value, then we know that we've gone over the bound. So we set the value of
                    //translateX to (1 - scaleFactor) times the display width. Notice that the terms are interchanged; it's the same
                    //as doing -1 * (scaleFactor - 1) * displayWidth
                    else if((translateX * -1) > (mScaleFactor - 1) * screenW) 
                        translateX = (1 - mScaleFactor) * screenW;                                          
                    if(translateY * -1 < 0) 
                        translateY = 0;                 
                    //We do the exact same thing for the bottom bound, except in this case we use the height of the display
                    else if((translateY * -1) > (mScaleFactor - 1) * screenH) 
                        translateY = (1 - mScaleFactor) * screenH;                  

                    if (!mScaleDetector.isInProgress()) 
                        c.translate(translateX / mScaleFactor, translateY / mScaleFactor);

      // Here I'd expect translateX to be 0, but always logs as correctly
      // translated, even when the background snaps to 0,0 with second pointer touch
                    if (stopTranslate)
                        testVarDump("DRAW", 0 ,0); 

                    updateBadGuys();
                    detectCollision();
                    draw(c);
                    c.restore();
                }
            } finally {
                if (c != null) 
                    gvSurfaceHolder.unlockCanvasAndPost(c);
            }
        }

I'm going a little nuts here - any idea what is forcing the translation JUST when a second finger is up or down? Please help - what the heck am I missing?

Watercayman
  • 7,970
  • 10
  • 31
  • 49
  • 1
    see my answer here http://stackoverflow.com/a/21657145/2252830 on how to combine scale and translate (and even rotate) gesture detectors in extremely easy way – pskink Mar 09 '15 at 14:42
  • @pskink - pretty brilliant code, thank you for sharing. While I have no problem adding code - I was hoping that I was just missing a simple if-check somewhere to prevent an unwanted translation -- I'd really rather not add in whole classes and all of your (excellent) code if there is a simple check that can stop the jump caused by the second pointer going up/down. – Watercayman Mar 09 '15 at 15:15
  • of course you dont have to paste my code: you can just call two detectors in **doTouchEvent**: `mgd.onTouchEvent(event); sgd.onTouchEvent(event);` that's all, magic: the Matrix is now translated and scaled properly – pskink Mar 09 '15 at 15:24

0 Answers0