XAML碰撞检测

本文关键字:碰撞检测 XAML | 更新日期: 2023-09-27 18:00:40

我正在开发一款Windows Phone游戏,它在没有碰撞检测的情况下进展顺利。

有没有一种简单的方法可以让任何人建议检测两个XAML对象是否在彼此之上?

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

有了所有很酷的XAML功能,比如触发器、行为等等,我想可能有一种更简单的方法。然而,搜索结果很少。

有什么想法吗?最简单的就是我要找的东西。没有什么疯狂的需要。当我的玩家与一个物体碰撞时,它就消失了。

我不知道这是否有什么不同,但我所有的物体都是图像。

XAML碰撞检测

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

你可以试试物理助手框架:

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/

非常棒!

所以我安装了Physics helper,但上面提供的助手不适用于任何经过mango构建的windows手机。所以我找到了Physics Helper XAML,它不是一个安装文件,在可预见的未来必须有糟糕的文档才能使用它。

所以我创建了自己的XAML碰撞检测系统。它很简单,做我需要的事,而且速度很快。

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

首先,我创建了我的嵌套画布,其中包含了我希望成为可压缩的项目

<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列表,否则忘记它。

    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循环检查玩家和collisionEnabled列表中的每个对象之间是否存在冲突。

  2. 如果发生冲突,它将被添加到冲突处理列表中

  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碰撞检测感兴趣的人

物理助手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物理引擎的包装器,似乎使用附加属性将物理属性附加到对象(如果我构建了这样的功能,我也会使用这种模式)

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