void MyExtendedUserDataListener::contactPointAddedCallback( hkpContactPointAddedEvent& event ) { // // Read the shape key hierarchy -- this is done identically for both Psi and Toi contact points. // hkpShapeKey shapeKey; { // This is the body to which the listener is attached. hkpEntity* body = event.m_callbackFiredFrom; // Extended user data only works when you use the default hkpSimpleConstraintContactMgr. // The function below will assert otherwise. // The atom caches information on how many extended user datas we store for each body. // Each body stores its data independently. const int numDatas = event.getNumExtendedUserDatas(event.m_callbackFiredFrom); // Now we can read the data. // The first user data stores the hkpShapeKey of the bottom most hkpCdBody in the shape hierarchy, // the next one stores hkpShapeKey of its parent, and so on, till we store '-1' as the hkpShapeKey // of the root collidable, or we run out of extended user data slots, in which case only a part // of the hierarchy is stored. // // In this demo we expect to have: // extendedUserDatas[0] in the [0,7] range -- this is the hkpShapeKey of one of the 8 transformed sphere shapes grouped under a hkpListShape // extendedUserDatas[1] equal -1 -- this is the root hkpListShape, with no parent, and therefore no hkpShapeKey // // Note that we only have two levels of hierarchy, while our shape is composed of hkpListShape->hkpConvexTransformShape->hkpSphereShape. // That's because hkpConvexTransform/TranslateShapes don't create a corresponding hkpCdBody during collision detection. // Note that the above is not the case for the deprecated hkpTransformShape. hkInplaceArray<hkpContactPointProperties::UserData,8> data; data.setSize(numDatas); event.getExtendedUserDatas(body, data.begin(), numDatas); // Let us store our custom contact point id. Let's store it in the last data slot to avoid overwriting the hkpShapeKey hierarchy. // We know we have enough room, as we set entity->m_numUserDatasInContactPointProperties = 3 which is more that the max hierarchy depth for our shape. data[numDatas-1] = m_uniqueIdCounter++; // And write back all datas event.setExtendedUserDatas(body, data.begin(), numDatas); // Get the hkpShapeKey shapeKey = data[0]; } // Sample demo structure holding history about callbacks triggered for this contact point. { ContactPointInfo& info = m_contactInfos.expandOne(); new (&info) ContactPointInfo(); HK_ASSERT2(0xad7853aa, m_contactInfos.getSize() == m_uniqueIdCounter, "Unique ID is not in synch with m_contactInfos array."); info.m_type = event.isToi() ? ContactPointInfo::TOI : ContactPointInfo::PSI; info.m_added = true; info.m_key = int(shapeKey); } // By setting the ProcessContactCallbackDelay to 0 we will receive callbacks for // any collisions processed for this body every frame (simulation step), i.e. the delay between // any such callbacks is 0 frames. // If you wish to only be notified every N frames simply set the delay to be N-1. // The default is 65536, i.e. (for practical purpose) once for the first collision only, until // the bodies separate to outside the collision tolerance. event.m_callbackFiredFrom->setProcessContactCallbackDelay(0); }