1

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

应该能够检测到按钮是否在两个轴上都接触?但是我如何确定它是否应该可以向上或滑过对象?

例子

4

3 回答 3

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
         }
    }
}
于 2013-09-12T04:11:53.727 回答
1

好的,调整我在这里找到的一些代码,我想出了一个完美的解决方案:

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 进行试验,但我需要先解码逻辑,因为它的编写方式会产生错误。

于 2013-09-12T05:23:05.170 回答
1
  1. 用于检查按钮是否在边界上。

保持 4 个值对应于沿 +x、-x、+y、-y 的边界距离。当这些值之一变为零时,应限制进一步的移动。

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