WPF画布和碰撞检测

时间:2012-10-15 21:18:31

标签: c# wpf canvas collision-detection

我正在尝试在父画布上随机定位多个子画布。我不希望兄弟画布重叠(或碰撞)所以我正在使用一些碰撞检测。

我显然做错了,因为碰撞但不能把手指放在上面。

我的绘制方法(每秒调用一次)

    private void draw(int args)
    {
        parent.Children.Clear();

        List<MyCanvas> children = fetchManyChildren(100);
        Random rand = new Random();

        foreach (MyCanvas child in children)
        {
            child.xPos = nextDouble(rand, 0, parent.ActualWidth - child.Width);
            child.yPos = nextDouble(rand, 0, parent.ActualHeight - child.Height);

            foreach (MyCanvas sibling in parent.Children)
            {
                while (child.collidesWith(sibling))
                {
                    child.xPos = nextDouble(rand, 0, parent.ActualWidth - child.Width);
                    child.yPos = nextDouble(rand, 0, parent.ActualHeight - child.Height);
                }
            }

            Canvas.SetLeft(child, child.xPos);
            Canvas.SetTop(child, child.yPos);

            parent.Children.Add(child);
        }
    }

一些辅助方法:

    private List<MyCanvas> fetchManyChildren(int amount)
    {
        List<MyCanvas> children = new List<MyCanvas>(amount);

        Random rand = new Random();

        for (int i = 1; i <= amount; i++)
        {
            double size = nextDouble(rand, 1, MAX_SIZE);

            MyCanvas child = new MyCanvas(0, 0, size, size);

            child.Background = randomBrush(rand);

            children.Add(child);
        }

        return children;
    }

    private double nextDouble(Random rand, double min, double max)
    {
        return min + (rand.NextDouble() * (max - min));
    }

从Canvas派生的类,它允许我将x / y位置赋予Canvas并检查碰撞:

public class MyCanvas : Canvas
{
    public double xPos = 0;
    public double yPos = 0;

    public MyCanvas(double x, double y, double w, double h)
    {
        this.xPos = x;
        this.yPos = y;
        this.Width = w;
        this.Height = h;
    }

    public bool collidesWith(MyCanvas p)
    {
        double bottom = this.yPos + this.Height;
        double top = this.yPos;
        double left = this.xPos;
        double right = this.xPos + this.Width;

        return !((bottom < p.yPos) ||
                 (top > p.yPos + p.Height) ||
                 (left > p.xPos + p.Width) ||
                 (right < p.xPos));
    }
}

1 个答案:

答案 0 :(得分:2)

当你发生碰撞时改变随机位置时,你忘记在parent.Children中再次检查所有的孩子......如果你没有,那么你可能会发现一个未被发现的碰撞因为你的迭代器已经过了那个项目。

您需要类似下面代码的内容。

注意你需要小心....

您应该以某种方式更改您的/我的代码,以处理无法将您的孩子置于未占用区域的情况,即没有任何剩余空间。

当你依靠“随机”数字生成最终找到“自由”位置时......发现区域所花费的时间和“运气”可能会使你处于需要的状态过度或无限的时间......一个更好的“找到”自由区域的算法是可取的。

private void draw(int args)
    {
        parent.Children.Clear();

        List<MyCanvas> children = fetchManyChildren(100);
        Random rand = new Random();

        foreach (MyCanvas child in children)
        {
            while(true)
            {
                // Choose a random place on Canvas we would like to place child

                child.xPos = nextDouble(rand, 0, parent.ActualWidth - child.Width);
                child.yPos = nextDouble(rand, 0, parent.ActualHeight - child.Height);

                // Now see if it collides with ones already on Canvas

                bool bCollisionDetected = false;

                foreach (MyCanvas sibling in parent.Children)
                {
                    bCollisionDetected = child.collidesWith(sibling);

                    if (bCollisionDetected)
                        break;
                }

                if (!bCollisionDetected) // Was able to place child in free position
                    break;
            }

            Canvas.SetLeft(child, child.xPos);
            Canvas.SetTop(child, child.yPos);

            parent.Children.Add(child);
        }
    }