【问题标题】:Monogame - Per Pixel Collision on iOSMonogame - iOS 上的每像素碰撞
【发布时间】:2017-03-07 20:20:21
【问题描述】:

首先,我想说的是,我正在使用此代码进行每像素碰撞检测:

    public bool CollidesWith(Sprite other)
    {
        // Default behavior uses per-pixel collision detection
        return CollidesWith(other, true);
    }

    public bool CollidesWith(Sprite other, bool calcPerPixel)
    {
        // Get dimensions of texture
        int widthOther = other.Texture.Width;
        int heightOther = other.Texture.Height;
        int widthMe = Texture.Width;
        int heightMe = Texture.Height;

        if (calcPerPixel &&                                // if we need per pixel
            ((Math.Min(widthOther, heightOther) > 10) ||  // at least avoid doing it
            (Math.Min(widthMe, heightMe) > 10)))          // for small sizes (nobody will notice :P)
        {
            return Rectangle.Intersects(other.Rectangle) // If simple intersection fails, don't even bother with per-pixel
                && PerPixelCollision(this, other);
        }

        return Rectangle.Intersects(other.Rectangle);
    }

    public bool PerPixelCollision(Sprite a, Sprite b)
    {
        // Get Color data of each Texture
        Color[] bitsA = new Color[a.Texture.Width * a.Texture.Height];
        a.Texture.GetData(bitsA);
        Color[] bitsB = new Color[b.Texture.Width * b.Texture.Height];
        b.Texture.GetData(bitsB);

        // Calculate the intersecting rectangle
        int x1 = Math.Max(a.Rectangle.X, b.Rectangle.X);
        int x2 = Math.Min(a.Rectangle.X + a.Rectangle.Width, b.Rectangle.X + b.Rectangle.Width);

        int y1 = Math.Max(a.Rectangle.Y, b.Rectangle.Y);
        int y2 = Math.Min(a.Rectangle.Y + a.Rectangle.Height, b.Rectangle.Y + b.Rectangle.Height);

        // For each single pixel in the intersecting rectangle
        for (int y = y1; y < y2; ++y)
        {
            for (int x = x1; x < x2; ++x)
            {
                // Get the color from each texture
                Color a1 = bitsA[(x - a.Rectangle.X) + (y - a.Rectangle.Y) * a.Texture.Width];
                Color b1 = bitsB[(x - b.Rectangle.X) + (y - b.Rectangle.Y) * b.Texture.Width];

                if (a1.A != 0 && b1.A != 0) // If both colors are not transparent (the alpha channel is not 0), then there is a collision
                {
                    return true;
                }
            }
        }
        // If no collision occurred by now, we're clear.
        return false;
    }

这段代码在我的“Sprite”结构中。它在 Windows、OpenGL(MonoGame 跨平台桌面项目)、Android 和 Windows UWP 上运行良好。

但在 iOS 上,当我调用 Sprite.CollidesWith(...); 时,我的程序会停止渲染屏幕。一切正常,但它不能渲染新帧(它渲染静态图像)。 (我添加了点击声音来测试程序是否崩溃。(点击屏幕冻结后,我可以听到声音)

问题出在这一行:

a.Texture.GetData(bitsA);

我在网上搜索,发现 Texture2D.GetData 没有在 iOS 上实现......所以,有没有可能在 iOS 上进行像素完美的碰撞检测? (不调用 GetData)

抱歉有任何错误,我是这个论坛的新手。 感谢您的帮助。

【问题讨论】:

  • @Jason 不,它不是重复的——我不想从 xml 加载它。保存或读取文件可能会影响游戏性能。
  • @Enter 再看看另一个问题。从 XML 加载是不是的答案。这样做的方法是创建您自己的 binary 格式(如其他问题的实际答案所示)。就性能而言,它不会对您在整个方案中的加载时间产生太大影响。加载该二进制格式可能只需要加载原始纹理所需时间的一小部分。
  • 我没有说它是重复的,但它确实包含对缺少 iOS 实现的解决方法的讨论

标签: c# ios debugging xamarin.ios monogame


【解决方案1】:

我在网上搜索,发现Texture2D.GetData在iOS上没有实现...

所以事情就是这样。 Texture2D.GetData 不打算以您使用它的方式使用。它实际上所做的是在纹理已经发送到显卡之后从 GPU 中读回纹理数据。如果可以避免,那不是你想做的事情。

如果您不相信我,请阅读this thread on the MonoGame forums。这是该线程的引述,很好地总结了它。

我们需要在文档中用大写字母表示。不要每帧都调用 GetData()。如果可能的话,完全避免它。 GPU 旨在让数据进入其中,而不是反过来。

在大多数平台上,这是一个相当缓慢的操作。正如您所发现的,在某些平台上,这甚至是不可能的。


soo,有没有可能在 iOS 上进行像素完美的碰撞检测? (不调用 GetData)

所以这里真正的问题是如何完全避免使用GetData。正如 cmets 中所述,如果您想要快速而肮脏的东西,您可以使用相当合理的 workaround

保存或读取文件可能会影响游戏性能。

我觉得有点讽刺的是,当您已经因每像素碰撞而影响渲染性能时,您还担心游戏性能。

事实上,出于性能原因,大多数游戏不会进行逐像素碰撞检测。如果您使用更简单的碰撞形状(如矩形和圆形),玩家几乎肯定不会注意到它。如果您真的需要它们,我认为值得考虑。

不过我不知道你在制作什么类型的游戏。有些游戏确实需要逐像素碰撞,所以如果确实是这种情况,我会告诉你我的想法如何处理它。

我认为进行逐像素碰撞的最佳方法是以某种二进制格式存储纹理数据。但更重要的是,理想情况下,您希望通过 MonoGame 内容管道或其他方式预处理数据,这样您就不会在运行时从慢速源读取数据。像这样的方法可以让您两全其美(游戏启动时的快速加载和快速渲染)。

工作量很大,但可能需要考虑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多