以优雅的方式使用多态进行碰撞检测

7

我想设置一些简单的2D图形, 可以通过鼠标在窗口中拖动. 当我将一个图形拖到另一个图形上时,希望它们能够注册碰撞。我有一个接口。

interface ICollidable
{
    bool CollidedWith(Shape other);
}

我有一个抽象类Shape,它实现了上述接口。

abstract class Shape : ICollidable
{
    protected bool IsPicked { private set; get; }
    protected Form1 Form { private set; get; }

    protected int X { set; get; } // Usually top left X, Y corner point
    protected int Y { set; get; } // Used for drawing using the Graphics object

    protected int CenterX { set; get; } // The center X point of the shape
    protected int CenterY { set; get; } // The center X point of the shape

    public Shape(Form1 f, int x, int y)
    {
        Form = f;
        X = x; Y = y;
        Form.MouseDown += new MouseEventHandler(form_MouseDown);
        Form.MouseMove += new MouseEventHandler(Form_MouseMove);
        Form.MouseUp += new MouseEventHandler(Form_MouseUp);
    }

    void Form_MouseMove(object sender, MouseEventArgs e)
    {
        if(IsPicked)
            Update(e.Location);
    }

    void Form_MouseUp(object sender, MouseEventArgs e)
    {
        IsPicked = false;
    }

    void form_MouseDown(object sender, MouseEventArgs e)
    {
        if (MouseInside(e.Location))
            IsPicked = true;
    }

    protected abstract bool MouseInside(Point point);
    protected abstract void Update(Point point);
    public abstract void Draw(Graphics g);
    public abstract bool CollidedWith(Shape other);
}

我有十个具体类Circle、Square、Rectangle等,它们扩展了Shape类并实现了抽象方法。 我希望能想出一种面向对象的干净而优雅的方式来进行碰撞检测,而不是在CollidedWith方法中使用大量的if语句块。

public bool CollidedWith(Shape other)
{
    if(other is Square)
    {
        // Code to detect shape against a square
    }
    else if(other is Triangle)
    {
        // Code to detect shape against a triangle
    }
    else if(other is Circle)
    {
        // Code to detect shape against a circle
    }
    ...   // Lots more if statements
}

有人有什么想法吗?这是一个问题,我之前曾经思考过,但现在才开始付诸实践。


如果您能解释一下如何定义碰撞以及它在子类之间可能如何变化,那将会很有帮助。Shape类是否还包含实例坐标的任何信息? - mclark1129
@Mick C. 我已经更改了代码,插入了整个Shape类的代码。 - John ClearZ
3个回答

4

碰撞检测是否如此“形状特定”,以至于每种排列组合都需要不同的实现?

Circle vs. Other Circle
Circle vs. Other Square
Circle vs. Other Triangle
Square vs. Other Circle
...

看起来你想创建一个所有可能性的矩阵,但如果你想出10个新形状,总共有20个,就会有400种可能性。

相反,我建议在你的抽象类中设计一个通用的Shape.Overlaps(Shape other)方法,可以满足所有形状。

如果这只是2D几何问题,那么判断任何形状的边缘路径是否交叉应该是微不足道的。


1

与其说是特定的形状,它们实际上只是路径区域

一个正方形只是一个有4个点的多边形,这些点碰巧在直角处。然后只需编写一个Path.CollidesWith(Path)方法即可继续进行。

查看一些相关的问题


1

1
如果你仔细想想,这其实和 OP 的 CollideWith 方法并没有太大的区别,只不过是框架会为你处理切换逻辑。另一个问题是,这种方法仍然需要你修改每个子类并为每种新类型提供新的实现,这将导致指数级增长的维护负担。 - mclark1129

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接