WPF 画布和冲突检测



我正在尝试在父画布上随机放置多个子画布。我不希望同级画布重叠(或碰撞),所以我使用了一些碰撞检测。

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

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

    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 的类,它允许我为 Canvas 提供 x/y 位置并检查冲突:

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));
    }
}

当您在发生碰撞时更改随机位置时,您忘记返回以再次检查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);
        }
    }

最新更新