Panda3D
collisionHandlerEvent.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file collisionHandlerEvent.cxx
10  * @author drose
11  * @date 2002-03-16
12  */
13 
14 #include "collisionHandlerEvent.h"
15 #include "config_collide.h"
16 
17 #include "eventParameter.h"
18 #include "throw_event.h"
19 
20 using std::string;
21 
22 
23 TypeHandle CollisionHandlerEvent::_type_handle;
24 
25 /**
26  * The default CollisionHandlerEvent will throw no events. Its pattern
27  * strings must first be set via a call to add_in_pattern() and/or
28  * add_out_pattern().
29  */
32 }
33 
34 /**
35  * Will be called by the CollisionTraverser before a new traversal is begun.
36  * It instructs the handler to reset itself in preparation for a number of
37  * CollisionEntries to be sent.
38  */
41  if (collide_cat.is_spam()) {
42  collide_cat.spam()
43  << "begin_group.\n";
44  }
45  _last_colliding.swap(_current_colliding);
46  _current_colliding.clear();
47 }
48 
49 /**
50  * Called between a begin_group() .. end_group() sequence for each collision
51  * that is detected.
52  */
55  nassertv(entry != nullptr);
56 
57  // Record this particular entry for later. This will keep track of all the
58  // unique pairs of nodenode intersections.
59  bool inserted = _current_colliding.insert(entry).second;
60 
61  if (collide_cat.is_spam()) {
62  collide_cat.spam()
63  << "Detected collision from " << entry->get_from_node_path()
64  << " to " << entry->get_into_node_path()
65  << ", inserted = " << inserted << "\n";
66  }
67 }
68 
69 /**
70  * Called by the CollisionTraverser at the completion of all collision
71  * detections for this traversal. It should do whatever finalization is
72  * required for the handler.
73  */
76  // Now compare the list of entries we collected this frame with those we
77  // kept from the last time. Each new entry represents a new 'in' event;
78  // each missing entry represents a new 'out' event.
79 
80  if (collide_cat.is_spam()) {
81  collide_cat.spam()
82  << "end_group.\n"
83  << "current_colliding has " << _current_colliding.size()
84  << " entries, last_colliding has " << _last_colliding.size()
85  << "\n";
86  }
87 
88  Colliding::iterator ca, cb;
89 
90  ca = _current_colliding.begin();
91  cb = _last_colliding.begin();
92 
93  SortEntries order;
94  while (ca != _current_colliding.end() && cb != _last_colliding.end()) {
95  if (order(*ca, *cb)) {
96  // Here's an element in a but not in b. That's a newly entered
97  // intersection.
98  throw_event_for(_in_patterns, *ca);
99  ++ca;
100  } else if (order(*cb, *ca)) {
101  // Here's an element in b but not in a. That's a newly exited
102  // intersection.
103  throw_event_for(_out_patterns, *cb);
104  ++cb;
105  } else {
106  // This element is in both b and a. It hasn't changed.
107  throw_event_for(_again_patterns, *cb);
108  ++ca;
109  ++cb;
110  }
111  }
112 
113  while (ca != _current_colliding.end()) {
114  // Here's an element in a but not in b. That's a newly entered
115  // intersection.
116  throw_event_for(_in_patterns, *ca);
117  ++ca;
118  }
119 
120  while (cb != _last_colliding.end()) {
121  // Here's an element in b but not in a. That's a newly exited
122  // intersection.
123  throw_event_for(_out_patterns, *cb);
124  ++cb;
125  }
126 
127  return true;
128 }
129 
130 /**
131  * Empties the list of elements that all colliders are known to be colliding
132  * with. No "out" events will be thrown; if the same collision is detected
133  * next frame, a new "in" event will be thrown for each collision.
134  *
135  * This can be called each frame to defeat the persistent "in" event
136  * mechanism, which prevents the same "in" event from being thrown repeatedly.
137  * However, also see add_again_pattern(), which can be used to set the event
138  * that is thrown when a collision is detected for two or more consecutive
139  * frames.
140  */
142 clear() {
143  _last_colliding.clear();
144  _current_colliding.clear();
145 }
146 
147 /**
148  * Same as clear() except "out" events are thrown.
149  */
151 flush() {
152  begin_group();
153  end_group();
154 }
155 
156 /**
157  * Throws whatever events are suggested by the list of patterns.
158  */
159 void CollisionHandlerEvent::
160 throw_event_for(const vector_string &patterns, CollisionEntry *entry) {
161  vector_string::const_iterator pi;
162  for (pi = patterns.begin(); pi != patterns.end(); ++pi) {
163  throw_event_pattern(*pi, entry);
164  }
165 }
166 
167 /**
168  * Throws an event matching the indicated pattern.
169  */
170 void CollisionHandlerEvent::
171 throw_event_pattern(const string &pattern, CollisionEntry *entry) {
172  if (pattern.empty()) {
173  return;
174  }
175 
176  string event;
177  for (size_t p = 0; p < pattern.size(); ++p) {
178  if (pattern[p] == '%') {
179  string key;
180  if (p + 1 < pattern.size() && pattern[p + 1] == '(') {
181  // Extract out the key--the name up until the closing paren.
182  size_t close = pattern.find(')', p + 2);
183  if (close != string::npos) {
184  key = pattern.substr(p + 2, close - (p + 2));
185  p = close;
186  }
187  }
188 
189  // Get out the command--the two characters following the percent sign
190  // (or the key).
191  string cmd = pattern.substr(p + 1, 2);
192  p += 2;
193  if (cmd == "fn") {
194  event += entry->get_from_node()->get_name();
195 
196  } else if (cmd == "in") {
197  if (entry->has_into()) {
198  event += entry->get_into_node()->get_name();
199  }
200 
201  } else if (cmd == "fs") {
202  event +=
203  (!entry->get_from()->is_tangible() ? 'i' : 't');
204 
205  } else if (cmd == "is") {
206  event +=
207  (entry->has_into() && !entry->get_into()->is_tangible() ? 'i' : 't');
208 
209  } else if (cmd == "ig") {
210  event +=
211  (entry->has_into() ? 'c' : 'g');
212 
213  } else if (cmd == "fh") {
214  if (!entry->get_from_node_path().has_net_tag(key)) {
215  return;
216  }
217 
218  } else if (cmd == "fx") {
219  if (entry->get_from_node_path().has_net_tag(key)) {
220  return;
221  }
222 
223  } else if (cmd == "ih") {
224  if (!(entry->has_into() && entry->get_into_node_path().has_net_tag(key))) {
225  return;
226  }
227 
228  } else if (cmd == "ix") {
229  if (entry->has_into() && entry->get_into_node_path().has_net_tag(key)) {
230  return;
231  }
232 
233  } else if (cmd == "ft") {
234  event += entry->get_from_node_path().get_net_tag(key);
235 
236  } else if (cmd == "it") {
237  if (entry->has_into()) {
238  event += entry->get_into_node_path().get_net_tag(key);
239  }
240 
241  } else {
242  collide_cat.error()
243  << "Invalid symbol in event_pattern: %" << cmd << "\n";
244  }
245  } else {
246  event += pattern[p];
247  }
248  }
249 
250  if (!event.empty()) {
251  throw_event(event, EventParameter(entry));
252  }
253 }
virtual bool end_group()
Called by the CollisionTraverser at the completion of all collision detections for this traversal.
get_from_node_path
Returns the NodePath that represents the CollisionNode that contains the CollisionSolid that triggere...
An optional parameter associated with an event.
void flush()
Same as clear() except "out" events are thrown.
virtual void begin_group()
Will be called by the CollisionTraverser before a new traversal is begun.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool has_into() const
Returns true if the "into" solid is, in fact, a CollisionSolid, and its pointer is known (in which ca...
get_into_node_path
Returns the NodePath that represents the specific CollisionNode or GeomNode instance that was collide...
void clear()
Empties the list of elements that all colliders are known to be colliding with.
get_from_node
Returns the node that contains the CollisionSolid that triggered this collision.
Defines a single collision event.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CollisionHandlerEvent()
The default CollisionHandlerEvent will throw no events.
get_into_node
Returns the node that contains the CollisionSolid that was collided into.
get_into
Returns the CollisionSolid pointer for the particular solid was collided into.
get_from
Returns the CollisionSolid pointer for the particular solid that triggered this collision.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
virtual void add_entry(CollisionEntry *entry)
Called between a begin_group() .
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.