如何使 MotionEvent 的坐标与缩放的 canvas 的坐标相匹配?
How do I make the coordinates of MotionEvent match the ones of a scaled canvas?
我有一个 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 和基于渲染比例的 class 的 Rect 之间的碰撞时,这会导致问题。这导致 class SuperCoin 的 X 坐标不等于 MotionEvent X 坐标。
通常,MotionEvent 的坐标 X 和 Y 都比屏幕的最大尺寸大得多(由 WIDTH
和 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;
}
还有超级币:
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 class 中定义的 Rect 与 onTouchEvent 方法中定义的不同。我猜是因为 X 和 Y 在 MotionEvent 定义的和缩放 canvas 定义的之间永久不同。 SuperCoin class 中的 Rect 以其已传递的 Bitmap 的宽度为单位。它使用位图的宽度和高度对其进行缩放。
在过去 2 天查看 Whosebug 和 Google 寻找接近解决方案的东西后,我想到了这个:缩放后获取 Canvas 坐标 up/down 或拖入 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);
我将此添加为答案并接受它,这样它就不再是未解决的问题,因为它已经解决了。上面的代码将坐标转换为整数,因此它们可用于检查手指与 object 我正在检查
之间的碰撞
不要直接缩放 canvas。制作一个 Matrix 对象,缩放一次。然后将其连接到 canvas。然后你可以为你的触摸事件制作一个倒矩阵。
只要改变视图矩阵就制作逆矩阵:
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);
大功告成。一切都为您服务。您对视图矩阵所做的任何修改都会更改您的视图框,并且您的触摸事件也会被转换为相同的场景。
如果您想添加平移或旋转,甚至倾斜视图,这一切都已解决。只需将其应用于矩阵,得到倒置矩阵,视图就会看起来像那样,触摸事件也会按照您的预期响应。
我有一个 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 和基于渲染比例的 class 的 Rect 之间的碰撞时,这会导致问题。这导致 class SuperCoin 的 X 坐标不等于 MotionEvent X 坐标。
通常,MotionEvent 的坐标 X 和 Y 都比屏幕的最大尺寸大得多(由 WIDTH
和 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;
}
还有超级币:
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 class 中定义的 Rect 与 onTouchEvent 方法中定义的不同。我猜是因为 X 和 Y 在 MotionEvent 定义的和缩放 canvas 定义的之间永久不同。 SuperCoin class 中的 Rect 以其已传递的 Bitmap 的宽度为单位。它使用位图的宽度和高度对其进行缩放。
在过去 2 天查看 Whosebug 和 Google 寻找接近解决方案的东西后,我想到了这个:缩放后获取 Canvas 坐标 up/down 或拖入 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);
我将此添加为答案并接受它,这样它就不再是未解决的问题,因为它已经解决了。上面的代码将坐标转换为整数,因此它们可用于检查手指与 object 我正在检查
之间的碰撞不要直接缩放 canvas。制作一个 Matrix 对象,缩放一次。然后将其连接到 canvas。然后你可以为你的触摸事件制作一个倒矩阵。
只要改变视图矩阵就制作逆矩阵:
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);
大功告成。一切都为您服务。您对视图矩阵所做的任何修改都会更改您的视图框,并且您的触摸事件也会被转换为相同的场景。
如果您想添加平移或旋转,甚至倾斜视图,这一切都已解决。只需将其应用于矩阵,得到倒置矩阵,视图就会看起来像那样,触摸事件也会按照您的预期响应。