Panda3D
|
00001 // Filename: collisionHandlerEvent.cxx 00002 // Created by: drose (16Mar02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 00016 #include "collisionHandlerEvent.h" 00017 #include "config_collide.h" 00018 00019 #include "eventParameter.h" 00020 #include "throw_event.h" 00021 00022 00023 TypeHandle CollisionHandlerEvent::_type_handle; 00024 00025 //////////////////////////////////////////////////////////////////// 00026 // Function: CollisionHandlerEvent::Constructor 00027 // Access: Public 00028 // Description: The default CollisionHandlerEvent will throw no 00029 // events. Its pattern strings must first be set via a 00030 // call to add_in_pattern() and/or add_out_pattern(). 00031 //////////////////////////////////////////////////////////////////// 00032 CollisionHandlerEvent:: 00033 CollisionHandlerEvent() { 00034 } 00035 00036 //////////////////////////////////////////////////////////////////// 00037 // Function: CollisionHandlerEvent::begin_group 00038 // Access: Public, Virtual 00039 // Description: Will be called by the CollisionTraverser before a new 00040 // traversal is begun. It instructs the handler to 00041 // reset itself in preparation for a number of 00042 // CollisionEntries to be sent. 00043 //////////////////////////////////////////////////////////////////// 00044 void CollisionHandlerEvent:: 00045 begin_group() { 00046 if (collide_cat.is_spam()) { 00047 collide_cat.spam() 00048 << "begin_group.\n"; 00049 } 00050 _last_colliding.swap(_current_colliding); 00051 _current_colliding.clear(); 00052 } 00053 00054 //////////////////////////////////////////////////////////////////// 00055 // Function: CollisionHandlerEvent::add_entry 00056 // Access: Public, Virtual 00057 // Description: Called between a begin_group() .. end_group() 00058 // sequence for each collision that is detected. 00059 //////////////////////////////////////////////////////////////////// 00060 void CollisionHandlerEvent:: 00061 add_entry(CollisionEntry *entry) { 00062 nassertv(entry != (CollisionEntry *)NULL); 00063 00064 // Record this particular entry for later. This will keep track of 00065 // all the unique pairs of node/node intersections. 00066 bool inserted = _current_colliding.insert(entry).second; 00067 00068 if (collide_cat.is_spam()) { 00069 collide_cat.spam() 00070 << "Detected collision from " << entry->get_from_node_path() 00071 << " to " << entry->get_into_node_path() 00072 << ", inserted = " << inserted << "\n"; 00073 } 00074 } 00075 00076 //////////////////////////////////////////////////////////////////// 00077 // Function: CollisionHandlerEvent::end_group 00078 // Access: Public, Virtual 00079 // Description: Called by the CollisionTraverser at the completion of 00080 // all collision detections for this traversal. It 00081 // should do whatever finalization is required for the 00082 // handler. 00083 //////////////////////////////////////////////////////////////////// 00084 bool CollisionHandlerEvent:: 00085 end_group() { 00086 // Now compare the list of entries we collected this frame with 00087 // those we kept from the last time. Each new entry represents a 00088 // new 'in' event; each missing entry represents a new 'out' event. 00089 00090 if (collide_cat.is_spam()) { 00091 collide_cat.spam() 00092 << "end_group.\n" 00093 << "current_colliding has " << _current_colliding.size() 00094 << " entries, last_colliding has " << _last_colliding.size() 00095 << "\n"; 00096 } 00097 00098 Colliding::iterator ca, cb; 00099 00100 ca = _current_colliding.begin(); 00101 cb = _last_colliding.begin(); 00102 00103 SortEntries order; 00104 while (ca != _current_colliding.end() && cb != _last_colliding.end()) { 00105 if (order(*ca, *cb)) { 00106 // Here's an element in a but not in b. That's a newly entered 00107 // intersection. 00108 throw_event_for(_in_patterns, *ca); 00109 ++ca; 00110 } else if (order(*cb, *ca)) { 00111 // Here's an element in b but not in a. That's a newly exited 00112 // intersection. 00113 throw_event_for(_out_patterns, *cb); 00114 ++cb; 00115 } else { 00116 // This element is in both b and a. It hasn't changed. 00117 throw_event_for(_again_patterns, *cb); 00118 ++ca; 00119 ++cb; 00120 } 00121 } 00122 00123 while (ca != _current_colliding.end()) { 00124 // Here's an element in a but not in b. That's a newly entered 00125 // intersection. 00126 throw_event_for(_in_patterns, *ca); 00127 ++ca; 00128 } 00129 00130 while (cb != _last_colliding.end()) { 00131 // Here's an element in b but not in a. That's a newly exited 00132 // intersection. 00133 throw_event_for(_out_patterns, *cb); 00134 ++cb; 00135 } 00136 00137 return true; 00138 } 00139 00140 //////////////////////////////////////////////////////////////////// 00141 // Function: CollisionHandlerEvent::clear 00142 // Access: Public 00143 // Description: Empties the list of elements that all colliders are 00144 // known to be colliding with. No "out" events will be 00145 // thrown; if the same collision is detected next frame, 00146 // a new "in" event will be thrown for each collision. 00147 // 00148 // This can be called each frame to defeat the 00149 // persistent "in" event mechanism, which prevents the 00150 // same "in" event from being thrown repeatedly. 00151 // However, also see add_again_pattern(), which can be 00152 // used to set the event that is thrown when a collision 00153 // is detected for two or more consecutive frames. 00154 //////////////////////////////////////////////////////////////////// 00155 void CollisionHandlerEvent:: 00156 clear() { 00157 _last_colliding.clear(); 00158 _current_colliding.clear(); 00159 } 00160 00161 //////////////////////////////////////////////////////////////////// 00162 // Function: CollisionHandlerEvent::flush 00163 // Access: Public 00164 // Description: Same as clear() except "out" events are thrown. 00165 //////////////////////////////////////////////////////////////////// 00166 void CollisionHandlerEvent:: 00167 flush() { 00168 begin_group(); 00169 end_group(); 00170 } 00171 00172 //////////////////////////////////////////////////////////////////// 00173 // Function: CollisionHandlerEvent::throw_event_for 00174 // Access: Private 00175 // Description: Throws whatever events are suggested by the list of 00176 // patterns. 00177 //////////////////////////////////////////////////////////////////// 00178 void CollisionHandlerEvent:: 00179 throw_event_for(const vector_string &patterns, CollisionEntry *entry) { 00180 vector_string::const_iterator pi; 00181 for (pi = patterns.begin(); pi != patterns.end(); ++pi) { 00182 throw_event_pattern(*pi, entry); 00183 } 00184 } 00185 00186 //////////////////////////////////////////////////////////////////// 00187 // Function: CollisionHandlerEvent::throw_event_pattern 00188 // Access: Private 00189 // Description: Throws an event matching the indicated pattern. 00190 //////////////////////////////////////////////////////////////////// 00191 void CollisionHandlerEvent:: 00192 throw_event_pattern(const string &pattern, CollisionEntry *entry) { 00193 if (pattern.empty()) { 00194 return; 00195 } 00196 00197 string event; 00198 for (size_t p = 0; p < pattern.size(); ++p) { 00199 if (pattern[p] == '%') { 00200 string key; 00201 if (p + 1 < pattern.size() && pattern[p + 1] == '(') { 00202 // Extract out the key--the name up until the closing paren. 00203 size_t close = pattern.find(')', p + 2); 00204 if (close != string::npos) { 00205 key = pattern.substr(p + 2, close - (p + 2)); 00206 p = close; 00207 } 00208 } 00209 00210 // Get out the command--the two characters following the percent 00211 // sign (or the key). 00212 string cmd = pattern.substr(p + 1, 2); 00213 p += 2; 00214 if (cmd == "fn") { 00215 event += entry->get_from_node()->get_name(); 00216 00217 } else if (cmd == "in") { 00218 if (entry->has_into()) { 00219 event += entry->get_into_node()->get_name(); 00220 } 00221 00222 } else if (cmd == "fs") { 00223 event += 00224 (!entry->get_from()->is_tangible() ? 'i' : 't'); 00225 00226 } else if (cmd == "is") { 00227 event += 00228 (entry->has_into() && !entry->get_into()->is_tangible() ? 'i' : 't'); 00229 00230 } else if (cmd == "ig") { 00231 event += 00232 (entry->has_into() ? 'c' : 'g'); 00233 00234 } else if (cmd == "fh") { 00235 if (!entry->get_from_node_path().has_net_tag(key)) { 00236 return; 00237 } 00238 00239 } else if (cmd == "fx") { 00240 if (entry->get_from_node_path().has_net_tag(key)) { 00241 return; 00242 } 00243 00244 } else if (cmd == "ih") { 00245 if (!(entry->has_into() && entry->get_into_node_path().has_net_tag(key))) { 00246 return; 00247 } 00248 00249 } else if (cmd == "ix") { 00250 if (entry->has_into() && entry->get_into_node_path().has_net_tag(key)) { 00251 return; 00252 } 00253 00254 } else if (cmd == "ft") { 00255 event += entry->get_from_node_path().get_net_tag(key); 00256 00257 } else if (cmd == "it") { 00258 if (entry->has_into()) { 00259 event += entry->get_into_node_path().get_net_tag(key); 00260 } 00261 00262 } else { 00263 collide_cat.error() 00264 << "Invalid symbol in event_pattern: %" << cmd << "\n"; 00265 } 00266 } else { 00267 event += pattern[p]; 00268 } 00269 } 00270 00271 if (!event.empty()) { 00272 throw_event(event, EventParameter(entry)); 00273 } 00274 }