• flash中物体运动基础之七碰撞处理


    碰撞处理这是个很大的话题,要研究的东西太多了,就我所知,就as3而言它提供了三种方法来检测碰撞,它们是:

    hitTestPoint,hitTestObject,hitTest

    前两个方法是应用于显示对象上的,后面一个用于位图像素级的碰撞检测,具体使用方法帮助文档中有详细介绍的。

    关于位图的碰撞检测和更高级的碰撞检测在《Flash Actionscript 3.0 动画高级教程》中有详细介绍,有兴趣的可以看一下,这里只讨论规则形状的hitTestPoint方法。

    启动FlashDevelop,新建一个FlashIDE工程,新建一个Fla文件,创建一个MC,里面画上两根线条,线条要粗一些(原因稍后),将新建的MC拖入舞台,定义一个实例名称_roadBlock;

    再新建一个Ball类,定义vx,vy分别表示Ball的x,y方向的速度,再在Fla文件的库中新建一个Ball类的实例。

    新建一个Main类,作为Fla的文档类

    一。简单的碰撞检测

    简单碰撞检测,这里只是调用了hitTestPoint方法,主要代码如下:

       _ball.vy += GRAVITY;
       if (_roadBlock.hitTestPoint(_ball.x,_ball.y,true))
       {
        _ball.vy = 0;
       }
       _ball.y += _ball.vy;

    在EnterFrame事件中检测_roadBlock是否碰到_ball,_ball的注册点在其几何中心,这样检测时在球体速度为0之前实际上球体早已碰到了线条。如上。

    二。复杂一点的检测,精确一点的检测

    上面是检测的球体的中心不能满足需求,而现在要检测球体边缘的点。效果如下:

    要检测圆周上的点与障碍物的碰撞,先要取得圆周上的点,现在一直圆的半径和圆的坐标,则能取得圆周上的点。

    半径:r = _ball.width/2;

    圆周上的点:px=r*Math.cos(angle);py=r*Math.sin(angle);

    angle取值范围为0~2*Math.PI,当angle为0时,px=r,py=0;当angle=90时,px=0,py=r;......

    现在的问题是,究竟取圆周上的哪些点?

    实际上要取所有的点,关键是取点的精度,即angle的增量,设dt为angle增量:

    设dt=90,那么每一个EnterFrame需要做碰撞检测的只有圆周上的四个点,四个点中任一个碰到障碍物,即碰撞发生,设球体速度为0。

    设dt=30,那么每一个EnterFrame需要做碰撞检测的就有360/30=12个点,12个点种任意一个碰到障碍物,即碰撞发生,比前面检测的点更多了。

    设dt=1,那么每一个EnterFrame需要做碰撞检测的就有360个点。。。。。。

    测试中,虽然360个点,但对于准确的检测还是很大误差,那将dt设为更小如:0.001,0.00001那么这样点数为36000,3600000或更大,但dt越小会导致检测一周的点的时间变长,导致占用的cup时间会更多,要取一个适当的数才行。

       //每一个EnterFrame中要检测碰撞的次数

       private var precision:Number = 20;

       _ball.vy += GRAVITY;
       for (var i:int = 0; i < precision;i++ )
       {
        var x:Number = _ball.x+radius * Math.cos(360*i/precision);
        var y:Number = _ball.y+radius * Math.sin(360*i/precision);
        
        if (_roadBlock.hitTestPoint(x,y,true))
        {
         _ball.vy = 0;
        }
       }
       _ball.y += _ball.vy;

    同样是上面的代码,现在将障碍物中水平的那根线去掉,然后再检测会有不准确了,如下:

    这个原因何在?或许还得寻找更加准确的碰撞检测方法。

    三。检测碰撞的次数

    在每一次EnterFrame中调用下面的代码,这样能显示每一次EnterFrame发生时有多少个点被检测到已经碰撞了。调整precision的值,_count的值会变化。

     _count = 0;
       _ball.vy += GRAVITY;
       for (var i:int = 0; i < precision;i++ )
       {
        var x:Number = _ball.x+radius * Math.cos(360*i/precision);
        var y:Number = _ball.y+radius * Math.sin(360*i/precision);
        
        if (_roadBlock.hitTestPoint(x,y,true))
        {
         _ball.vy = 0;
         _count++;
        }
       }
       textField.text = "" + _count;
       _ball.y += _ball.vy;
       _ball.x += _ball.vx;

    为了更直观的看到碰撞的点,现在在每次碰撞时,根据所碰撞的点求出一个平均位置,来绘制一条线条,代码如下:

       _count = 0;
       var sumX:Number = 0;
       var sumY:Number = 0;
       _ball.vy += GRAVITY;
       for (var i:int = 0; i < precision;i++ )
       {
        var x:Number = _ball.x+radius * Math.cos(360*i/precision);
        var y:Number = _ball.y+radius * Math.sin(360*i/precision);
        
        if (_roadBlock.hitTestPoint(x,y,true))
        {
         _ball.vy = 0;
         sumX += x;
         sumY += y;
         _count++;
        }
        
       }
       if (_count>0)
       {
        x = sumX / _count;
        y = sumY / _count;
        lineMC.graphics.clear();
        lineMC.graphics.lineStyle(1);
        lineMC.graphics.moveTo(x, y);
        lineMC.graphics.lineTo(_ball.x, _ball.y);
       }
       textField.text = "" + _count;
       _ball.y += _ball.vy;
       _ball.x += _ball.vx;

    lineMC是Main类中新定义的一个MC,当有碰撞发生时用来绘制线条。效果如下:

    作者:ywxgod
    E-mail:给我发邮件
    出处:http://ywxgod.cnblogs.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    RESTful架构的设计误区
    CRUD的http请求方式
    RESTful API的安全性
    REST风格的原则
    REST架构风格理解
    ansible上手之认识Playbook
    ansible模块之file
    ansible模块之yum,yum_repository
    ansible模块之copy
    Pygame
  • 原文地址:https://www.cnblogs.com/ywxgod/p/1789335.html
Copyright © 2020-2023  润新知