检测矩形(按钮)是否在x轴或y轴上重叠

时间:2013-09-12 03:14:12

标签: algorithm rectangles collision

我目前正在尝试在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
       }
   }
}

应该能够检测按钮是否在两个轴上都有触摸?但是,如何确定是否可以向上滑动或穿过对象?

Example

3 个答案:

答案 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)

  1. 用于检查边界上是否有按钮。
  2. 保持4个值对应于沿+ x,-x,+ y,-y的边界距离。 当其中一个值为零时,应进一步限制运动..

    1. 每个按钮从X到Y轴上的X1到X2和Y1到Y2。保留所有按钮。如果您的按钮沿X轴移动,请检查它是否与任何其他按钮X间隔重叠。如果是,请计算与该按钮的Y距离。如果为零,则限制移动。否则让它移动..