zoukankan      html  css  js  c++  java
  • nape.dynamics.InteractionFilter

    (转载http://tomyail.com/blog/1123

    Nape定义了三种交互方式:

    • Collision(碰撞)
    • Sensor(感应)
    • Fluid(浮力)

    默认情况下两个物体只会发生Collision交互,另外的两种交互需要设置Shape的sensorEnabled 和fluidEnabled 来手动开启.

    如果一个Shape的这三种交互都是开启的,那么将只处理优先级最高的.

    交互的优先级:Sensor>Fluid>Collision.

    也就是说当三种交互都允许时,实际上只检测Sensor交互.

    控制交互的两种方式:

    1. InteractionFilters
    2. InteractionGroups

    InteractionFilters

    说明:

    所有的Shape类型都有一个filter属性,这个属性是InteractionFilter类型,通过控制filter的group和mask(掩码)来过滤不必要的交互

    过滤规则:

    当交互对象A的group和其被交互对象B的mask做按位和操作,(无论A和B对象是否互换)如果结果是0说明不交互,否则发生交互.

    默认情况下

    group都是1,二进制是00…01.

    mask是-1,二进制是11…11.

    所以默认下任意两个对象都会发生碰撞,因为它们的按位和非0

    先来一个简单的demo(小球默认能和下面的木板发生碰撞,点击右边的按钮可以切换小球是否和木板发生碰撞):

    filter版本小球碰撞的源码:

    private function testSimpleFilter():void
            {
                
                var ball:Body = createCircleBody(BodyType.DYNAMIC, 60, 40, 30);
                ball.shapes.at(0).material = new Material(Number.POSITIVE_INFINITY);
                var box:Body = createRectBody(BodyType.KINEMATIC, 110, 150, 200, 20);
                var btn:PushButton = new PushButton(this, 400, 100, box.shapes.at(0).filter.collisionMask.toString(2), clickCallback);
                btn.width = 200;
                function clickCallback(e:MouseEvent):void
                {
                    box.shapes.at(0).filter.collisionMask = ~box.shapes.at(0).filter.collisionMask;
                    btn.label = box.shapes.at(0).filter.collisionMask.toString(2);
                }
            }
    使用InteractionFilters的一般思路是

    1:首先为需要过滤的对象分组,我们可以将它们抽象成A,B,C组之类的.

    2:建立一张含有A,B,C的表格,看个人爱好决定横行表头是group,纵行表头是mask或者横行表头是mask,纵行表头是group.

    3:然后为这些组的group表头设定值,这里分group有一个原则就是所有group的按位和操作必须是0(后面会演示如果不这么做会出现什么情况),最简单的方式就是依次按2的整数幂次方为它们编号.

    4:按照给定的规则分别标记两两对象的是否可以交互.

    5:计算对应的mask.

    举个例子:我们想表示三组对象之间的碰撞关系:

    0表示不碰撞(按位和=0),1表示碰撞(按位和!=0)
      Triangle(mask) Rect(mask) Circle(mask)
    Triangle(group) 0(× 1 1
    Rect(group) 1( 1 0(×)
    Circle(group) 1 0× 0×

    定义了三个组,按照1,2规则建立一张表格,左边的假定是group

    然后我们给group分配值,按照规则三我们假定

    Triangle的group是2^0 >>001;

    Rect的group是2^1 >>010;

    Circle的group是2^2 >>100;

    结合上表就能依次计算出:

    Triangle的mask是110也就是十进制的6;(观察第一列:只有110和001按位和0,和010按位和非0,和100按位和非0,下同)

    Rect的mask是011也就是十进制的3;

    Circle的mask是001也就是十进制的1;

    结果如下:

    控制三组对象碰撞关系的filter版本源码:

    private function testMultiFilter():void
            {
                
                var triangle1:Body = createRegular(BodyType.DYNAMIC,100,20,40,3);
                var triangle2:Body = createRegular(BodyType.DYNAMIC,500,20,60,3);
                
                triangle1.shapes.at(0).filter.collisionGroup = 1;
                triangle2.shapes.at(0).filter.collisionGroup = 1;
                
                triangle1.shapes.at(0).filter.collisionMask = ~1;
                triangle2.shapes.at(0).filter.collisionMask = ~1;
                
                var rect1:Body = createRectBody(BodyType.DYNAMIC,200,50,120,40);
                var rect2:Body = createRectBody(BodyType.DYNAMIC,550,50,50,50);
                
                rect1.shapes.at(0).filter.collisionGroup = 2;
                rect2.shapes.at(0).filter.collisionGroup = 2;
                
                rect1.shapes.at(0).filter.collisionMask = ~4;
                rect2.shapes.at(0).filter.collisionMask = ~4;
                
                var cirCle1:Body = createCircleBody(BodyType.DYNAMIC,300,100,40);;
                var cirCle2:Body = createCircleBody(BodyType.DYNAMIC,420,100,80);;
                
                cirCle1.shapes.at(0).filter.collisionGroup = 4;
                cirCle2.shapes.at(0).filter.collisionGroup = 4;
                
                cirCle1.shapes.at(0).filter.collisionMask = ~(4 | 2);
                cirCle2.shapes.at(0).filter.collisionMask = ~(4 | 2);
            }

    所有group的按位和操作必须是0,如果不是会怎么样呢?做个实验就知道了.

    我们假定

    Triangle的group是001;

    Rect的group是011;

    Circle的group是101;

    那么对于第一列能得出Triangle的mask是110.

    但是对于第二列

    第二列第一行能确定??1

    第二列第二行能确定?11

    第二列第三行需要101,但是101和?11都是互斥的,所以认定这个group组合不合法.

    mask的快捷计算方式:

    这个方法比较笨拙,如果对位操作比较熟悉,可以使用nape作者推荐的计算mask的方法:

    对所有不和指定组发生交互的组的group取或(|)操作,并且将得到的结果按位取反(~).

    比如:

    A不和A发生碰撞那么计算掩码的直接表达式就是

    maskA = ~(groupA) = 110;

    C不和BC碰撞

    maskC = ~(groupB|groupC) = ~(010|100) = ~(110) = 001;

  • 相关阅读:
    Algs4-1.3.37Josephus问题
    Algs4-1.3.35随机队列
    Algs4-1.3.33一个双向队列Deque的可变长环形数组实现
    Algs4-1.3.34随机背包
    Algs4-1.3.33一个双向队列Deque-双向链表实现
    Algs4-1.3.32链表实现Stack和Queue的合体Steque
    Algs4-1.3.31实现双向链表
    Algs4-1.3.30反转链表
    C语言多级指针
    spring mvc@ModelAttribute与@SessionAttributes的执行流程
  • 原文地址:https://www.cnblogs.com/ddw1997/p/3167074.html
Copyright © 2011-2022 走看看