简体   繁体   English

如何使MotionEvent的坐标与缩放画布的坐标相匹配?

[英]How do I make the coordinates of MotionEvent match the ones of a scaled canvas?

I have a Canvas that is scaled so everything fits better: 我有一个可缩放的画布 ,因此所有内容都更合适:

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

}

It scales based on these two: 它基于以下两个方面进行缩放:

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

Which causes the problem that the coordinates of the MotionEvent that handles touch events is not equal to the coordinates that is created with the Canvas. 这会导致以下问题:处理触摸事件的MotionEvent的坐标不等于使用Canvas创建的坐标。 This causes problems when I try to check collision between the MotionEvent Rect and the Rect of a class that is based on the rendering scale. 当我尝试检查MotionEvent Rect和基于渲染比例的类的Rect之间的冲突时,这会导致问题。 This causes the class SuperCoin's X coordinate to not be equal to MotionEvent X coordinates. 这将导致SuperCoin类的X坐标不等于MotionEvent X坐标。 Usually, MotionEvent's coordinates, both X and Y is way bigger than the screen's max size(defined by WIDTH and HEIGHT ) 通常,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;

}

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

How can I check collision between the two different when the MotionEvent X coordinate is bigger than the screen's scaled max coordinates? 当MotionEvent X坐标大于屏幕的缩放最大坐标时,如何检查两个不同对象之间的碰撞?

Honestly, I am not completly sure why the Rect defined in the SuperCoin class is different from the one defined in the onTouchEvent method. 坦率地说,我不能完全确定为什么SuperCoin类中定义的Rect与onTouchEvent方法中定义的Rect不同。 I'm guessing because the X and Y is permanently different between the one defined by MotionEvent and the ones defined by the scaled canvas. 我猜是因为MotionEvent定义的X和Y和缩放画布定义的X和Y永久不同。 The Rect in the SuperCoin class goes by the width of the Bitmap it has been passed. SuperCoin类中的Rect通过它已传递的位图的宽度。 It scales it with the width and height of the Bitmap. 它使用位图的宽度和高度对其进行缩放。

After looking through StackOverflow and Google for the past 2 days looking for something that comes close to a solution, I came over this: Get Canvas coordinates after scaling up/down or dragging in android Which solved the problem. 在过去两天中浏览了StackOverflow和Google,寻找了接近解决方案的东西之后,我想到了:放大/缩小或拖动android后获取Canvas坐标,从而解决了问题。 It was really hard to find because the title was slightly misleading(of the other question) 真的很难找到,因为标题有点误导(另一个问题)

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

I added this as an answer and accepting it so it no longer will be an unanswered question as it is solved. 我将此添加为答案并接受它,因此它在解决后将不再是一个未解决的问题。 The code above converts the coordinates to integers so they can be used for checking collision between the finger and the object I'm checking with 上面的代码将坐标转换为整数,因此它们可用于检查手指与我正在检查的对象之间的碰撞

Don't scale the canvas directly. 不要直接缩放画布。 Make a Matrix object, scale that once. 制作一个Matrix对象,缩放一次。 Then concat that to the canvas. 然后将其连接到画布。 Then you can make an inverted matrix for your touch events. 然后,您可以为触摸事件制作一个倒置矩阵。

And just make the invert matrix whenever you change the view matrix: 只要更改视图矩阵,就可以制作逆矩阵:

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

Then apply these two matrices to the relevant events. 然后将这两个矩阵应用于相关事件。

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

And then on the draw events, concat the matrix. 然后在绘制事件上,合并矩阵。

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

And you're done. 这样就完成了。 everything is taken care of for you. 一切都为您照顾。 Whatever modifications you do to the view matrix will change your viewbox and your touch events will be translated into that same scene too. 无论您对视图矩阵进行任何修改,都将更改您的视图框,并且您的触摸事件也将转换为该场景。

If you want to add panning or rotation, or even skew the view, it's all taken care of. 如果您想添加平移或旋转,甚至使视图倾斜,都可以解决。 Just apply that to the matrix, get the inverted matrix, and the view will look that way and the touch events will respond as you expect. 只需将其应用于矩阵,得到倒置的矩阵,视图将以这种方式显示,并且触摸事件将按照您的期望进行响应。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM