Panda3D
Loading...
Searching...
No Matches
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
15#include "config_collide.h"
16
17#include "eventParameter.h"
18#include "throw_event.h"
19
20using std::string;
21
22
23TypeHandle 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 */
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 */
75end_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 */
142clear() {
143 _last_colliding.clear();
144 _current_colliding.clear();
145}
146
147/**
148 * Same as clear() except "out" events are thrown.
149 */
151flush() {
152 begin_group();
153 end_group();
154}
155
156/**
157 * Serializes this object, to implement pickle support.
158 */
160write_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 */
183 _in_patterns.clear();
184 size_t num_in_patterns = scan.get_uint32();
185 for (size_t i = 0; i < num_in_patterns; ++i) {
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) {
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) {
199 }
200}
201
202/**
203 * Throws whatever events are suggested by the list of patterns.
204 */
205void CollisionHandlerEvent::
206throw_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 */
216void CollisionHandlerEvent::
217throw_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}
Defines a single collision event.
get_from_node
Returns the node that contains the CollisionSolid that triggered this collision.
get_into
Returns the CollisionSolid pointer for the particular solid was collided into.
bool has_into() const
Returns true if the "into" solid is, in fact, a CollisionSolid, and its pointer is known (in which ca...
get_from_node_path
Returns the NodePath that represents the CollisionNode that contains the CollisionSolid that triggere...
get_into_node_path
Returns the NodePath that represents the specific CollisionNode or GeomNode instance that was collide...
get_into_node
Returns the node that contains the CollisionSolid that was collided into.
get_from
Returns the CollisionSolid pointer for the particular solid that triggered this collision.
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...
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...
virtual void begin_group()
Will be called by the CollisionTraverser before a new traversal is begun.
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.
void flush()
Same as clear() except "out" events are thrown.
CollisionHandlerEvent()
The default CollisionHandlerEvent will throw no events.
virtual void add_entry(CollisionEntry *entry)
Called between a begin_group() .
void read_datagram(DatagramIterator &source)
Restores the object state from the given datagram, previously obtained using __getstate__.
void clear()
Empties the list of elements that all colliders are known to be colliding with.
void write_datagram(Datagram &destination) const
Serializes this object, to implement pickle support.
virtual bool end_group()
Called by the CollisionTraverser at the completion of all collision detections for this traversal.
A class to retrieve the individual data elements previously stored in a Datagram.
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
std::string get_string()
Extracts a variable-length string.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
Definition datagram.I:94
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
Definition datagram.I:219
An optional parameter associated with an event.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.