6871aeebc7642a6862a43c64e5a62b035753c43c
[blender.git] / source / gameengine / Ketsji / KX_NearSensor.cpp
1 /**
2  * Sense if other objects are near
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  */
31
32 #include "KX_NearSensor.h"
33 #include "SCA_LogicManager.h"
34 #include "KX_GameObject.h"
35 #include "KX_TouchEventManager.h"
36 #include "KX_Scene.h" // needed to create a replica
37 #include "PHY_IPhysicsEnvironment.h"
38 #include "PHY_IPhysicsController.h"
39 #include "PHY_IMotionState.h"
40
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44 KX_NearSensor::KX_NearSensor(SCA_EventManager* eventmgr,
45                                                          KX_GameObject* gameobj,
46                                                          float margin,
47                                                          float resetmargin,
48                                                          bool bFindMaterial,
49                                                          const STR_String& touchedpropname,
50                                                          PHY_IPhysicsController* ctrl)
51                          :KX_TouchSensor(eventmgr,
52                                                          gameobj,
53                                                          bFindMaterial,
54                                                          false,
55                                                          touchedpropname),
56                          m_Margin(margin),
57                          m_ResetMargin(resetmargin)
58
59 {
60
61         gameobj->getClientInfo()->m_sensors.remove(this);
62         m_client_info = new KX_ClientObjectInfo(gameobj, KX_ClientObjectInfo::SENSOR);
63         m_client_info->m_sensors.push_back(this);
64         
65         //DT_ShapeHandle shape = (DT_ShapeHandle) vshape;
66         m_physCtrl = ctrl;
67         if (m_physCtrl)
68         {
69                 m_physCtrl->SetMargin(m_Margin);
70                 m_physCtrl->setNewClientInfo(m_client_info);
71         }
72         SynchronizeTransform();
73 }
74
75 void KX_NearSensor::SynchronizeTransform()
76 {
77         // The near and radar sensors are using a different physical object which is 
78         // not linked to the parent object, must synchronize it.
79         if (m_physCtrl)
80         {
81                 PHY_IMotionState* motionState = m_physCtrl->GetMotionState();
82                 KX_GameObject* parent = ((KX_GameObject*)GetParent());
83                 const MT_Point3& pos = parent->NodeGetWorldPosition();
84                 float ori[12];
85                 parent->NodeGetWorldOrientation().getValue(ori);
86                 motionState->setWorldPosition(pos[0], pos[1], pos[2]);
87                 motionState->setWorldOrientation(ori);
88                 m_physCtrl->WriteMotionStateToDynamics(true);
89         }
90 }
91
92 CValue* KX_NearSensor::GetReplica()
93 {
94         KX_NearSensor* replica = new KX_NearSensor(*this);
95         replica->ProcessReplica();
96         return replica;
97 }
98
99 void KX_NearSensor::ProcessReplica()
100 {
101         KX_TouchSensor::ProcessReplica();
102         
103         m_client_info = new KX_ClientObjectInfo(m_client_info->m_gameobject, KX_ClientObjectInfo::SENSOR);
104         
105         if (m_physCtrl)
106         {
107                 m_physCtrl = m_physCtrl->GetReplica();
108                 if (m_physCtrl)
109                 {
110                         //static_cast<KX_TouchEventManager*>(m_eventmgr)->GetPhysicsEnvironment()->addSensor(replica->m_physCtrl);
111                         m_physCtrl->SetMargin(m_Margin);
112                         m_physCtrl->setNewClientInfo(m_client_info);
113                 }
114                 
115         }
116 }
117
118 void KX_NearSensor::ReParent(SCA_IObject* parent)
119 {
120         SCA_ISensor::ReParent(parent);
121         m_client_info->m_gameobject = static_cast<KX_GameObject*>(parent); 
122         m_client_info->m_sensors.push_back(this);
123         //Synchronize here with the actual parent.
124         SynchronizeTransform();
125 }
126
127
128
129 KX_NearSensor::~KX_NearSensor()
130 {
131         // for nearsensor, the sensor is the 'owner' of sumoobj
132         // for touchsensor, it's the parent
133         if (m_physCtrl)
134         {
135                 //static_cast<KX_TouchEventManager*>(m_eventmgr)->GetPhysicsEnvironment()->removeSensor(m_physCtrl);
136                 delete m_physCtrl;
137                 m_physCtrl = NULL;
138         }
139         
140                 
141         if (m_client_info)
142                 delete m_client_info;
143 }
144
145
146 bool KX_NearSensor::Evaluate()
147 {
148         bool result = false;
149 //      KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
150
151         if (m_bTriggered != m_bLastTriggered)
152         {
153                 m_bLastTriggered = m_bTriggered;
154                 if (m_bTriggered)
155                 {
156                         if (m_physCtrl)
157                         {
158                                 m_physCtrl->SetRadius(m_ResetMargin);
159                         }
160                 } else
161                 {
162                         if (m_physCtrl)
163                         {
164                                 m_physCtrl->SetRadius(m_Margin);
165                         }
166
167                 }
168                 result = true;
169         }
170
171         return result;
172 }
173
174 // this function is called at broad phase stage to check if the two controller
175 // need to interact at all. It is used for Near/Radar sensor that don't need to
176 // check collision with object not included in filter
177 bool    KX_NearSensor::BroadPhaseFilterCollision(void*obj1,void*obj2)
178 {
179         KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
180         
181         // need the mapping from PHY_IPhysicsController to gameobjects now
182         assert(obj1==m_physCtrl && obj2);
183         KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>((static_cast<PHY_IPhysicsController*>(obj2))->getNewClientInfo());
184
185         KX_GameObject* gameobj = ( client_info ? 
186                         client_info->m_gameobject :
187                         NULL);
188         
189         if (gameobj && (gameobj != parent))
190         {
191                 // only take valid colliders
192                 if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
193                 {
194                         if ((m_touchedpropname.Length() == 0) || 
195                                 (gameobj->GetProperty(m_touchedpropname)))
196                         {
197                                 return true;
198                         }
199                 }
200         }
201
202         return false;
203 }
204
205 bool    KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData * coll_data)
206 {
207 //      KX_TouchEventManager* toucheventmgr = static_cast<KX_TouchEventManager*>(m_eventmgr);
208 //      KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
209         
210         // need the mapping from PHY_IPhysicsController to gameobjects now
211         
212         KX_ClientObjectInfo* client_info =static_cast<KX_ClientObjectInfo*> (obj1 == m_physCtrl? 
213                                         ((PHY_IPhysicsController*)obj2)->getNewClientInfo() : 
214                                         ((PHY_IPhysicsController*)obj1)->getNewClientInfo());
215
216         KX_GameObject* gameobj = ( client_info ? 
217                         client_info->m_gameobject :
218                         NULL);
219         
220         // Add the same check as in SCA_ISensor::Activate(), 
221         // we don't want to record collision when the sensor is not active.
222         if (m_links && !m_suspended &&
223                 gameobj /* done in BroadPhaseFilterCollision() && (gameobj != parent)*/)
224         {
225                 if (!m_colliders->SearchValue(gameobj))
226                         m_colliders->Add(gameobj->AddRef());
227                 // only take valid colliders
228                 // These checks are done already in BroadPhaseFilterCollision()
229                 //if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
230                 //{
231                 //      if ((m_touchedpropname.Length() == 0) || 
232                 //              (gameobj->GetProperty(m_touchedpropname)))
233                 //      {
234                                 m_bTriggered = true;
235                                 m_hitObject = gameobj;
236                 //      }
237                 //}
238         }
239         
240         return false; // was DT_CONTINUE; but this was defined in Sumo as false
241 }
242
243
244 /* ------------------------------------------------------------------------- */
245 /* Python Functions                                                                                                                      */
246 /* ------------------------------------------------------------------------- */
247
248 //No methods
249
250 /* ------------------------------------------------------------------------- */
251 /* Python Integration Hooks                                                  */
252 /* ------------------------------------------------------------------------- */
253
254 PyTypeObject KX_NearSensor::Type = {
255 #if (PY_VERSION_HEX >= 0x02060000)
256         PyVarObject_HEAD_INIT(NULL, 0)
257 #else
258         /* python 2.5 and below */
259         PyObject_HEAD_INIT( NULL )  /* required py macro */
260         0,                          /* ob_size */
261 #endif
262         "KX_NearSensor",
263         sizeof(PyObjectPlus_Proxy),
264         0,
265         py_base_dealloc,
266         0,
267         0,
268         0,
269         0,
270         py_base_repr,
271         0,0,0,0,0,0,0,0,0,
272         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
273         0,0,0,0,0,0,0,
274         Methods,
275         0,
276         0,
277         &KX_TouchSensor::Type,
278         0,0,0,0,0,0,
279         py_base_new
280 };
281
282 PyMethodDef KX_NearSensor::Methods[] = {
283         //No methods
284         {NULL,NULL} //Sentinel
285 };
286
287 PyAttributeDef KX_NearSensor::Attributes[] = {
288         KX_PYATTRIBUTE_FLOAT_RW_CHECK("distance", 0, 100, KX_NearSensor, m_Margin, CheckResetDistance),
289         KX_PYATTRIBUTE_FLOAT_RW_CHECK("resetDistance", 0, 100, KX_NearSensor, m_ResetMargin, CheckResetDistance),
290         {NULL} //Sentinel
291 };