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 }
throw_event.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eventParameter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CollisionEntry::get_from_node_path
get_from_node_path
Returns the NodePath that represents the CollisionNode that contains the CollisionSolid that triggere...
Definition: collisionEntry.h:101
CollisionEntry::get_from
get_from
Returns the CollisionSolid pointer for the particular solid that triggered this collision.
Definition: collisionEntry.h:97
CollisionEntry
Defines a single collision event.
Definition: collisionEntry.h:42
CollisionEntry::get_into_node_path
get_into_node_path
Returns the NodePath that represents the specific CollisionNode or GeomNode instance that was collide...
Definition: collisionEntry.h:102
CollisionHandlerEvent::add_entry
virtual void add_entry(CollisionEntry *entry)
Called between a begin_group() .
Definition: collisionHandlerEvent.cxx:54
CollisionHandlerEvent::begin_group
virtual void begin_group()
Will be called by the CollisionTraverser before a new traversal is begun.
Definition: collisionHandlerEvent.cxx:40
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
CollisionHandlerEvent::end_group
virtual bool end_group()
Called by the CollisionTraverser at the completion of all collision detections for this traversal.
Definition: collisionHandlerEvent.cxx:75
CollisionHandlerEvent::clear
void clear()
Empties the list of elements that all colliders are known to be colliding with.
Definition: collisionHandlerEvent.cxx:142
EventParameter
An optional parameter associated with an event.
Definition: eventParameter.h:35
CollisionEntry::get_from_node
get_from_node
Returns the node that contains the CollisionSolid that triggered this collision.
Definition: collisionEntry.h:99
CollisionEntry::get_into
get_into
Returns the CollisionSolid pointer for the particular solid was collided into.
Definition: collisionEntry.h:98
CollisionEntry::has_into
bool has_into() const
Returns true if the "into" solid is, in fact, a CollisionSolid, and its pointer is known (in which ca...
Definition: collisionEntry.I:40
CollisionHandlerEvent::CollisionHandlerEvent
CollisionHandlerEvent()
The default CollisionHandlerEvent will throw no events.
Definition: collisionHandlerEvent.cxx:31
collisionHandlerEvent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_collide.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CollisionHandlerEvent::flush
void flush()
Same as clear() except "out" events are thrown.
Definition: collisionHandlerEvent.cxx:151
CollisionEntry::get_into_node
get_into_node
Returns the node that contains the CollisionSolid that was collided into.
Definition: collisionEntry.h:100