greyhh

记录学习中的点点滴滴

导航

线性规划解决图片内不规则多边形的碰撞体问题

Posted on 2016-07-18 18:13  greyhh  阅读(1023)  评论(0编辑  收藏  举报

首先,我们先来看一个问题,如下图演示

 

当鼠标点击图片里正六边形内某个点时,我们需要取到该点的颜色值并进行一些操作。而点击正六边形外的透明区域时,我们不需要对该区域进行取值,但是Unity没有正六边形碰撞体,用其他碰撞体代替总会有一些问题。

于是,我首先想到了用多个小碰撞体来拼接一下,好了,问题完美解决了。

不过。。。如果是这样的呢?

   

 

要想完美拼接起来,那得需要多少boxcollider啊!

 

于是我又想到了另外一种方法:线性规划。

通过线性规划将所需区域围起来,点击时判断鼠标位置是否在规划区域里,从而解决不规则多边形的事件检测。

 

简单的做了一个Demo,部分代码如下:

直线类(相应的可以扩展各种曲线)

public class Line
{
    public Vector2 StartPos { get; set; }
    public Vector2 EndPos { get; set; }
    public Line(Vector2 start, Vector2 end)
    {
        StartPos = start;
        EndPos = end;
    }
     /// <summary>
     ///计算点是否在该直线上
     /// </summary>
     /// <param name="point"></param>
     /// <returns>0:点在直线上;1:点在直线上方;-1:点在直线下方</returns>
    public int IsOnLine(Vector2 point)
    {
        float yOnLine = CalcYByX(point.x);
        if (Math.Abs(yOnLine - point.y) <= 0.001f) return 0;
        else
        {
            if ((yOnLine - point.y) > 0) return -1;
            else return 1;
        }
    }
    public float CalcYByX(float x)
    {
        if (StartPos.x == EndPos.x) throw new Exception("X1=X2");
        if (StartPos.y == EndPos.y) return StartPos.y;
        return (EndPos.y - StartPos.y) / (EndPos.x - StartPos.x) * (x - StartPos.x) + StartPos.y;
    }
}

 

正六边形线性规划代码:

 //线性规划解决点是否在正六边形内部
    bool IsInRegularHexagon(Vector2 center,float edge,Vector2 point)
    {
        Vector2 pUp=new Vector2(center.x,center.y+edge);
        Vector2 pDown = new Vector2(center.x, center.y - edge);
        Vector2 pLeft1 = new Vector2(center.x-1.732f/2*edge, center.y + edge/2); 
        Vector2 pLeft2=new Vector2(center.x-1.732f/2*edge, center.y - edge/2); 
        Vector2 pRight1=new Vector2(center.x+1.732f/2*edge, center.y + edge/2); 
        Vector2 pRight2=new Vector2(center.x+1.732f/2*edge, center.y - edge/2);
        Line line1 = new Line(pUp,pLeft1);
        Line line2 = new Line(pUp,pRight1);
        Line line3 = new Line(pDown,pLeft2);
        Line line4 = new Line(pDown,pRight2);
      
        if (point.x > (center.x - 1.732f / 2 * edge) && point.x < center.x + 1.732f / 2 * edge)
        {
            if (line1.IsOnLine(point)==-1&&
                line2.IsOnLine(point)==-1&&
                line3.IsOnLine(point)==1&&
                line4.IsOnLine(point)==1)
            {
                return true;
            }
        }
        return false;
    }