BGE: new sensor object to generalize Near and Radar sensor, static-static collision...
[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                                                          class KX_Scene* scene,
51                                                          PHY_IPhysicsController*        ctrl,
52                                                          PyTypeObject* T)
53                          :KX_TouchSensor(eventmgr,
54                                                          gameobj,
55                                                          bFindMaterial,
56                                                          false,
57                                                          touchedpropname,
58                                                          /* scene, */
59                                                          T),
60                          m_Margin(margin),
61                          m_ResetMargin(resetmargin)
62
63 {
64
65         gameobj->getClientInfo()->m_sensors.remove(this);
66         m_client_info = new KX_ClientObjectInfo(gameobj, KX_ClientObjectInfo::SENSOR);
67         m_client_info->m_sensors.push_back(this);
68         
69         //DT_ShapeHandle shape = (DT_ShapeHandle) vshape;
70         m_physCtrl = ctrl;
71         if (m_physCtrl)
72         {
73                 m_physCtrl->SetMargin(m_Margin);
74                 m_physCtrl->setNewClientInfo(m_client_info);
75         }
76         SynchronizeTransform();
77 }
78
79 void KX_NearSensor::SynchronizeTransform()
80 {
81         // The near and radar sensors are using a different physical object which is 
82         // not linked to the parent object, must synchronize it.
83         if (m_physCtrl)
84         {
85                 PHY_IMotionState* motionState = m_physCtrl->GetMotionState();
86                 KX_GameObject* parent = ((KX_GameObject*)GetParent());
87                 const MT_Point3& pos = parent->NodeGetWorldPosition();
88                 float ori[12];
89                 parent->NodeGetWorldOrientation().getValue(ori);
90                 motionState->setWorldPosition(pos[0], pos[1], pos[2]);
91                 motionState->setWorldOrientation(ori);
92                 m_physCtrl->WriteMotionStateToDynamics(true);
93         }
94 }
95
96 CValue* KX_NearSensor::GetReplica()
97 {
98         KX_NearSensor* replica = new KX_NearSensor(*this);
99         replica->ProcessReplica();
100         return replica;
101 }
102
103 void KX_NearSensor::ProcessReplica()
104 {
105         KX_TouchSensor::ProcessReplica();
106         
107         m_client_info = new KX_ClientObjectInfo(m_client_info->m_gameobject, KX_ClientObjectInfo::SENSOR);
108         
109         if (m_physCtrl)
110         {
111                 m_physCtrl = m_physCtrl->GetReplica();
112                 if (m_physCtrl)
113                 {
114                         //static_cast<KX_TouchEventManager*>(m_eventmgr)->GetPhysicsEnvironment()->addSensor(replica->m_physCtrl);
115                         m_physCtrl->SetMargin(m_Margin);
116                         m_physCtrl->setNewClientInfo(m_client_info);
117                 }
118                 
119         }
120 }
121
122 void KX_NearSensor::ReParent(SCA_IObject* parent)
123 {
124         SCA_ISensor::ReParent(parent);
125         m_client_info->m_gameobject = static_cast<KX_GameObject*>(parent); 
126         m_client_info->m_sensors.push_back(this);
127         //Synchronize here with the actual parent.
128         SynchronizeTransform();
129 }
130
131
132
133 KX_NearSensor::~KX_NearSensor()
134 {
135         // for nearsensor, the sensor is the 'owner' of sumoobj
136         // for touchsensor, it's the parent
137         if (m_physCtrl)
138         {
139                 //static_cast<KX_TouchEventManager*>(m_eventmgr)->GetPhysicsEnvironment()->removeSensor(m_physCtrl);
140                 delete m_physCtrl;
141                 m_physCtrl = NULL;
142         }
143         
144                 
145         if (m_client_info)
146                 delete m_client_info;
147 }
148
149
150 bool KX_NearSensor::Evaluate()
151 {
152         bool result = false;
153 //      KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
154
155         if (m_bTriggered != m_bLastTriggered)
156         {
157                 m_bLastTriggered = m_bTriggered;
158                 if (m_bTriggered)
159                 {
160                         if (m_physCtrl)
161                         {
162                                 m_physCtrl->SetRadius(m_ResetMargin);
163                         }
164                 } else
165                 {
166                         if (m_physCtrl)
167                         {
168                                 m_physCtrl->SetRadius(m_Margin);
169                         }
170
171                 }
172                 result = true;
173         }
174
175         return result;
176 }
177
178 // this function is called at broad phase stage to check if the two controller
179 // need to interact at all. It is used for Near/Radar sensor that don't need to
180 // check collision with object not included in filter
181 bool    KX_NearSensor::BroadPhaseFilterCollision(void*obj1,void*obj2)
182 {
183         KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
184         
185         // need the mapping from PHY_IPhysicsController to gameobjects now
186         assert(obj1==m_physCtrl && obj2);
187         KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>((static_cast<PHY_IPhysicsController*>(obj2))->getNewClientInfo());
188
189         KX_GameObject* gameobj = ( client_info ? 
190                         client_info->m_gameobject :
191                         NULL);
192         
193         if (gameobj && (gameobj != parent))
194         {
195                 // only take valid colliders
196                 if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
197                 {
198                         if ((m_touchedpropname.Length() == 0) || 
199                                 (gameobj->GetProperty(m_touchedpropname)))
200                         {
201                                 return true;
202                         }
203                 }
204         }
205
206         return false;
207 }
208
209 bool    KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData * coll_data)
210 {
211 //      KX_TouchEventManager* toucheventmgr = static_cast<KX_TouchEventManager*>(m_eventmgr);
212 //      KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
213         
214         // need the mapping from PHY_IPhysicsController to gameobjects now
215         
216         KX_ClientObjectInfo* client_info =static_cast<KX_ClientObjectInfo*> (obj1 == m_physCtrl? 
217                                         ((PHY_IPhysicsController*)obj2)->getNewClientInfo() : 
218                                         ((PHY_IPhysicsController*)obj1)->getNewClientInfo());
219
220         KX_GameObject* gameobj = ( client_info ? 
221                         client_info->m_gameobject :
222                         NULL);
223         
224         // Add the same check as in SCA_ISensor::Activate(), 
225         // we don't want to record collision when the sensor is not active.
226         if (m_links && !m_suspended &&
227                 gameobj /* done in BroadPhaseFilterCollision() && (gameobj != parent)*/)
228         {
229                 if (!m_colliders->SearchValue(gameobj))
230                         m_colliders->Add(gameobj->AddRef());
231                 // only take valid colliders
232                 // These checks are done already in BroadPhaseFilterCollision()
233                 //if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
234                 //{
235                 //      if ((m_touchedpropname.Length() == 0) || 
236                 //              (gameobj->GetProperty(m_touchedpropname)))
237                 //      {
238                                 m_bTriggered = true;
239                                 m_hitObject = gameobj;
240                 //      }
241                 //}
242         }
243         
244         return false; // was DT_CONTINUE; but this was defined in Sumo as false
245 }
246
247
248 /* ------------------------------------------------------------------------- */
249 /* Python Functions                                                                                                                      */
250 /* ------------------------------------------------------------------------- */
251
252 //No methods
253
254 /* ------------------------------------------------------------------------- */
255 /* Python Integration Hooks                                                  */
256 /* ------------------------------------------------------------------------- */
257
258 PyTypeObject KX_NearSensor::Type = {
259 #if (PY_VERSION_HEX >= 0x02060000)
260         PyVarObject_HEAD_INIT(NULL, 0)
261 #else
262         /* python 2.5 and below */
263         PyObject_HEAD_INIT( NULL )  /* required py macro */
264         0,                          /* ob_size */
265 #endif
266         "KX_NearSensor",
267         sizeof(PyObjectPlus_Proxy),
268         0,
269         py_base_dealloc,
270         0,
271         0,
272         0,
273         0,
274         py_base_repr,
275         0,0,0,0,0,0,
276         py_base_getattro,
277         py_base_setattro,
278         0,0,0,0,0,0,0,0,0,
279         Methods
280 };
281
282
283
284 PyParentObject KX_NearSensor::Parents[] = {
285         &KX_NearSensor::Type,
286         &KX_TouchSensor::Type,
287         &SCA_ISensor::Type,
288         &SCA_ILogicBrick::Type,
289         &CValue::Type,
290         NULL
291 };
292
293
294
295 PyMethodDef KX_NearSensor::Methods[] = {
296         //No methods
297         {NULL,NULL} //Sentinel
298 };
299
300 PyAttributeDef KX_NearSensor::Attributes[] = {
301         KX_PYATTRIBUTE_FLOAT_RW_CHECK("distance", 0, 100, KX_NearSensor, m_Margin, CheckResetDistance),
302         KX_PYATTRIBUTE_FLOAT_RW_CHECK("resetDistance", 0, 100, KX_NearSensor, m_ResetMargin, CheckResetDistance),
303         {NULL} //Sentinel
304 };
305
306
307 PyObject* KX_NearSensor::py_getattro(PyObject *attr)
308 {
309         py_getattro_up(KX_TouchSensor);
310 }
311
312 PyObject* KX_NearSensor::py_getattro_dict() {
313         py_getattro_dict_up(KX_TouchSensor);
314 }
315
316 int KX_NearSensor::py_setattro(PyObject*attr, PyObject* value)
317 {
318         py_setattro_up(KX_TouchSensor);
319 }