我目前正在尝试在Android中开发一个原型,用户可以在屏幕上拖动4个单独的按钮。
我遇到的麻烦是碰撞检测。例如,如果其中一个按钮位于另一个按钮旁边,则只允许沿Y轴移动。同样,如果其中一个按钮触摸另一个按钮的顶部或底部,则只允许沿X轴移动。
像
这样的东西for (TouchButton t:myButtons)
{
if(!(t.equals(b)))
{
if((b.getY() >= t.getY() && (b.getY() <= (t.getY() + t.getMeasuredHeight()))))
{
if((b.getX() >= t.getX() && (b.getX() <= (t.getX() + t.getMeasuredWidth()))))
{
//dont move
}
}
}
应该能够检测按钮是否在两个轴上都有触摸?但是,如何确定是否可以向上滑动或穿过对象?
答案 0 :(得分:3)
这是严格的版本:
boolean areOverlapping (TouchButton a, TouchButton b)
{
return (b.getY() >= a.getY()
&& (b.getY() <= (a.getY() + a.getMeasuredHeight()))
&& b.getX() >= a.getX()
&& (b.getX() <= (a.getX() + a.getMeasuredWidth()))));
}
在此版本中,允许按轴触摸:
boolean areOverlappingButTouchIsAllowed (TouchButton a, TouchButton b)
{
return (b.getY() > a.getY()
&& (b.getY() < (a.getY() + a.getMeasuredHeight()))
&& b.getX() > a.getX()
&& (b.getX() < (a.getX() + a.getMeasuredWidth()))));
}
您还可以检查他们是否触摸:
boolean areTouching (TouchButton a, TouchButton b)
{
return ((b.getY() == (a.getY() + a.getMeasuredHeight()))
|| (a.getY() == (b.getY() + b.getMeasuredHeight()))
|| (b.getX() == (a.getX() + a.getMeasuredWidth())))
|| (a.getX() == (b.getX() + b.getMeasuredWidth()))));
}
然后
for (TouchButton t : myButtons)
{
if (!t.equals(b))
{
if (areOverlappingButTouchIsAllowed(b,t))
{
// overlapping beside borders
}
else if (areTouching(b,t))
{
// touching; overlapping borders only
}
}
}
答案 1 :(得分:1)
确定我调整了here的一些代码,我想出了一个完美的解决方案:
Float newX = ev.getX() - (b.getMeasuredWidth()/2);
Float newY = ev.getY() - (b.getMeasuredHeight()/2);
for (TouchButton t:myButtons)
{
if(!(t.equals(b)))
{
Rectangle r1 = new Rectangle(t.getX(), t.getY(), (float)t.getMeasuredWidth(), (float)t.getMeasuredHeight());
Rectangle r2 = new Rectangle(newX, b.getY(), (float)b.getMeasuredWidth(), (float) b.getMeasuredHeight());
Rectangle r3 = new Rectangle(b.getX(), newY, (float)b.getMeasuredWidth(), (float) b.getMeasuredHeight());
if(r1.interects(r2))
{
MoveX = false;
}
if(r1.interects(r3))
{
MoveY = false;
}
}
}
这里是Rectangle.java:
public class Rectangle
{
private Float startX;
private Float startY;
private Float width;
private Float height;
private Float endX;
private Float endY;
public Rectangle(Float _x, Float _y, Float _width, Float _height)
{
startX = _x;
startY = _y;
width = _width;
height = _height;
endX = _width + _x;
endY = _height + _y;
}
public Float getX()
{
return startX;
}
public Float getY()
{
return startY;
}
public float getWidth()
{
return width;
}
public float getHeight()
{
return height;
}
public float getEndX()
{
return endX;
}
public float getEndY()
{
return endY;
}
public boolean interects (Rectangle _r2)
{
return rectOverlap(this, _r2);
}
private boolean valueInRange(float value, float min, float max)
{ return (value >= min) && (value <= max); }
private boolean rectOverlap(Rectangle A, Rectangle B)
{
boolean xOverlap = valueInRange(A.getX(), B.getX(), B.getEndX()) ||
valueInRange(B.getX(), A.getX(), A.getEndX());
boolean yOverlap = valueInRange(A.getY(), B.getY(), B.getEndY()) ||
valueInRange(B.getY(), A.getY(), A.getY() + B.getHeight());
return xOverlap && yOverlap;
}
}
[这里不稳定的回答]
[出于历史目的]
我不确定这是多么优雅,也许有人能想出更好的东西?
在Khaled A Khunaifer的回答基础上,我意识到如果要进行移动,我需要检查按钮的位置,然后只有在没有碰撞后才执行每次移动:
Boolean MoveX = true;
Boolean MoveY = true;
Float newX = ev.getX() - (b.getMeasuredWidth()/2);
Float newY = ev.getY() - (b.getMeasuredHeight()/2);
for (TouchButton t:myButtons)
{
if(!(t.equals(b)))
{
if (areOverlapping(t,b.getX(), newY))
{
MoveY=false;
}
if(areOverlapping(t,newX,b.getY()))
{
MoveX = false;
}
}
}
if (MoveX)
{
b.setX(newX);
}
if (MoveY)
{
b.setY(newY);
}
boolean areOverlapping (TouchButton a, double x, double y)
{
return (y >= a.getY()
&& (y <= (a.getY() + a.getMeasuredHeight()))
&& x >= a.getX()
&& (x <= (a.getX() + a.getMeasuredWidth())));
}
这种方式实现了我正在寻找的东西,但它有点不稳定,有时允许按钮重叠。我将尝试使用areTouching进行实验,但我需要先解码逻辑,因为它的编写方式会产生错误。
答案 2 :(得分:1)
保持4个值对应于沿+ x,-x,+ y,-y的边界距离。 当其中一个值为零时,应进一步限制运动..