[源码解读]Silverlight 4 中对不规则对象进行碰撞检测(在游戏中常使用的是否碰撞怪物边界等原理)
2011-04-25 14:04
597 查看
在以前的Silverlight中,有个HitTest方法可以用来完成碰撞的检测。
But,Older versions (pre 3.0) did have a HitTest method!
在Silverlight4中就不可以使用HitTest方法来完成了。那么我们要该怎么做?
下面我会解读一个国外的源代码,让大家了解怎么进行碰撞检测。
会使用到一个方法FindElementsInHostCoordinates,这个是用来替代没有HitTest来检测碰撞。
还有一个方法作为基础就是Intersect方法,用来确立相交的范围。
DEMO:http://www.andybeaulieu.com/silverlight/2.0/hittest/clientbin/testpage.html
原博客地址(可下载源码):http://www.andybeaulieu.com/Default.aspx?tabid=67&EntryID=95
碰撞原理:
我们把不规则的两个元素用矩形框来框起来,表示最大的范围,当两个矩形框想碰撞时,我们取出相交的范围,用Intersect方法,但是矩形相交不代表实际的对象是相交的,所以我们还需要遍历交集范围内的每一个点像素,看相交的两个物体是否都在这个点像素上,用FindElementsInHostCoordinates,如果都在,则表示碰撞。
代码展示(我已加上中文注释,根据原理加上注释可以和方便的理解下面代码):
代码很少,但是当你理解了碰撞的原理和使用的核心方法,只要你有想法,都可以做出很复杂的碰撞检测。
But,Older versions (pre 3.0) did have a HitTest method!
在Silverlight4中就不可以使用HitTest方法来完成了。那么我们要该怎么做?
下面我会解读一个国外的源代码,让大家了解怎么进行碰撞检测。
会使用到一个方法FindElementsInHostCoordinates,这个是用来替代没有HitTest来检测碰撞。
还有一个方法作为基础就是Intersect方法,用来确立相交的范围。
DEMO:http://www.andybeaulieu.com/silverlight/2.0/hittest/clientbin/testpage.html
原博客地址(可下载源码):http://www.andybeaulieu.com/Default.aspx?tabid=67&EntryID=95
碰撞原理:
我们把不规则的两个元素用矩形框来框起来,表示最大的范围,当两个矩形框想碰撞时,我们取出相交的范围,用Intersect方法,但是矩形相交不代表实际的对象是相交的,所以我们还需要遍历交集范围内的每一个点像素,看相交的两个物体是否都在这个点像素上,用FindElementsInHostCoordinates,如果都在,则表示碰撞。
代码展示(我已加上中文注释,根据原理加上注释可以和方便的理解下面代码):
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; namespace HitTest { public partial class Page : UserControl { public Page() { InitializeComponent(); } private void UserControl_MouseMove(object sender, MouseEventArgs e) { Point pt = e.GetPosition(cnvHitTest); ship.SetValue(Canvas.LeftProperty, pt.X); ship.SetValue(Canvas.TopProperty, pt.Y); // lets get pointers to the actual UI elements we care about: // 获得飞船的Path坐标 Path shipShell = ship.FindName("ShipShell") as Path; // 获得陨石的path坐标 Path cnvAsteroid = asteroid.FindName("asteroidBig") as Path; // 检测碰撞 // ship 飞船的用户控件(矩形大范围) // shipShell 飞船的外壳Path坐标 // asteroid 陨石的用户控件(矩形大范围) // cnvAsteroid 陨石的外壳Path坐标 if (CheckCollision(ship, shipShell, asteroid, cnvAsteroid)) txtStatus.Text = "Collision!"; else txtStatus.Text = "no collision"; } private bool CheckCollision(FrameworkElement control1, FrameworkElement controlElem1, FrameworkElement control2, FrameworkElement controlElem2) { // first see if sprite rectangles collide // 用户控件使用的是Canvas,我们现在要把用户控件的Canvas转换成矩形表示 // UserControlBounds()用于转换为矩形来表示编辑 // rect1 为飞船矩形 // rect2 为陨石矩形 // control1 为飞船用户控件(矩形) // control2 为运行用户控件(矩形) Rect rect1 = UserControlBounds(control1); Rect rect2 = UserControlBounds(control2); // Intersect(Rect) 查找当前矩形和指定矩形的交集,并将结果存储为当前矩形。 rect1.Intersect(rect2); if (rect1 == Rect.Empty) // 为空为矩形没有交集,那么飞船和陨石没有碰撞 { // no collision - GET OUT! return false; } else // 不为空,有交集,返回交集,但不表示飞船就和陨石有碰撞,需要进行更细致的判断 { bool bCollision = false; // 是否碰撞 Point ptCheck = new Point(); // 点检测 // now we do a more accurate pixel hit test // 进行精确的点测试 // 以行为单位,循环扫描矩形内的每个点 // 在这里rect1为交集的矩形 for (int x = Convert.ToInt32(rect1.X); x < Convert.ToInt32(rect1.X + rect1.Width); x++) { // 遍历行中的每个点 for (int y = Convert.ToInt32(rect1.Y); y < Convert.ToInt32(rect1.Y + rect1.Height); y++) { // 行增加 //设置检测点的坐标 ptCheck.X = x; ptCheck.Y = y; // 用FindElementsInHostCoordinates方法找出飞船用户控件中在点ptCheck上的element元素 List<UIElement> hits = System.Windows.Media.VisualTreeHelper.FindElementsInHostCoordinates(ptCheck, control1) as List<UIElement>; // controlElem1 为实际的飞船 if (hits.Contains(controlElem1)) // hits里面装的是飞船用户控件中所有在点ptCheck中的元素,看实际的飞船是否在其中 { // we have a hit on the first control elem, now see if the second elem has a similar hit // 我们检测的飞船,还需要看点是否也在陨石中 // 同上面获取hits的方法,找出陨石控件中在点ptCheck上的element元素 List<UIElement> hits2 = System.Windows.Media.VisualTreeHelper.FindElementsInHostCoordinates(ptCheck, control2) as List<UIElement>; // controlElem2 为实际的陨石 if (hits2.Contains(controlElem2)) // hits2里面装的是陨石用户控件中所有在点ptCheck中的元素,看实际的陨石是否在其中 { // 够满足条件,是碰撞 bCollision = true; break; } } } if (bCollision) break; } return bCollision; } } public Rect UserControlBounds(FrameworkElement control) { Point ptTopLeft = new Point(Convert.ToDouble(control.GetValue(Canvas.LeftProperty)), Convert.ToDouble(control.GetValue(Canvas.TopProperty))); Point ptBottomRight = new Point(Convert.ToDouble(control.GetValue(Canvas.LeftProperty)) + control.Width, Convert.ToDouble(control.GetValue(Canvas.TopProperty)) + control.Height); return new Rect(ptTopLeft, ptBottomRight); } } }
代码很少,但是当你理解了碰撞的原理和使用的核心方法,只要你有想法,都可以做出很复杂的碰撞检测。
相关文章推荐
- 处理模型——对小而快的对象使用Ray-Traced进行碰撞检测
- Cocos2d-x碰撞检测原理与英雄要打死怪物--之游戏开发《赵云要格斗》(7)
- Cocos2d-x碰撞检测原理与英雄要打死怪物--之游戏开发《赵云要格斗》(7)
- 向量几何在游戏编程中的使用【3】2-D边界碰撞检测
- 向量几何在游戏编程中的使用3-2-D边界碰撞检测
- 使用Faster-Rcnn进行目标检测的原理
- Android游戏开发之检测游戏碰撞的原理实现(九)
- Android游戏开发之检测游戏碰撞的原理实现(四)
- Silverlight Page Turning Made Simple [silverlight翻页实例 源码 原理 如何使用]
- 使用物理引擎进行碰撞检测
- (译)碰撞检测和收集物品:如何使用cocos2d制作基于tiled地图的游戏:第二部分
- 对象分割过程中,对没有赋label值的边界使用邻域查找的方式进行标记(2)
- 使用Faster-Rcnn进行目标检测的原理
- Cocos2d-x3.2总结:使用物理引擎进行碰撞检测
- [译]在Tiled Map中使用碰撞检测(一) 创建基于Tiled Map的游戏
- cocos2d-x游戏开发 跑酷(八) 对象管理 碰撞检测
- [译]在Tiled Map中使用碰撞检测(一) 创建基于Tiled Map的游戏
- 使用Faster-Rcnn进行目标检测的原理
- (译)碰撞检测和收集物品:如何使用cocos2d制作基于tiled地图的游戏:第二部分
- (译)碰撞检测和收集物品:如何使用cocos2d制作基于tiled地图的游戏:第二部分