Polarbear0106 Polarbear0106 - 5 months ago 8
Android Question

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. 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. This causes the class SuperCoin's X coordinate to not be equal to MotionEvent X coordinates.
Usually, MotionEvent's coordinates, both X and Y is way bigger than the screen's max size(defined by
WIDTH
and
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;

}


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?

Honestly, I am not completly sure why the Rect defined in the SuperCoin class is different from the one defined in the onTouchEvent method. 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. The Rect in the SuperCoin class goes by the width of the Bitmap it has been passed. It scales it with the width and height of the Bitmap.

Answer

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. 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