void EntityLODComponent::UpdateLODLevel(int newLevel) { if (m_iCurrentLevel==newLevel) { return; } // change the mesh and the animation config used int oldLevel = m_iCurrentLevel; VLODLevelInfo &newLODInfo = GetLevelInfo(newLevel); m_iCurrentLevel=newLevel; m_pOwner->SetMesh(newLODInfo.m_spMesh); m_pOwner->SetAnimConfig(newLODInfo.m_spAnimConfig); // synchronize animation tracks of both LODs if (oldLevel>=0 && oldLevel<m_iLevelCount) { VLODLevelInfo &oldLODInfo = GetLevelInfo(oldLevel); IVisAnimResultGenerator_cl* oldLODAnimInput = oldLODInfo.m_spAnimConfig->GetFinalResult()->GetSkeletalAnimInput(); float currAnimTime = 0.0f; if ( oldLODAnimInput->IsOfType( V_RUNTIME_CLASS(VisSkeletalAnimControl_cl) ) ) { VisSkeletalAnimControl_cl* oldLODAanimController = static_cast< VisSkeletalAnimControl_cl* >( oldLODAnimInput ); currAnimTime = oldLODAanimController->GetCurrentSequenceTime(); } IVisAnimResultGenerator_cl* newLODAnimInput = newLODInfo.m_spAnimConfig->GetFinalResult()->GetSkeletalAnimInput(); if ( newLODAnimInput->IsOfType( V_RUNTIME_CLASS(VisSkeletalAnimControl_cl) ) ) { VisSkeletalAnimControl_cl* newLODAanimController = static_cast< VisSkeletalAnimControl_cl* >( newLODAnimInput ); newLODAanimController->SetCurrentSequenceTime( currAnimTime ); } } }
BOOL VBlobShadow::CanAttachToObject(VisTypedEngineObject_cl *pObject, VString &sErrorMsgOut) { if (!IVObjectComponent::CanAttachToObject(pObject, sErrorMsgOut)) return FALSE; if ((!pObject->IsOfType(V_RUNTIME_CLASS(VisObject3D_cl))) && (!pObject->IsOfType(V_RUNTIME_CLASS(VisStaticMeshInstance_cl)))) { sErrorMsgOut = "Component can only be added to instances of VisObject3D_cl and VisStaticMeshInstance_cl or derived classes."; return FALSE; } return TRUE; }
void RPG_Pickup::CheckCharacterContact() { VArray<RPG_Character*> const& characters = RPG_GameManager::s_instance.GetCharacters(); hkvVec3 const& currentPosition = GetPosition(); for(int index = 0; index < characters.GetSize(); ++index) { RPG_Character* character = characters.GetAt(index); // only target players if(!character->IsOfType(V_RUNTIME_CLASS(RPG_PlayerCharacter))) { continue; } hkvVec3 const& targetPosition = character->GetPosition(); float currentRangeSquared = (currentPosition - targetPosition).getLengthSquared(); if(currentRangeSquared <= m_pickupRadius * m_pickupRadius) { // call OnPickup for subclasses OnPickup(character); // play the pickup effect CreateEffect(PKFX_Pickup, GetPosition(), GetOrientation()); // setup this object for deletion DisposeObject(); } } }
BOOL VTimeOfDayComponent::CanAttachToObject(VisTypedEngineObject_cl *pObject, VString &sErrorMsgOut) { if (pObject->IsOfType(V_RUNTIME_CLASS(VisObject3D_cl))) return TRUE; return FALSE; }
void VRendererNodeCommon::UpdateTimeOfDay() { // Update the active sky. IVSky* pSky = m_spSky; if (pSky == NULL) { pSky = Vision::World.GetActiveSky(); } if (pSky != NULL) { pSky->Tick(0); } // Update Time Of Day handler. IVTimeOfDay* pTimeOfDayInterface = Vision::Renderer.GetTimeOfDayHandler(); if (pTimeOfDayInterface != NULL) { VASSERT_MSG(pTimeOfDayInterface->IsOfType(V_RUNTIME_CLASS(VTimeOfDay)), "Incompatible time of day handler installed - has to be VTimeOfDay or a subclass of it!"); VTimeOfDay* pTimeOfDay = vstatic_cast<VTimeOfDay*>(pTimeOfDayInterface); pTimeOfDay->UpdateFogParameters(); VColorRef vAmbientColor = pTimeOfDay->GetAmbientColor(); Vision::Renderer.SetGlobalAmbientColor(vAmbientColor.ToFloat().getAsVec4(1.0f)); } else { // Set the default global ambient color. Vision::Renderer.SetGlobalAmbientColor(Vision::Renderer.GetDefaultGlobalAmbientColor()); } }
/// Checks if this is a valid entity for triggering. bool RPG_Trigger::IsValidEntity(VisBaseEntity_cl* entity) const { if(!entity) { return false; } // make sure this entity isn't Entering again before leaving. if(m_insideEntities.Find(entity) > -1) { //VASSERT_MSG(false, "RPG_Trigger::IsValidEntity - Entity is trying to Enter more than once before Leaving!"); return false; } bool canTrigger = false; if(m_acceptOnlyPlayers) { // make sure this is a player if(entity->Components().GetComponentOfBaseType(V_RUNTIME_CLASS(RPG_PlayerControllerComponent))) { canTrigger = true; } } else { // go ahead if we have no restrictions canTrigger = true; } return canTrigger; }
void RPG_GameManager::OnAfterSceneLoaded() { RPG_RendererUtil::StoreViewParams(m_storedViewParams); // Set up game view params RPG_ViewParams viewParams = m_storedViewParams; { viewParams.m_projectionType = VIS_PROJECTIONTYPE_PERSPECTIVE; viewParams.m_nearClip = 50.f; viewParams.m_farClip = 2500.f; viewParams.m_fovX = 0.f; viewParams.m_fovY = 50.f; } RPG_RendererUtil::LoadViewParams(viewParams); // Local player VisBaseEntity_cl* playerEntity = SpawnPlayer("Prefabs\\Demo_Player_Hero.vprefab"); if(playerEntity) { RPG_PlayerControllerComponent *const playerController = static_cast<RPG_PlayerControllerComponent*> (playerEntity->Components().GetComponentOfBaseType(V_RUNTIME_CLASS(RPG_PlayerControllerComponent))); VASSERT(playerController); if(playerController) { RPG_PlayerUI::s_instance.SetController(playerController); } } }
void VTimeOfDayComponent::SetOwner(VisTypedEngineObject_cl *pOwner) { IVObjectComponent::SetOwner(pOwner); m_bIsLightClass = pOwner!=NULL && pOwner->IsOfType(V_RUNTIME_CLASS(VisLightSource_cl)); if (m_bIsLightClass) m_iColor = ((VisLightSource_cl*)pOwner)->GetColor(); }
BOOL VPrefab::Instantiate(VPrefabInstanceInfo &info) { EnsureLoaded(); if (!IsLoaded()) return FALSE; // serialize from memory block (class VPrefabShapesArchive provides with transformation) VMemBlockWrapperStream inStream(m_BinaryBlock.GetBuffer(), m_iSize); VPrefabShapesArchive ar(&inStream, info); ar.SetLoadingVersion(m_Header.m_iArchiveVersion); if (info.m_bOutputInstances) info.m_Instances.EnsureSize(m_Header.m_iRootObjectCount); info.m_iInstanceCount = m_Header.m_iRootObjectCount; for (int i=0;i<m_Header.m_iRootObjectCount;i++) { VTypedObject *pObj = ar.ReadObject(NULL); if (info.m_bOutputInstances) info.m_Instances[i] = pObj; if (info.m_pParentObject!=NULL && pObj!=NULL && pObj->IsOfType(V_RUNTIME_CLASS(VisObject3D_cl))) { VisObject3D_cl *pObj3D = (VisObject3D_cl *)pObj; if (pObj3D->GetParent()==NULL) // this is how we identify the root elements pObj3D->AttachToParent(info.m_pParentObject); } } ar.Close(); return TRUE; }
VisBaseEntity_cl* MyGameManager::SpawnPlayer(const VString& prefabName, hkvVec3 const& position, hkvVec3 const& orientation) { VisBaseEntity_cl* playerEntity = CreateEntityFromPrefab(prefabName, position, orientation); playerEntity->InitFunction(); if(playerEntity) { PlayerComponent *const playerController = static_cast<PlayerComponent*> (playerEntity->Components().GetComponentOfBaseType(V_RUNTIME_CLASS(PlayerComponent))); //VASSERT(playerController); if(playerController) { spGUIContext = new VGUIMainContext(NULL); // Create a GUI context mDialog = new PlayerDialog(playerController); mDialog->InitDialog(spGUIContext, NULL, NULL); spGUIContext->ShowDialog(mDialog); spGUIContext->SetActivate(true); } m_playerEntity = playerEntity->GetWeakReference(); //Vision::Message.Add(1, "Spawn"); } return playerEntity; }
// ---------------------------------------------------------------------------- void vHavokChainAnimation::CommonInit() { CommonDeinit(); if (!m_pOwner || !m_pOwner->IsOfType(V_RUNTIME_CLASS(VisBaseEntity_cl))) return; Vision::Callbacks.OnUpdateSceneFinished += this; m_pOwnerEntity = static_cast<VisBaseEntity_cl*>(m_pOwner); VisAnimConfig_cl *pAnimConfig = m_pOwnerEntity->GetAnimConfig(); // If there is no AnimConfig, but we can get a skeleton, create the AnimConfig. if (!pAnimConfig) { VDynamicMesh *pMesh = m_pOwnerEntity->GetMesh(); VisSkeleton_cl *pSkeleton = pMesh ? pMesh->GetSkeleton() : NULL; if (pSkeleton) { VisAnimFinalSkeletalResult_cl* pFinalSkeletalResult; pAnimConfig = VisAnimConfig_cl::CreateSkeletalConfig(pMesh, &pFinalSkeletalResult); m_pOwnerEntity->SetAnimConfig(pAnimConfig); } } }
///< Spawn the Ai Character and perform any setup we need to of them. void RPG_AiSpawnPoint::OnSpawn() { // only spawn if we haven't already. @todo: add support for spawning waves of characters. if(m_spawned) { return; } m_spawned = true; bool success = false; if(!m_prefabName.IsEmpty()) { VisBaseEntity_cl* entity = RPG_GameManager::s_instance.CreateEntityFromPrefab(m_prefabName, GetPosition(), GetOrientation()); if(entity) { if(entity->IsOfType(V_RUNTIME_CLASS(RPG_Character))) { m_character = static_cast<RPG_Character*>(entity); } success = true; } } else if(!m_spawnScript.IsEmpty()) { VisBaseEntity_cl* entity = RPG_GameManager::s_instance.CreateEntityFromScript(m_spawnScript, GetPosition(), GetOrientation()); VASSERT(entity); if(entity) { if(entity->IsOfType(V_RUNTIME_CLASS(RPG_Character))) { m_character = static_cast<RPG_Character*>(entity); } success = true; } } if(!success) { hkvLog::Warning("Ai Spawner has no Prefab defined, and no valid Script definition!"); } }
void PlayerUIDialog::ContinueMeleeAttack(RPG_Character* characterEntity, RPG_DamageableEntity * const targetEntity) { VASSERT(characterEntity); const bool hitHighlightable = targetEntity->Components().GetComponentOfBaseType(V_RUNTIME_CLASS(RPG_HighlightableComponent)); const bool hitAttackable = targetEntity->Components().GetComponentOfBaseType(V_RUNTIME_CLASS(RPG_AttackableComponent)); //@debug: test log output //Vision::Error.Warning(hitEntity->GetMesh()->GetFilename()); if (hitHighlightable || hitAttackable) { if (hitHighlightable) //"(RPG) Highlightable" { //Vision::Error.Warning("(RPG) Highlightable"); #ifdef _DEBUG if (m_debugUI) { Vision::Message.DrawMessage3D("(RPG) Highlightable", targetEntity->GetPosition()); } #endif } if (hitAttackable) //"(RPG) Attackable" { // if player's holding down primary action input on an existing attack action, this sets its continue flag to true. if (characterEntity->GetActionHandler().IsPerformingAction(AT_MeleeAttack)) { characterEntity->GetActionHandler().SetActiveActionFlags(1); } #ifdef _DEBUG if (m_debugUI) { Vision::Message.DrawMessage3D("(RPG) Attackable", targetEntity->GetPosition() + hkvVec3(0.0f, 0.0f, 16.0f)); // (@hack: offset a little to avoid overwriting other component messages) } #endif } } else { if(!characterEntity->IsAttacking()) { // fall back to the move if the entity we hit wasn't a highlightable or attackable. RequestMove(characterEntity, false); } } }
bool VPathRenderingData::SetPathObject(VTypedObject* pObject) { if (!pObject->IsOfType(V_RUNTIME_CLASS(VisPath_cl))) return false; m_spPathObject = (VisPath_cl*)pObject; return true; }
bool vHavokConstraintChainRenderingData::SetPathObject(VTypedObject* pObject) { if (!pObject->IsOfType(V_RUNTIME_CLASS(vHavokConstraintChain))) return false; m_spPathObject = (vHavokConstraintChain*)pObject; return true; }
void VTerrainVisibilityInfo::Set(IVisVisibilityCollector_cl *pCollector,const VTerrainConfig &config) { hkvVec3 vCamPos(hkvNoInitialization), vCamDir(hkvNoInitialization); pCollector->GetSourceObject()->GetPosition(vCamPos); vCamDir = pCollector->GetSourceObject()->GetDirection(); VisRenderContext_cl *pLODContext = pCollector->GetLODReferenceRenderContext(); VASSERT(pLODContext!=NULL && pLODContext->GetCamera()!=NULL); pLODContext->GetCamera()->GetPosition(m_vCamLODPos); m_vCamPos.FromRenderSpace(config,(const hkvVec3& )vCamPos); m_vCamVisPos = vCamPos; m_CameraPlane.setFromPointAndNormal(vCamPos,vCamDir); VASSERT(m_vCamPos.IsValid(config)); // compute the rest float fNear,fFar; pCollector->GetClipPlanes(fNear,fFar); m_fMaxViewDistance = fFar; m_fLODDistanceInvScale = pLODContext->GetLODDistanceScaling() * VTerrainSectorManager::g_fDecorationDistanceInvScaling; if (m_fLODDistanceInvScale>0.f) m_fLODDistanceScale = 1.f/m_fLODDistanceInvScale; else m_fLODDistanceScale = 0.f; // overestimate config.GetViewDistanceBox(m_CamBBox, m_vCamVisPos, fFar); m_VisibleRangeBox.FromRenderSpace(config,m_CamBBox); m_iContextFilterMask = pCollector->GetFilterBitmask(); // reset min/max m_iVisibleSectorRange[0] = m_iVisibleSectorRange[1] = 32000; m_iVisibleSectorRange[2] = m_iVisibleSectorRange[3] = -32000; // reset some of the values: m_iVisibleDecorationCount = 0; m_iEstimatedDecorationCount = 0; static bool bEnableOpt = true; // shadowmap related: if (bEnableOpt && pCollector->GetTypeId()==V_RUNTIME_CLASS(VShadowmapVisibilityCollector)) { m_pSMGenerator = ((VShadowmapVisibilityCollector *)pCollector)->m_pSMGenerator; float fShadowExtrusionFactor = m_pSMGenerator->GetShadowMapComponent()->GetShadowBoxExtrudeMultiplier(); m_vShadowExtrusion = m_pSMGenerator->GetDirection(); if (m_vShadowExtrusion.z<-0.01f) // normalize height m_vShadowExtrusion.z *= (-1.f/m_vShadowExtrusion.z); m_vShadowExtrusion *= fShadowExtrusionFactor; m_bCastDynamicShadows = (m_pSMGenerator->GetShadowMapComponent()->GetGeometryTypes()&SHADOW_CASTER_TERRAIN)>0; } else m_pSMGenerator = NULL; }
BOOL VPathRenderingMetaData::CanAttachToObject(VisTypedEngineObject_cl* pObject, VString& sErrorMsgOut) { if (!IVObjectComponent::CanAttachToObject(pObject, sErrorMsgOut)) return FALSE; if (!pObject->IsOfType(V_RUNTIME_CLASS(VisPath_cl))) return FALSE; return TRUE; }
void RPG_Pickup::UpdateMagnetForces(float const deltaTime) { if(m_usePhysics) { // find the player VArray<RPG_Character*> const& characters = RPG_GameManager::s_instance.GetCharacters(); hkvVec3 const& currentPosition = GetPosition(); RPG_PlayerCharacter* player = NULL; // find a player in range for(int index = 0; index < characters.GetSize(); ++index) { RPG_Character* character = characters.GetAt(index); // only target apparently alive players if(!character->IsOfType(V_RUNTIME_CLASS(RPG_PlayerCharacter)) || character->IsDead() || character->IsFeigningDeath()) { continue; } player = static_cast<RPG_PlayerCharacter*>(character); break; } if(player) { hkvVec3 targetPosition = player->GetPosition(); targetPosition.z += 0.5f * player->GetBoundingBox().getSizeZ(); float distance = (currentPosition - targetPosition).getLength(); if(distance < m_pickupRadius) { distance = m_pickupRadius; } float const distanceSquared = distance * distance; if(distanceSquared < m_magnetMaxDistance * m_magnetMaxDistance) { hkvVec3 direction = targetPosition - GetPosition(); direction.normalizeIfNotZero(); float magnitude = m_magnetSpeedMultiplier * (1.0f / distanceSquared - m_magnetMaxDistanceInverseSquared); m_currentMagnetSpeed += deltaTime * magnitude * RPG_HEALTH_PICKUP_MAGNET_SPEED_MULTIPLIER_CONVERSION_VALUE; m_currentMagnetVelocity = m_currentMagnetSpeed * direction; } } } }
void RPG_DestructibleEntity::AddComponents() { // Add an attackable component if none was added in the editor if (!Components().GetComponentOfType(V_RUNTIME_CLASS(RPG_AttackableComponent))) { RPG_AttackableComponent* attackableComponent = new RPG_AttackableComponent; AddComponent(attackableComponent); } // Add a rigid body component if none already exists if (!Components().GetComponentOfType(V_RUNTIME_CLASS(vHavokRigidBody))) { // Rigid Body vHavokRigidBody* rigidBody = new vHavokRigidBody; rigidBody->Shape_Type = ShapeType_CYLINDER; rigidBody->Shape_Radius = m_collisionRadius; rigidBody->Shape_Height = m_collisionHeight; rigidBody->Havok_MotionType = MotionType_FIXED; AddComponent(rigidBody); } }
/// Finds and stores the level info object. void RPG_GameManager::FindLevelInfo() { // find the level info object VisBaseEntity_cl* levelInfo = Vision::Game.SearchEntity(RPG_LevelInfo::GetStaticKey()); if(levelInfo && levelInfo->IsOfType(V_RUNTIME_CLASS(RPG_LevelInfo))) { // store the level info object if we found one m_levelInfo = static_cast<RPG_LevelInfo*>(levelInfo); } }
void PlayerUIDialog::TryMeleeAttack(RPG_Character* characterEntity, RPG_DamageableEntity * const targetEntity) { VASSERT(characterEntity); const bool hitHighlightable = targetEntity->Components().GetComponentOfBaseType(V_RUNTIME_CLASS(RPG_HighlightableComponent)); const bool hitAttackable = targetEntity->Components().GetComponentOfBaseType(V_RUNTIME_CLASS(RPG_AttackableComponent)); //@debug: test log output //Vision::Error.Warning(hitEntity->GetMesh()->GetFilename()); if (hitHighlightable || hitAttackable) { if (hitHighlightable) //"(RPG) Highlightable" { //Vision::Error.Warning("(RPG) Highlightable"); } if (hitAttackable) //"(RPG) Attackable" { //Vision::Error.Warning("(RPG) Attackable"); if(characterEntity->IsTargetWithinAttackRange(targetEntity)) { characterEntity->GetActionHandler().PerformAction(AT_MeleeAttack, true, targetEntity, hkvVec3(0, 0, 0), 0); } else { characterEntity->GetActionHandler().PerformAction(AT_Move, true, targetEntity, hkvVec3(0, 0, 0), MF_AttackRange); characterEntity->GetActionHandler().PerformAction(AT_MeleeAttack, false, targetEntity); } } } else { // fall back to the move if the entity we hit wasn't a highlightable or attackable. if (!characterEntity->IsAttacking()) { RequestMove(characterEntity, true); } } }
BOOL VAnimationComponent::CanAttachToObject(VisTypedEngineObject_cl *pObject, VString &sErrorMsgOut) { if (!IVObjectComponent::CanAttachToObject(pObject, sErrorMsgOut)) return false; if (!pObject->IsOfType(V_RUNTIME_CLASS(VisBaseEntity_cl))) { sErrorMsgOut = "Component can only be added to instances of VisBaseEntity_cl or derived classes."; return FALSE; } return IVObjectComponent::CanAttachToObject(pObject, sErrorMsgOut); }
VDialog * VDlgControlBase::GetParentDialog() const { // find the first owner of type dialog VWindowBase *pParent = GetParent(); VType *pDlgType = V_RUNTIME_CLASS(VDialog); while (pParent) { if (pParent->IsOfType(pDlgType)) return (VDialog *)pParent; pParent = pParent->GetParent(); } return NULL; }
BOOL VMeshPaintingComponent::CanAttachToObject(VisTypedEngineObject_cl *pObject, VString &sErrorMsgOut) { #if defined( HK_ANARCHY ) sErrorMsgOut = "Component type not supported in Anarchy."; return FALSE; #else if (!IVObjectComponent::CanAttachToObject(pObject, sErrorMsgOut)) return FALSE; if (pObject->IsOfType(V_RUNTIME_CLASS(VisStaticMeshInstance_cl))) return TRUE; return FALSE; #endif }
BOOL RPG_MeshTrailEffectComponent::CanAttachToObject(VisTypedEngineObject_cl *object, VString& errorOut) { if(!IVObjectComponent::CanAttachToObject(object, errorOut)) { return FALSE; } bool const isBaseEntity = (object->IsOfType(V_RUNTIME_CLASS(VisBaseEntity_cl)) == TRUE); if(!isBaseEntity) { errorOut = "VisBaseEntity_cl (or derived) required"; return FALSE; } bool const hasWeaponTrailEffect = (object->Components().GetComponentOfBaseType(V_RUNTIME_CLASS(RPG_MeshTrailEffectComponent)) != NULL); if(hasWeaponTrailEffect) { errorOut = "RPG_MeshTrailEffectComponent (or derived) already attached"; return FALSE; } return TRUE; }
// ---------------------------------------------------------------------------- BOOL vHavokChainAnimation::CanAttachToObject( VisTypedEngineObject_cl *pObject, VString &sErrorMsgOut) { if (!IVObjectComponent::CanAttachToObject(pObject, sErrorMsgOut)) return FALSE; if (!pObject->IsOfType(V_RUNTIME_CLASS(VisBaseEntity_cl))) { sErrorMsgOut = "Component can only be added to entities."; return FALSE; } return TRUE; }
// ---------------------------------------------------------------------------- BOOL vHavokConstraintChainRendererBase::CanAttachToObject( VisTypedEngineObject_cl *pObject, VString &sErrorMsgOut) { if (!IVObjectComponent::CanAttachToObject(pObject, sErrorMsgOut)) return FALSE; if (!pObject->IsOfType(V_RUNTIME_CLASS(vHavokConstraintChain))) { sErrorMsgOut = "Component can only be added to Havok constraint chains."; return FALSE; } return TRUE; }
void VPathRenderingMetaData::OnVariableValueChanged(VisVariable_cl* pVar, const char* value) { IVObjectComponent::OnVariableValueChanged(pVar, value); // path renderers need to be re-initialized when variables are changed if (GetOwner() != NULL) { for (int i = 0; i < GetOwner()->Components().Count(); i++) { IVObjectComponent* pComp = GetOwner()->Components().GetAt(i); if (pComp != NULL && pComp->IsOfType(V_RUNTIME_CLASS(VPathRendererBase))) ((VPathRendererBase*)pComp)->OnDataChanged(); } } }
BOOL VThrowItemComponent::CanAttachToObject(VisTypedEngineObject_cl *pObject, VString &sErrorMsgOut) { if (!IVObjectComponent::CanAttachToObject(pObject, sErrorMsgOut)) return FALSE; // Define criteria here that allows the editor to attach this component to the passed object. // In our example, the object should be derived from VisObject3D_cl to be positionable. BOOL bIsValidClass = pObject->IsOfType(V_RUNTIME_CLASS(VisBaseEntity_cl)); if (!bIsValidClass) { sErrorMsgOut += "Component can only be added to instances of VisBaseEntity_cl or derived classes."; return FALSE; } return TRUE; }
// ---------------------------------------------------------------------------- bool vHavokConstraintChainRendererBase::DoInit() { // Get the constraint chain that owns this component VisTypedEngineObject_cl *pOwner = GetOwner(); m_pConstraintChain = (pOwner && pOwner->IsOfType(V_RUNTIME_CLASS(vHavokConstraintChain))) ? static_cast<vHavokConstraintChain*>(pOwner) : NULL; if (!m_pConstraintChain) return false; // Register as a rendering hook Vision::Callbacks.OnRenderHook += this; Vision::Callbacks.OnUpdateSceneBegin += this; return true; }