【问题标题】:XAML Collision detectionXAML 冲突检测
【发布时间】:2013-02-24 05:07:09
【问题描述】:

我正在开发一款 Windows Phone 游戏,它在减去碰撞检测的情况下运行流畅。

是否有任何人可以建议检测两个 XAML 对象是否相互重叠的简单方法?

我知道的唯一方法是创建一个列表,其中包含游戏中每个可碰撞对象的坐标,然后扫描该列表以确定是否存在碰撞。

有了触发器、行为等所有很酷的 XAML 功能,我认为可能有更简单的方法。但是,搜索结果很少。

有什么想法吗?最简单的是我正在寻找的。没有什么疯狂的需要。就在我的播放器与物体碰撞时,它消失了。

我不知道这是否有区别,但我所有的对象都是图像。

【问题讨论】:

  • 系统必须知道你在测试哪两个对象,所以我认为你必须迭代所有候选对象

标签: c# wpf windows-phone-7 xaml collision-detection


【解决方案1】:

没有内置的 XAML 对象冲突检测机制。这是有道理的,XAML 是为创建应用程序 UI 而设计的——它不是游戏引擎!

你可以试试 Physics Helper 框架:

http://physicshelper.codeplex.com/

这添加了一个物理引擎,允许您通过行为将 XAML 对象转换为“物理”对象:

  <Ellipse Width="100" Height="100" Fill="Red"
            Canvas.Left="80" Canvas.Top="100">
    <!-- make the engine aware of this element -->
    <i:Interaction.Behaviors>
      <pb:PhysicsObjectBehavior />
    </i:Interaction.Behaviors>
  </Ellipse>

前段时间我玩过这个框架:

http://www.scottlogic.co.uk/blog/colin/2011/12/a-festive-and-fun-windows-phone-7-maze-game/

还不错!

【讨论】:

  • 物理助手很酷,但我无法让它与我的应用程序一起使用。我必须编写自己的引擎,但它非常简单。一会儿我会贴出来。
【解决方案2】:

所以我安装了物理助手,但上面提供的那个不能与任何 Windows 手机构建过去的芒果一起工作。所以我找到了 Physics Helper XAML,它不是一个安装文件,并且在可预见的将来使用它的文档很差。

所以我创建了自己的 XAML 冲突检测系统。它非常简单,可以满足我的需求并且速度很快。

最重要的是,您可以在 Blend 或 WYSISYG 编辑器中编辑您的画布,而且不会破坏代码。

首先,我使用我希望可碰撞的项目创建嵌套画布

<Canvas x:Name="Collidables">
            <Image x:Name="star" Width="50" Height="50" Source="images/star.png" Canvas.Left="54" Canvas.Top="-132"/>
            <Image x:Name="star_Copy" Width="50" Height="50" Source="/images/star.png" Canvas.Left="158" Canvas.Top="-190"/>
            <Image x:Name="star_Copy1" Width="50" Height="50" Source="/images/star.png" Canvas.Left="268" Canvas.Top="-260"/>
            <Image x:Name="star_Copy2" Width="50" Height="50" Source="/images/star.png" Canvas.Left="372" Canvas.Top="-322"/>
            <Image x:Name="star_Copy3" Width="50" Height="50" Source="/images/star.png" Canvas.Left="54" Canvas.Top="-390"/>
            <Image x:Name="star_Copy4" Width="50" Height="50" Source="/images/star.png" Canvas.Left="158" Canvas.Top="-448"/>
            <Image x:Name="star_Copy5" Width="50" Height="50" Source="/images/star.png" Canvas.Left="268" Canvas.Top="-518"/>
            <Image x:Name="star_Copy6" Width="50" Height="50" Source="/images/star.png" Canvas.Left="372" Canvas.Top="-580"/>
            <Image x:Name="star_Copy7" Width="50" Height="50" Source="/images/star.png" Canvas.Left="372" Canvas.Top="-798"/>
            <Image x:Name="star_Copy8" Width="50" Height="50" Source="/images/star.png" Canvas.Left="268" Canvas.Top="-882"/>
            <Image x:Name="star_Copy9" Width="50" Height="50" Source="/images/star.png" Canvas.Left="158" Canvas.Top="-982"/>
            <Image x:Name="star_Copy10" Width="50" Height="50" Source="/images/star.png" Canvas.Left="54" Canvas.Top="-1060"/>
</canvas>

然后你可以去后面的代码做剩下的事情##注意每个项目都是唯一的##

在游戏循环中,我声明了以下方法来检查碰撞检测

 collisionChecks();
 handleCollisions();

那么第一种方法中发生的事情是这样的:

  1. 可碰撞画布中的所有元素都被拉到一个列表中

  2. 为了节省检查甚至不在屏幕上的项目,我将它们除掉 通过说元素的顶部是否在屏幕上将其添加到 collisionEnabled List 不然算了。

    public void collisionChecks()
    {            
        List<UIElement> AllCollidables = Collidables.Children.ToList();
        collisionEnabled.Clear();
    
        foreach (UIElement item in AllCollidables)
        {
            if (Canvas.GetTop((Image)item) + canvasShift > 0)
                collisionEnabled.Add(item as Image);
        }
    }
    

现在我们可以处理符合碰撞条件的对象

  1. 第一个 foreach 循环检查播放器和碰撞启用列表中的每个对象之间是否存在碰撞。

  2. 如果发生碰撞,它会被添加到 Collisions to handle 列表中

  3. 一旦我们拥有所有实际发生碰撞的对象,我们就可以根据它们的名称单独处理它们以确定如何处理它们。例如,在这段代码中,我说如果名称包含“star”,那么让它消失,很快它也会播放声音。但我也可以说,如果它包含“火箭”,那么将玩家状态更改为飞行或其他任何状态。

    public void handleCollisions()
    {
    
        Rect player = new Rect();
        player.X = Canvas.GetLeft(Player);
        player.Y = Canvas.GetTop(Player);
        player.Height = Player.Height;
        player.Width = Player.Width;
    
    
        foreach (Image item in collisionEnabled)
        {
            if (item.Visibility == Visibility.Visible)
            {
                Rect obj = new Rect();
                obj.X = Canvas.GetLeft(item);
                obj.Y = Canvas.GetTop(item) + canvasShift;
                obj.Height = item.Height;
                obj.Width = item.Width;
    
                obj.Intersect(player);
    
                if (!obj.IsEmpty)
                {
                    collisionsToHandle.Add(item);
                }
            }
        }
        foreach (Image item in collisionsToHandle)
        {                
            item.Visibility = Visibility.Collapsed;
    
            if (item.Name.ToLower().Contains("star"))
            {
                score += 100;
            }
        }
        collisionsToHandle.Clear();
        collisionEnabled.Clear();}
    

这不是实现碰撞检测系统的最简洁的方法,但它是我想出的最小和最快的方法。希望这可以帮助任何对 XAML 对象的简单 2D 碰撞检测感兴趣的人

【讨论】:

  • 你能链接到你使用的物理助手吗?
  • 不,它被称为物理助手。
【解决方案3】:

Physics Helper XAML (http://physicshelperxaml.codeplex.com) 表示这是对原始物理助手 (https://physicshelper.codeplex.com) 的重写,可以通过 Blend Behaviors API 用于 Silverlight(浏览器和 WindowsPhone)。

据我所知,新版本不使用行为,因为它最初移植到早期版本的 WinRT (http://www.spritehand.com/2011/09/physics-helper-xaml-for-metro-winrt.html?m=1),当时还没有类似的功能可用。它的作者认为新的代码库更简单(并且可以将其移植到 Silverlight 以用于浏览器和 Windows Phone)

另一个是 https://xamlphysics.codeplex.com,它也是 Farseer Physics 引擎的包装器,似乎使用 Attached Properties 将物理属性附加到对象(如果我构建此类功能,我也会使用这种模式)

不确定您是否也可以将此类属性添加到容器中,例如在父级中设置重力以影响其所有子级

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-14
    • 2015-10-05
    • 2013-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    相关资源
    最近更新 更多