Ejemplo n.º 1
0
void plDistributor::ISetAngProbCosines() const
{
    if( fAngProbHi == fAngProbLo )
        return;

    float maxAng, minAng;
    if( fAngProbHi > fAngProbLo )
    {
        maxAng = hsDegreesToRadians(fAngProbHi);
        minAng = hsDegreesToRadians(fAngProbLo);
    }
    else
    {
        maxAng = hsDegreesToRadians(fAngProbLo);
        minAng = hsDegreesToRadians(fAngProbHi);
    }

    float transAng = hsDegreesToRadians(fAngProbTrans);
    if( transAng > (maxAng - minAng) * 0.5f )
        transAng = (maxAng - minAng) * 0.5f;

    float transAngMax = maxAng < M_PI ? transAng : 0;
    float transAngMin = minAng > 0 ? transAng : 0;

    fCosAngProbHi = cos(minAng);
    fCosAngProbLo = cos(maxAng);
    fCosAngProbHiTrans = cos(minAng + transAngMin);
    fCosAngProbLoTrans = cos(maxAng - transAngMax);
}
Ejemplo n.º 2
0
void plObjectInVolumeAndFacingDetector::SetFacingTolerance(int degrees)
{
    fFacingTolerance = cos(hsDegreesToRadians(degrees));
}
Ejemplo n.º 3
0
void plDistributor::SetPolarRange(float deg) 
{ 
    fPolarRange = hsDegreesToRadians(deg); 
    fTanPolarRange = tan(fPolarRange); 
}
void plWalkingStrategy::ICheckForFalseGround()
{
    if (fGroundHit)
        return; // Already collided with "real" ground.

    // We need to check for the case where the avatar hasn't collided with "ground", but is colliding
    // with a few other objects so that he's not actually falling (wedged in between some slopes).
    // We do this by answering the following question (in 2d top-down space): "If you sort the contact 
    // normals by angle, is there a large enough gap between normals?"
    // 
    // If you think in terms of geometry, this means a collection of surfaces are all pushing on you.
    // If they're pushing from all sides, you have nowhere to go, and you won't fall. There needs to be
    // a gap, so that you're pushed out and have somewhere to fall. This is the same as finding a gap 
    // larger than 180 degrees between sorted normals.
    // 
    // The problem is that on top of that, the avatar needs enough force to shove him out that gap (he
    // has to overcome friction). I deal with that by making the threshold (360 - (180 - 60) = 240). I've
    // seen up to 220 reached in actual gameplay in a situation where we'd want this to take effect. 
    // This is the same running into 2 walls where the angle between them is 60.
    int i, j;
    const float threshold = hsDegreesToRadians(240.f);
    int numContacts = fContactNormals.GetCount() + fPrevSlidingNormals.GetCount();
    if (numContacts >= 2)
    {
        // For extra fun... PhysX will actually report some collisions every other frame, as though
        // we're bouncing back and forth between the two (or more) objects blocking us. So it's not
        // enough to look at this frame's collisions, we have to check previous frames too.
        hsTArray<float> fCollisionAngles;
        fCollisionAngles.SetCount(numContacts);
        int angleIdx = 0;
        for (i = 0; i < fContactNormals.GetCount(); i++, angleIdx++)
        {
            fCollisionAngles[angleIdx] = atan2(fContactNormals[i].fY, fContactNormals[i].fX);
        }
        for (i = 0; i < fPrevSlidingNormals.GetCount(); i++, angleIdx++)
        {
            fCollisionAngles[angleIdx] = atan2(fPrevSlidingNormals[i].fY, fPrevSlidingNormals[i].fX);
        }
        // numContacts is rarely larger than 6, so let's do a simple bubble sort.
        for (i = 0; i < numContacts; i++)
        {
            for (j = i + 1; j < numContacts; j++)
            {
                if (fCollisionAngles[i] > fCollisionAngles[j])
                {
                    float tempAngle = fCollisionAngles[i];
                    fCollisionAngles[i] = fCollisionAngles[j];
                    fCollisionAngles[j] = tempAngle;
                }
            }
        }
        // sorted, now we check.
        for (i = 1; i < numContacts; i++)
        {
            if (fCollisionAngles[i] - fCollisionAngles[i - 1] >= threshold)
                break;
        }
        if (i == numContacts)
        {
            // We got to the end. Check the last with the first and make your decision.
            if (!(fCollisionAngles[0] - fCollisionAngles[numContacts - 1] >= (threshold - 2 * M_PI)))
                fFalseGround = true;
        }
    }
}
Ejemplo n.º 5
0
void plInterMeshSmooth::SetAngle(float degs)
{
    fMinNormDot = cos(hsDegreesToRadians(degs));
}
Ejemplo n.º 6
0
bool plClickDragComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
    plLocation loc = node->GetLocation();
    plSceneObject *obj = node->GetSceneObject();
    
    plKey logicKey = fLogicModKeys[node];
    plLogicModifier *logic = plLogicModifier::ConvertNoRef(logicKey->GetObjectPtr());
    logic->fMyCursor = plCursorChangeMsg::kCursorOpen;

        // Create the detector
    plDetectorModifier *detector = nil;
    detector = new plPickingDetector;

    // Register the detector
    plKey detectorKey = hsgResMgr::ResMgr()->NewKey(IGetUniqueName(node), detector, loc);
    hsgResMgr::ResMgr()->AddViaNotify(detectorKey, new plObjRefMsg(obj->GetKey(), plRefMsg::kOnCreate, -1, plObjRefMsg::kModifier), plRefFlags::kActiveRef);

    // set up the axis anim controller
    
    plKey axisKey = fAxisKeys[node];
    plAxisAnimModifier* pAxis = plAxisAnimModifier::ConvertNoRef(axisKey->GetObjectPtr());
    // attach the animation controller to the animation objects:
    // find an animation controller:
    
    hsTArray<plKey> receivers;
    IGetReceivers(node, receivers);
    
    int i;
    for (i = 0; i < receivers.Count(); i++)
        pAxis->GetNotify()->AddReceiver(receivers[i]);

    pAxis->SetNotificationKey(logicKey);
    uint32_t count = node->NumAttachedComponents();
    bool bHasAnim = false;
    plAnimComponentBase* pAnim = nil;

    for (i = 0; i < count; i++)
    {
        plComponentBase *comp = node->GetAttachedComponent(i);
        if (comp->ClassID() == ANIM_COMP_CID || comp->ClassID() == ANIM_GROUP_COMP_CID)
        {
            pAnim = (plAnimComponentBase*)comp;
            break;
        }
    }
    if (!pAnim)
    {
        pErrMsg->Set(true, "WARNING", "Object %s has click-drag component attached but NO animation component!", ((INode*)node)->GetName()).Show();
        pErrMsg->Set(false);
    }
    else
    {
        if (fCompPB->GetInt(kClickDragUseX))
        {
            pAxis->SetXAnim( pAnim->GetModKey(node) );
        }   
        else // take out this else when we support multiple channels
        if (fCompPB->GetInt(kClickDragUseY))
        {
            pAxis->SetYAnim( pAnim->GetModKey(node) );
        }
        pAxis->SetAllOrNothing(fCompPB->GetInt(kClickDragAllOrNothing));

        // add callbacks for beginning and end of animation
        plEventCallbackMsg* pCall1 = new plEventCallbackMsg;
        pCall1->fEvent = kBegin;
        pCall1->fRepeats = -1;
        pCall1->AddReceiver(axisKey);
        
        plEventCallbackMsg* pCall2 = new plEventCallbackMsg;
        pCall2->fEvent = kEnd;
        pCall2->fRepeats = -1;
        pCall2->AddReceiver(axisKey);

        plAnimCmdMsg* pMsg = new plAnimCmdMsg;
        plString tempAnimName = pAnim->GetAnimName();
        if (tempAnimName.IsNull())
        {
            //pMsg->SetAnimName(ENTIRE_ANIMATION_NAME);
            pMsg->SetAnimName(pAnim->GetModKey(node)->GetName());
            pAxis->SetAnimLabel(ENTIRE_ANIMATION_NAME);
        }
        else
        {
            //pMsg->SetAnimName(tempAnimName);
            pMsg->SetAnimName(pAnim->GetModKey(node)->GetName());
            pAxis->SetAnimLabel(tempAnimName);
        }
        

        pMsg->SetCmd(plAnimCmdMsg::kAddCallbacks);
        pMsg->AddCallback(pCall1);
        pMsg->AddCallback(pCall2);

        hsRefCnt_SafeUnRef( pCall1 );
        hsRefCnt_SafeUnRef( pCall2 );

        pMsg->AddReceiver( pAnim->GetModKey(node) );
        plgDispatch::MsgSend(pMsg);
    }


    // is this a using a proxy primitive?
    plPickingDetector* det2 = nil;
    plKey det2Key  = nil;
    plMaxNode* pProxyNode = (plMaxNode*)fCompPB->GetINode(kClickDragProxy);
    
    if (pProxyNode && fCompPB->GetInt(kClickDragUseProxy))
    {
        
        // verify that there is a physical proxy attached to this scene object:
        uint32_t count = ((plMaxNodeBase*)pProxyNode)->NumAttachedComponents();
        bool bHasPhys = false;
//      for (uint32_t i = 0; i < count; i++)
        //      {
        //          plComponentBase *comp = ((plMaxNodeBase*)pProxyNode)->GetAttachedComponent(i);
        //          if (comp->ClassID() == Class_ID(0x11e81ee4, 0x36b81450))
        //          {
        //              bHasPhys = true;
        //              break;
        //          }
        //      }
        //      if (!bHasPhys)
        //      {
        //          pErrMsg->Set(true, "WARNING", "Object %s listed as draggable component proxy physical for %s but has NO physical component.\n  Please attach a proxyTerrain componet!\n Export will continue but this gadget will not function",pProxyNode->GetName(), ((INode*)node)->GetName()).Show();
        //          pErrMsg->Set(false);
        //      }
        

        if(pProxyNode->CanConvert())
        {
            det2 = new plPickingDetector;
            // Register the detector
            det2Key = hsgResMgr::ResMgr()->NewKey(IGetUniqueName(node), det2, loc);
            hsgResMgr::ResMgr()->AddViaNotify(det2Key, new plObjRefMsg(((plMaxNode*)pProxyNode)->GetSceneObject()->GetKey(), plRefMsg::kOnCreate, -1, plObjRefMsg::kModifier), plRefFlags::kActiveRef);
            hsgResMgr::ResMgr()->AddViaNotify(logicKey, new plObjRefMsg( det2Key, plRefMsg::kOnCreate, -1, plObjRefMsg::kModifier), plRefFlags::kActiveRef);
            det2->SetProxyKey(node->GetSceneObject()->GetKey());
        }
        else
        {
            pErrMsg->Set(true, "Unknown Error", "Invalid proxy physical detector set for draggable %s.", ((INode*)pProxyNode)->GetName()).Show();
            pErrMsg->Set(false);
            return false;
        }
    
    }



    // create and register the CONDITIONS for the DETECTOR's Logic Modifier
    plActivatorConditionalObject* activatorCond = new plActivatorConditionalObject;
    plKey activatorKey = hsgResMgr::ResMgr()->NewKey(IGetUniqueName(node), activatorCond, loc);

    // do we have a required region?
    plMaxNode* pProxyRegNode = (plMaxNode*)fCompPB->GetINode(kClickDragProxyRegion);
    if (pProxyRegNode)
    {
        // verify that there is a physical detector attached to this scene object:
        uint32_t count = ((plMaxNodeBase*)pProxyRegNode)->NumAttachedComponents();
        bool bHasPhys = false;
//      for (uint32_t i = 0; i < count; i++)
        //      {
        //          plComponentBase *comp = ((plMaxNodeBase*)pProxyRegNode)->GetAttachedComponent(i);
        //          if (comp->ClassID() == Class_ID(0x33b60376, 0x7e5163e0))
        //          {
        //              bHasPhys = true;
        //              break;
        //          }
        //      }
        //      if (!bHasPhys)
        //      {
        //          pErrMsg->Set(true, "WARNING", "Object %s listed as draggable component detector region for %s but has NO physical detector component!\n  Please attach a detector componet.\n Export will continue but this gadget will not function",((INode*)pProxyRegNode)->GetName(), ((INode*)node)->GetName()).Show();
        //          pErrMsg->Set(false);
        //      }
        

        if(pProxyRegNode->CanConvert())
        {
            // need a player in box condition here...
            // first a detector-any for the box
            plObjectInVolumeDetector* pCDet = new plObjectInVolumeDetector(plCollisionDetector::kTypeAny);
            plKey cDetKey = hsgResMgr::ResMgr()->NewKey(IGetUniqueName(node), pCDet, loc);
            hsgResMgr::ResMgr()->AddViaNotify(cDetKey, new plObjRefMsg(((plMaxNode*)pProxyRegNode)->GetSceneObject()->GetKey(), plRefMsg::kOnCreate, -1, plObjRefMsg::kModifier), plRefFlags::kActiveRef);
            pCDet->AddLogicObj(logicKey);
            // then an object-in-box condition for the logic mod
            plObjectInBoxConditionalObject* boxCond = new plObjectInBoxConditionalObject;
            plKey boxCondKey = hsgResMgr::ResMgr()->NewKey(IGetUniqueName(node), boxCond, loc);
            logic->AddCondition(boxCond);
        }
        else
        {       
            pErrMsg->Set(true, "Problem with region", "Can't convert region component on  %s.  This component will not be exported.\n", ((INode*)pProxyRegNode)->GetName()).Show();
            pErrMsg->Set(false);
            return false;
        }
    }
    else
    {
        pErrMsg->Set(true, "Must specify trigger region", "No required trigger region specified for click-drag component on %s.  This component will not be exported.\n", ((INode*)node)->GetName()).Show();
        pErrMsg->Set(false);
        return false;
    }


    // How do we feel about player facing
    plFacingConditionalObject* facingCond = new plFacingConditionalObject;
    facingCond->SetDirectional(fCompPB->GetInt(kClickDragDirectional));
    int deg = fCompPB->GetInt(kClickDragDegrees);
    if (deg > 180)
        deg = 180;
    float rad = hsDegreesToRadians(deg);
    facingCond->SetTolerance(cos(rad));
    plKey facingKey = hsgResMgr::ResMgr()->NewKey(IGetUniqueName(node), facingCond, loc);
    
    
    // link everything up:
    if (det2) // set up the remote detector (if any)
    {
        activatorCond->SetActivatorKey(det2Key);
        det2->AddLogicObj(logicKey);
    }
    else
    {
        detector->AddLogicObj(logicKey);     // send messages to this logic component
        activatorCond->SetActivatorKey(detectorKey); // Tells the activator condition to look for stimulus from the detector
    }
    logic->AddCondition(activatorCond); // add this activator condition
    logic->AddCondition(facingCond);
    logic->SetDisabled(fCompPB->GetInt(kClikDragEnabled) == 0);

    
    // If this is for the SceneViewer, set the local only flag since the read function will never be called
    if (plConvert::Instance().IsForSceneViewer())
        logic->SetLocalOnly(true);

    return true;
}