Blender  V2.59
KX_NearSensor.cpp
Go to the documentation of this file.
00001 /*
00002  * Sense if other objects are near
00003  *
00004  * $Id: KX_NearSensor.cpp 35171 2011-02-25 13:35:59Z jesterking $
00005  *
00006  * ***** BEGIN GPL LICENSE BLOCK *****
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License
00010  * as published by the Free Software Foundation; either version 2
00011  * of the License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software Foundation,
00020  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00021  *
00022  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00023  * All rights reserved.
00024  *
00025  * The Original Code is: all of this file.
00026  *
00027  * Contributor(s): none yet.
00028  *
00029  * ***** END GPL LICENSE BLOCK *****
00030  */
00031 
00037 #include "KX_NearSensor.h"
00038 #include "SCA_LogicManager.h"
00039 #include "KX_GameObject.h"
00040 #include "KX_TouchEventManager.h"
00041 #include "KX_Scene.h" // needed to create a replica
00042 #include "PHY_IPhysicsEnvironment.h"
00043 #include "PHY_IPhysicsController.h"
00044 #include "PHY_IMotionState.h"
00045 
00046 KX_NearSensor::KX_NearSensor(SCA_EventManager* eventmgr,
00047                                                          KX_GameObject* gameobj,
00048                                                          float margin,
00049                                                          float resetmargin,
00050                                                          bool bFindMaterial,
00051                                                          const STR_String& touchedpropname,
00052                                                          PHY_IPhysicsController* ctrl)
00053                          :KX_TouchSensor(eventmgr,
00054                                                          gameobj,
00055                                                          bFindMaterial,
00056                                                          false,
00057                                                          touchedpropname),
00058                          m_Margin(margin),
00059                          m_ResetMargin(resetmargin)
00060 
00061 {
00062 
00063         gameobj->getClientInfo()->m_sensors.remove(this);
00064         m_client_info = new KX_ClientObjectInfo(gameobj, KX_ClientObjectInfo::SENSOR);
00065         m_client_info->m_sensors.push_back(this);
00066         
00067         //DT_ShapeHandle shape = (DT_ShapeHandle) vshape;
00068         m_physCtrl = ctrl;
00069         if (m_physCtrl)
00070         {
00071                 m_physCtrl->SetMargin(m_Margin);
00072                 m_physCtrl->setNewClientInfo(m_client_info);
00073         }
00074         SynchronizeTransform();
00075 }
00076 
00077 void KX_NearSensor::SynchronizeTransform()
00078 {
00079         // The near and radar sensors are using a different physical object which is 
00080         // not linked to the parent object, must synchronize it.
00081         if (m_physCtrl)
00082         {
00083                 PHY_IMotionState* motionState = m_physCtrl->GetMotionState();
00084                 KX_GameObject* parent = ((KX_GameObject*)GetParent());
00085                 const MT_Point3& pos = parent->NodeGetWorldPosition();
00086                 float ori[12];
00087                 parent->NodeGetWorldOrientation().getValue(ori);
00088                 motionState->setWorldPosition(pos[0], pos[1], pos[2]);
00089                 motionState->setWorldOrientation(ori);
00090                 m_physCtrl->WriteMotionStateToDynamics(true);
00091         }
00092 }
00093 
00094 CValue* KX_NearSensor::GetReplica()
00095 {
00096         KX_NearSensor* replica = new KX_NearSensor(*this);
00097         replica->ProcessReplica();
00098         return replica;
00099 }
00100 
00101 void KX_NearSensor::ProcessReplica()
00102 {
00103         KX_TouchSensor::ProcessReplica();
00104         
00105         m_client_info = new KX_ClientObjectInfo(m_client_info->m_gameobject, KX_ClientObjectInfo::SENSOR);
00106         
00107         if (m_physCtrl)
00108         {
00109                 m_physCtrl = m_physCtrl->GetReplica();
00110                 if (m_physCtrl)
00111                 {
00112                         //static_cast<KX_TouchEventManager*>(m_eventmgr)->GetPhysicsEnvironment()->addSensor(replica->m_physCtrl);
00113                         m_physCtrl->SetMargin(m_Margin);
00114                         m_physCtrl->setNewClientInfo(m_client_info);
00115                 }
00116                 
00117         }
00118 }
00119 
00120 void KX_NearSensor::ReParent(SCA_IObject* parent)
00121 {
00122         SCA_ISensor::ReParent(parent);
00123         m_client_info->m_gameobject = static_cast<KX_GameObject*>(parent); 
00124         m_client_info->m_sensors.push_back(this);
00125         //Synchronize here with the actual parent.
00126         SynchronizeTransform();
00127 }
00128 
00129 
00130 
00131 KX_NearSensor::~KX_NearSensor()
00132 {
00133         // for nearsensor, the sensor is the 'owner' of sumoobj
00134         // for touchsensor, it's the parent
00135         if (m_physCtrl)
00136         {
00137                 //static_cast<KX_TouchEventManager*>(m_eventmgr)->GetPhysicsEnvironment()->removeSensor(m_physCtrl);
00138                 delete m_physCtrl;
00139                 m_physCtrl = NULL;
00140         }
00141         
00142                 
00143         if (m_client_info)
00144                 delete m_client_info;
00145 }
00146 
00147 void KX_NearSensor::SetPhysCtrlRadius()
00148 {
00149         if (m_bTriggered)
00150         {
00151                 if (m_physCtrl)
00152                 {
00153                         m_physCtrl->SetRadius(m_ResetMargin);
00154                 }
00155         } else
00156         {
00157                 if (m_physCtrl)
00158                 {
00159                         m_physCtrl->SetRadius(m_Margin);
00160                 }
00161         }
00162 }
00163 
00164 bool KX_NearSensor::Evaluate()
00165 {
00166         bool result = false;
00167 //      KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
00168 
00169         if (m_bTriggered != m_bLastTriggered)
00170         {
00171                 m_bLastTriggered = m_bTriggered;
00172                 
00173                 SetPhysCtrlRadius();
00174                 
00175                 result = true;
00176         }
00177 
00178         return result;
00179 }
00180 
00181 // this function is called at broad phase stage to check if the two controller
00182 // need to interact at all. It is used for Near/Radar sensor that don't need to
00183 // check collision with object not included in filter
00184 bool    KX_NearSensor::BroadPhaseFilterCollision(void*obj1,void*obj2)
00185 {
00186         KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
00187         
00188         // need the mapping from PHY_IPhysicsController to gameobjects now
00189         assert(obj1==m_physCtrl && obj2);
00190         KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>((static_cast<PHY_IPhysicsController*>(obj2))->getNewClientInfo());
00191 
00192         KX_GameObject* gameobj = ( client_info ? 
00193                         client_info->m_gameobject :
00194                         NULL);
00195         
00196         if (gameobj && (gameobj != parent))
00197         {
00198                 // only take valid colliders
00199                 if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
00200                 {
00201                         if ((m_touchedpropname.Length() == 0) || 
00202                                 (gameobj->GetProperty(m_touchedpropname)))
00203                         {
00204                                 return true;
00205                         }
00206                 }
00207         }
00208 
00209         return false;
00210 }
00211 
00212 bool    KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData * coll_data)
00213 {
00214 //      KX_TouchEventManager* toucheventmgr = static_cast<KX_TouchEventManager*>(m_eventmgr);
00215 //      KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
00216         
00217         // need the mapping from PHY_IPhysicsController to gameobjects now
00218         
00219         KX_ClientObjectInfo* client_info =static_cast<KX_ClientObjectInfo*> (obj1 == m_physCtrl? 
00220                                         ((PHY_IPhysicsController*)obj2)->getNewClientInfo() : 
00221                                         ((PHY_IPhysicsController*)obj1)->getNewClientInfo());
00222 
00223         KX_GameObject* gameobj = ( client_info ? 
00224                         client_info->m_gameobject :
00225                         NULL);
00226         
00227         // Add the same check as in SCA_ISensor::Activate(), 
00228         // we don't want to record collision when the sensor is not active.
00229         if (m_links && !m_suspended &&
00230                 gameobj /* done in BroadPhaseFilterCollision() && (gameobj != parent)*/)
00231         {
00232                 if (!m_colliders->SearchValue(gameobj))
00233                         m_colliders->Add(gameobj->AddRef());
00234                 // only take valid colliders
00235                 // These checks are done already in BroadPhaseFilterCollision()
00236                 //if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
00237                 //{
00238                 //      if ((m_touchedpropname.Length() == 0) || 
00239                 //              (gameobj->GetProperty(m_touchedpropname)))
00240                 //      {
00241                                 m_bTriggered = true;
00242                                 m_hitObject = gameobj;
00243                 //      }
00244                 //}
00245         }
00246         
00247         return false; // was DT_CONTINUE; but this was defined in Sumo as false
00248 }
00249 
00250 #ifdef WITH_PYTHON
00251 
00252 /* ------------------------------------------------------------------------- */
00253 /* Python Functions                                                                                                                      */
00254 /* ------------------------------------------------------------------------- */
00255 
00256 /* ------------------------------------------------------------------------- */
00257 /* Python Integration Hooks                                                  */
00258 /* ------------------------------------------------------------------------- */
00259 
00260 PyTypeObject KX_NearSensor::Type = {
00261         PyVarObject_HEAD_INIT(NULL, 0)
00262         "KX_NearSensor",
00263         sizeof(PyObjectPlus_Proxy),
00264         0,
00265         py_base_dealloc,
00266         0,
00267         0,
00268         0,
00269         0,
00270         py_base_repr,
00271         0,0,0,0,0,0,0,0,0,
00272         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00273         0,0,0,0,0,0,0,
00274         Methods,
00275         0,
00276         0,
00277         &KX_TouchSensor::Type,
00278         0,0,0,0,0,0,
00279         py_base_new
00280 };
00281 
00282 PyMethodDef KX_NearSensor::Methods[] = {
00283         //No methods
00284         {NULL,NULL} //Sentinel
00285 };
00286 
00287 PyAttributeDef KX_NearSensor::Attributes[] = {
00288         KX_PYATTRIBUTE_FLOAT_RW_CHECK("distance", 0, 100, KX_NearSensor, m_Margin, CheckResetDistance),
00289         KX_PYATTRIBUTE_FLOAT_RW_CHECK("resetDistance", 0, 100, KX_NearSensor, m_ResetMargin, CheckResetDistance),
00290         {NULL} //Sentinel
00291 };
00292 
00293 #endif // WITH_PYTHON