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 */
30 CollisionHandlerEvent::
31 CollisionHandlerEvent() {
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 */
39 void CollisionHandlerEvent::
40 begin_group() {
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 */
53 void CollisionHandlerEvent::
54 add_entry(CollisionEntry *entry) {
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 */
74 bool CollisionHandlerEvent::
75 end_group() {
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 */
141 void CollisionHandlerEvent::
142 clear() {
143 _last_colliding.clear();
144 _current_colliding.clear();
145 }
146
147 /**
148 * Same as clear() except "out" events are thrown.
149 */
150 void CollisionHandlerEvent::
151 flush() {
152 begin_group();
153 end_group();
154 }
155
156 /**
157 * Serializes this object, to implement pickle support.
158 */
159 void CollisionHandlerEvent::
160 write_datagram(Datagram &dg) const {
161 dg.add_uint32(_in_patterns.size());
162 for (const std::string &pattern : _in_patterns) {
163 dg.add_string(pattern);
164 }
165
166 dg.add_uint32(_again_patterns.size());
167 for (const std::string &pattern : _again_patterns) {
168 dg.add_string(pattern);
169 }
170
171 dg.add_uint32(_out_patterns.size());
172 for (const std::string &pattern : _out_patterns) {
173 dg.add_string(pattern);
174 }
175 }
176
177 /**
178 * Restores the object state from the given datagram, previously obtained using
179 * __getstate__.
180 */
181 void CollisionHandlerEvent::
182 read_datagram(DatagramIterator &scan) {
183 _in_patterns.clear();
184 size_t num_in_patterns = scan.get_uint32();
185 for (size_t i = 0; i < num_in_patterns; ++i) {
186 add_in_pattern(scan.get_string());
187 }
188
189 _again_patterns.clear();
190 size_t num_again_patterns = scan.get_uint32();
191 for (size_t i = 0; i < num_again_patterns; ++i) {
192 add_again_pattern(scan.get_string());
193 }
194
195 _out_patterns.clear();
196 size_t num_out_patterns = scan.get_uint32();
197 for (size_t i = 0; i < num_out_patterns; ++i) {
198 add_out_pattern(scan.get_string());
199 }
200 }
201
202 /**
203 * Throws whatever events are suggested by the list of patterns.
204 */
205 void CollisionHandlerEvent::
206 throw_event_for(const vector_string &patterns, CollisionEntry *entry) {
207 vector_string::const_iterator pi;
208 for (pi = patterns.begin(); pi != patterns.end(); ++pi) {
209 throw_event_pattern(*pi, entry);
210 }
211 }
212
213 /**
214 * Throws an event matching the indicated pattern.
215 */
216 void CollisionHandlerEvent::
217 throw_event_pattern(const string &pattern, CollisionEntry *entry) {
218 if (pattern.empty()) {
219 return;
220 }
221
222 string event;
223 for (size_t p = 0; p < pattern.size(); ++p) {
224 if (pattern[p] == '%') {
225 string key;
226 if (p + 1 < pattern.size() && pattern[p + 1] == '(') {
227 // Extract out the key--the name up until the closing paren.
228 size_t close = pattern.find(')', p + 2);
229 if (close != string::npos) {
230 key = pattern.substr(p + 2, close - (p + 2));
231 p = close;
232 }
233 }
234
235 // Get out the command--the two characters following the percent sign
236 // (or the key).
237 string cmd = pattern.substr(p + 1, 2);
238 p += 2;
239 if (cmd == "fn") {
240 event += entry->get_from_node()->get_name();
241
242 } else if (cmd == "in") {
243 if (entry->has_into()) {
244 event += entry->get_into_node()->get_name();
245 }
246
247 } else if (cmd == "fs") {
248 event +=
249 (!entry->get_from()->is_tangible() ? 'i' : 't');
250
251 } else if (cmd == "is") {
252 event +=
253 (entry->has_into() && !entry->get_into()->is_tangible() ? 'i' : 't');
254
255 } else if (cmd == "ig") {
256 event +=
257 (entry->has_into() ? 'c' : 'g');
258
259 } else if (cmd == "fh") {
260 if (!entry->get_from_node_path().has_net_tag(key)) {
261 return;
262 }
263
264 } else if (cmd == "fx") {
265 if (entry->get_from_node_path().has_net_tag(key)) {
266 return;
267 }
268
269 } else if (cmd == "ih") {
270 if (!(entry->has_into() && entry->get_into_node_path().has_net_tag(key))) {
271 return;
272 }
273
274 } else if (cmd == "ix") {
275 if (entry->has_into() && entry->get_into_node_path().has_net_tag(key)) {
276 return;
277 }
278
279 } else if (cmd == "ft") {
280 event += entry->get_from_node_path().get_net_tag(key);
281
282 } else if (cmd == "it") {
283 if (entry->has_into()) {
284 event += entry->get_into_node_path().get_net_tag(key);
285 }
286
287 } else {
288 collide_cat.error()
289 << "Invalid symbol in event_pattern: %" << cmd << "\n";
290 }
291 } else {
292 event += pattern[p];
293 }
294 }
295
296 if (!event.empty()) {
297 throw_event(event, EventParameter(entry));
298 }
299 }
CollisionEntry
Defines a single collision event.
Definition: collisionEntry.h:42
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
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_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
CollisionEntry::get_into_node
get_into_node
Returns the node that contains the CollisionSolid that was collided into.
Definition: collisionEntry.h:100
CollisionEntry::get_from
get_from
Returns the CollisionSolid pointer for the particular solid that triggered this collision.
Definition: collisionEntry.h:97
CollisionHandlerEvent::add_out_pattern
void add_out_pattern(const std::string &out_pattern)
Adds the pattern string that indicates how the event names are generated when a collision between two...
Definition: collisionHandlerEvent.I:184
CollisionHandlerEvent::add_again_pattern
void add_again_pattern(const std::string &again_pattern)
Adds the pattern string that indicates how the event names are generated when a collision between two...
Definition: collisionHandlerEvent.I:131
CollisionHandlerEvent::begin_group
virtual void begin_group()
Will be called by the CollisionTraverser before a new traversal is begun.
Definition: collisionHandlerEvent.cxx:40
CollisionHandlerEvent::add_in_pattern
void add_in_pattern(const std::string &in_pattern)
Adds a pattern string to the list of events that will be generated in response to a collision.
Definition: collisionHandlerEvent.I:76
CollisionHandlerEvent::flush
void flush()
Same as clear() except "out" events are thrown.
Definition: collisionHandlerEvent.cxx:151
CollisionHandlerEvent::CollisionHandlerEvent
CollisionHandlerEvent()
The default CollisionHandlerEvent will throw no events.
Definition: collisionHandlerEvent.cxx:31
CollisionHandlerEvent::add_entry
virtual void add_entry(CollisionEntry *entry)
Called between a begin_group() .
Definition: collisionHandlerEvent.cxx:54
CollisionHandlerEvent::read_datagram
void read_datagram(DatagramIterator &source)
Restores the object state from the given datagram, previously obtained using __getstate__.
Definition: collisionHandlerEvent.cxx:182
CollisionHandlerEvent::clear
void clear()
Empties the list of elements that all colliders are known to be colliding with.
Definition: collisionHandlerEvent.cxx:142
CollisionHandlerEvent::write_datagram
void write_datagram(Datagram &destination) const
Serializes this object, to implement pickle support.
Definition: collisionHandlerEvent.cxx:160
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
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
DatagramIterator::get_uint32
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
Definition: datagramIterator.I:164
DatagramIterator::get_string
std::string get_string()
Extracts a variable-length string.
Definition: datagramIterator.cxx:26
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
Datagram::add_uint32
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
Definition: datagram.I:94
Datagram::add_string
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
Definition: datagram.I:219
EventParameter
An optional parameter associated with an event.
Definition: eventParameter.h:35
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
collisionHandlerEvent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_collide.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eventParameter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
throw_event.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.