【问题标题】:How do I make the coordinates of MotionEvent match the ones of a scaled canvas?如何使 MotionEvent 的坐标与缩放画布的坐标相匹配?
【发布时间】:2016-10-29 22:14:11
【问题描述】:

我有一个Canvas,它被缩放,所以一切都更合适:

@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);
    }

}

它基于这两个扩展:

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

这导致处理触摸事件的MotionEvent的坐标不等于Canvas创建的坐标的问题。当我尝试检查 MotionEvent Rect 和基于渲染比例的类的 Rect 之间的碰撞时,这会导致问题。这会导致 SuperCoin 类的 X 坐标不等于 MotionEvent X 坐标。 通常,MotionEvent 的 X 和 Y 坐标都远大于屏幕的最大尺寸(由 WIDTHHEIGHT 定义)

 @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;

}

还有超级币:

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);
    }
}

当 MotionEvent X 坐标大于屏幕的缩放最大坐标时,如何检查两者之间的碰撞?

老实说,我不完全确定为什么 SuperCoin 类中定义的 Rect 与 onTouchEvent 方法中定义的不同。我猜是因为 X 和 Y 在 MotionEvent 定义的和缩放画布定义的之间是永久不同的。 SuperCoin 类中的 Rect 按照它传递的位图的宽度。它使用位图的宽度和高度对其进行缩放。

【问题讨论】:

    标签: android canvas android-bitmap motionevent


    【解决方案1】:

    在过去 2 天里通过 StackOverflow 和 Google 寻找接近解决方案的东西后,我想到了这个:Get Canvas coordinates after scaling up/down or dragging in android 解决了这个问题。真的很难找到,因为标题有点误导(另一个问题)

    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);
    

    我将此添加为答案并接受它,因此它不再是一个未回答的问题,因为它已解决。上面的代码将坐标转换为整数,因此它们可以用于检查手指和我正在检查的对象之间的碰撞

    【讨论】:

      【解决方案2】:

      不要直接缩放画布。制作一个矩阵对象,缩放一次。然后将其连接到画布上。然后你可以为你的触摸事件制作一个倒置矩阵。

      只要你改变视图矩阵,只需制作反转矩阵:

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

      然后将这两个矩阵应用于相关事件。

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

      然后在绘制事件上,连接矩阵。

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

      你就完成了。一切都为你照顾。无论您对视图矩阵所做的任何修改都会改变您的视图框,并且您的触摸事件也将被转换到同一个场景中。

      如果您想添加平移或旋转,甚至倾斜视图,这一切都已处理完毕。只需将其应用于矩阵,得到倒置矩阵,视图就会看起来像这样,并且触摸事件会按照您的预期响应。

      【讨论】:

      • 这是基于两个比例相同的事实。如果 X 刻度与 Y 刻度不同怎么办?
      • viewMatrix.postScale(scale, scale, x, y); --->> viewMatrix.postScale(scale, 1, x, y); ---- 看到它工作。 youtube.com/watch?v=GCG3i709g-Y&feature=youtu.be
      • 这是基于 x * m * (1/m) = x 的事实。也就是说,应用于触摸的反转矩阵和应用于视图的标准矩阵导致它们出现在同一空间中。 - 如果你这样做,你不再需要考虑任何一个。它只是工作。你通过一个矩阵过滤它,正确的方向并称之为一天。
      • youtube.com/watch?v=-XSjanaAdWA 您可以在使用此方案移动物体时使其呈螺旋状旋转。因为所有其他的东西都是矩阵数学,它是在矩阵类中完成的。
      • 我写道,我将行从第一件事更改为第二件事......然后我发布了一个在生产代码中进行更改的视频。它看起来很疯狂,但效果很好。
      猜你喜欢
      • 2014-09-13
      • 1970-01-01
      • 2014-08-27
      • 2012-03-07
      • 2017-02-08
      • 2016-01-01
      • 2015-03-13
      • 1970-01-01
      • 2016-11-11
      相关资源
      最近更新 更多