2016-06-27 9 views
2

Ich habe ein Canvas, die ist so skaliert, alles passt besser:Wie stimme ich die Koordinaten von MotionEvent mit denen eines skalierten Canvas überein?

@Override 
public void draw(Canvas c){ 
    super.draw(c); 
    final float scaleFactorX = getWidth()/(WIDTH*1.f); 
    final float scaleFactorY = getHeight()/(HEIGHT*1.f); 

    if(c!=null) { 
     final int savedState = c.save(); 

     c.scale(scaleFactorX, scaleFactorY); 

     (rendering) 

     c.restoreToCount(savedState); 
    } 

} 

Schuppen auf Basis dieser beiden:

public static final int WIDTH = 856; 
public static final int HEIGHT = 1050; 

, die das Problem verursacht, dass die Koordinaten des Motion, die Touch-Ereignisse behandelt ist nicht gleich den Koordinaten, die mit dem Canvas erstellt werden. Dies führt zu Problemen, wenn ich versuche, die Kollision zwischen dem MotionEvent-Rect und dem Rect einer Klasse zu überprüfen, die auf dem Rendering-Maßstab basiert. Dies bewirkt, dass die X-Koordinate der Klasse SuperCoin nicht den MotionEvent X-Koordinaten entspricht. Normalerweise Motionkoordinaten, X und Y ist viel größer als die maximale Größe des Bildschirms (definiert durch WIDTH und HEIGHT)

@Override 
public boolean onTouchEvent(MotionEvent e) { 
    super.onTouchEvent(e); 

    switch (MotionEventCompat.getActionMasked(e)) { 
     case MotionEvent.ACTION_DOWN: 
     case MotionEvent.ACTION_POINTER_DOWN: 
      (...) 
      Rect r = new Rect((int)e.getX(), (int)e.getY(), (int)e.getX() + 3, (int)e.getY() + 3); 
      if(superCoins.size() != 0) { 
       for (SuperCoin sc : superCoins) { 
        if (sc.checkCollision(r)) { 
         progress++; 
         superCoins.remove(sc); 
        } 
       } 
      } 

      break; 

    } 

    return true; 

} 

Und die Supercoin:

public class SuperCoin { 
    private Bitmap bm; 
    public int x, y, orgY; 
    Clicker cl; 
    private Long startTime; 
    Random r = new Random(); 
    public SuperCoin(Bitmap bm, int x, int y, Clicker c){ 
     this.x = x; 
     this.y = y; 
     this.orgY = y; 
     this.bm = bm; 
     this.cl = c; 
     startTime = System.nanoTime(); 
     bounds = new Rect(x, y, x + bm.getWidth(), y + bm.getHeight()); 

    } 

    private Rect bounds; 

    public boolean checkCollision(Rect second){ 
     if(second.intersect(bounds)){ 
      return true; 
     } 
     return false; 
    } 


    private int velX = 0, velY = 0; 


    public void render(Canvas c){ 

     long elapsed = (System.nanoTime()-startTime)/1000000; 
     if(elapsed>50) { 


      int cx; 
      cx = r.nextInt(2); 
      if(cx == 0){ 
       velX = r.nextInt(4); 
      }else if(cx == 1){ 
       velX = -r.nextInt(4); 
      } 

      velY = r.nextInt(10) + 1; 

      startTime = System.nanoTime(); 
     } 

     if(x < 0) velX = +2; 
     if(x > Clicker.WIDTH) velX = -2; 

     x += velX; 
     y -= velY; 


     c.drawBitmap(bm, x, y, null); 
    } 
} 

Wie kann ich überprüfen Kollision zwischen der zwei verschiedene, wenn die MotionEvent X-Koordinate größer als die skalierten maximalen Koordinaten des Bildschirms ist?

Ehrlich gesagt bin ich mir nicht ganz sicher, warum das in der SuperCoin-Klasse definierte Rect sich von dem in der onTouchEvent-Methode definierten unterscheidet. Ich nehme an, weil X und Y sich permanent unterscheiden zwischen dem von MotionEvent definierten und dem von der skalierten Leinwand definierten. Das Rect in der SuperCoin-Klasse wird um die Breite der übergebenen Bitmap berechnet. Es skaliert es mit der Breite und Höhe der Bitmap.

Antwort

0

Nachdem ich in den letzten zwei Tagen durch StackOverflow und Google nach etwas gesucht habe, das einer Lösung nahe kommt, kam ich über Folgendes: Get Canvas-Koordinaten nach dem Vergrößern/Verkleinern oder Ziehen in Android Das Problem wurde gelöst. Es war wirklich schwer zu finden, weil der Titel leicht (die anderen Frage)

float px = e.getX()/mScaleFactorX; 
float py = e.getY()/mScaleFactorY; 
int ipy = (int) py; 
int ipx = (int) px; 
Rect r = new Rect(ipx, ipy, ipx+2, ipy+2); 

irreführend war ich dies als eine Antwort gegeben und akzeptiert es, so dass es nicht mehr wird eine offene Frage sein, wie es gelöst ist. Der obige Code konvertiert die Koordinaten in Ganzzahlen, sodass sie zum Überprüfen der Kollision zwischen dem Finger und dem Objekt, das ich überprüfe, verwendet werden können.

-1

Die Leinwand nicht direkt skalieren. Erstelle ein Matrix-Objekt, skaliere das einmal. Dann concat das auf die Leinwand. Dann können Sie eine invertierte Matrix für Ihre Berührungsereignisse erstellen.

Und machen Sie einfach die Invert-Matrix, wenn Sie die Ansicht Matrix ändern:

viewMatrix = new Matrix(); 
viewMatrix.scale(scalefactor,scalefactor); 
invertMatrix = new Matrix(viewMatrix); 
invertMatrix.invert(invertMatrix); 

Dann diese beiden Matrizen auf die relevanten Ereignisse gelten.

@Override 
    public boolean onTouchEvent(MotionEvent event) { 
     event.transform(invertMatrix); 

Und dann auf die Zeichenereignisse, concat die Matrix.

@Override 
protected void onDraw(Canvas canvas) { 
    canvas.concat(viewMatrix); 

Und du bist fertig. Alles ist für dich erledigt. Alle Änderungen, die Sie an der Ansichtsmatrix vornehmen, ändern Ihre Viewbox und Ihre Touch-Ereignisse werden ebenfalls in dieselbe Szene übersetzt.

Wenn Sie Panning oder Rotation hinzufügen oder sogar die Ansicht verzerren möchten, ist alles erledigt. Wenden Sie das einfach auf die Matrix an, erhalten Sie die invertierte Matrix und die Ansicht wird so aussehen und die Berührungsereignisse werden wie erwartet reagieren.

+0

, die auf der Tatsache basiert, dass beide Maßstäbe gleich sind. Was ist, wenn die X-Skala von der Y-Skala abweicht? – Zoe

+0

Dann funktioniert es vollkommen in Ordnung. – Tatarize

+0

viewMatrix.postScale (Skalierung, Skalierung, x, y); --- >> viewMatrix.postScale (Maßstab, 1, x, y); ---- Sehen Sie es funktioniert. https://www.youtube.com/watch?v=GCG3i709g-Y&feature=youtu.be – Tatarize

Verwandte Themen