Panda3D
Loading...
Searching...
No Matches
collisionHandlerPusher.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 collisionHandlerPusher.cxx
10 * @author drose
11 * @date 2002-03-16
12 */
13
15#include "collisionNode.h"
16#include "collisionEntry.h"
17#include "collisionPolygon.h"
18#include "config_collide.h"
19#include "dcast.h"
20#include "epvector.h"
21
22TypeHandle CollisionHandlerPusher::_type_handle;
23
24/**
25 * The ShoveData class is used within
26 * CollisionHandlerPusher::handle_entries(), to track multiple shoves onto a
27 * given collider. It's not exported outside this file.
28 */
29class ShoveData {
30public:
31 LVector3 _vector;
32 PN_stdfloat _length;
33 bool _valid;
34 CollisionEntry *_entry;
35};
36
37/**
38 *
39 */
40CollisionHandlerPusher::
41CollisionHandlerPusher() {
42 _horizontal = pushers_horizontal;
43}
44
45/**
46 *
47 */
48CollisionHandlerPusher::
49~CollisionHandlerPusher() {
50}
51
52/**
53 * Serializes this object, to implement pickle support.
54 */
61
62/**
63 * Restores the object state from the given datagram, previously obtained using
64 * __getstate__.
65 */
72
73/**
74 * Called by the parent class after all collisions have been detected, this
75 * manages the various collisions and moves around the nodes as necessary.
76 *
77 * The return value is normally true, but it may be false to indicate the
78 * CollisionTraverser should disable this handler from being called in the
79 * future.
80 */
81bool CollisionHandlerPusher::
82handle_entries() {
83 bool okflag = true;
84
85 FromEntries::const_iterator fi;
86 for (fi = _from_entries.begin(); fi != _from_entries.end(); ++fi) {
87 const NodePath &from_node_path = (*fi).first;
88 const Entries &entries = (*fi).second;
89
90 Colliders::iterator ci;
91 ci = _colliders.find(from_node_path);
92 if (ci == _colliders.end()) {
93 // Hmm, someone added a CollisionNode to a traverser and gave it this
94 // CollisionHandler pointer--but they didn't tell us about the node.
95 collide_cat.error()
96 << "CollisionHandlerPusher doesn't know about "
97 << from_node_path << ", disabling.\n";
98 okflag = false;
99 } else {
100 ColliderDef &def = (*ci).second;
101 {
102 // How to apply multiple shoves from different solids onto the same
103 // collider? One's first intuition is to vector sum all the shoves.
104 // However, this causes problems when two parallel walls shove on the
105 // collider, because we end up with a double shove. We hack around
106 // this by testing if two shove vectors share nearly the same
107 // direction, and if so, we keep only the longer of the two.
108
109 typedef epvector<ShoveData> Shoves;
110 Shoves shoves;
111
112 Entries::const_iterator ei;
113 for (ei = entries.begin(); ei != entries.end(); ++ei) {
114 CollisionEntry *entry = (*ei);
115 nassertr(entry != nullptr, false);
116 nassertr(from_node_path == entry->get_from_node_path(), false);
117
118 LPoint3 surface_point;
119 LVector3 normal;
120 LPoint3 interior_point;
121
122 if (!entry->get_all(def._target, surface_point, normal, interior_point)) {
123#ifndef NDEBUG
124 if (collide_cat.is_debug()) {
125 collide_cat.debug()
126 << "Cannot shove on " << from_node_path << " for collision into "
127 << entry->get_into_node_path() << "; no normal/depth information.\n";
128 }
129#endif
130 } else {
131 // Shove it just enough to clear the volume.
132 if (!surface_point.almost_equal(interior_point)) {
133 if (_horizontal) {
134 normal[2] = 0.0f;
135 }
136 // Just to be on the safe size, we normalize the normal vector,
137 // even though it really ought to be unit-length already (unless
138 // we just forced it horizontal, above).
139 normal.normalize();
140
141 ShoveData sd;
142 sd._vector = normal;
143 sd._length = (surface_point - interior_point).length();
144 sd._valid = true;
145 sd._entry = entry;
146
147 #ifndef NDEBUG
148 if (collide_cat.is_debug()) {
149 collide_cat.debug()
150 << "Shove on " << from_node_path << " from "
151 << entry->get_into_node_path() << ": " << sd._vector
152 << " times " << sd._length << "\n";
153 }
154 #endif
155
156 shoves.push_back(sd);
157 }
158 }
159 }
160
161 if (!shoves.empty()) {
162 // Now we look for two shoves that are largely in the same
163 // direction, so we can combine them into a single shove of the same
164 // magnitude; we also check for two shoves at 90 degrees, so we can
165 // detect whether we are hitting an inner or an outer corner.
166
167 Shoves::iterator si;
168 for (si = shoves.begin(); si != shoves.end(); ++si) {
169 ShoveData &sd = (*si);
170 Shoves::iterator sj;
171 for (sj = shoves.begin(); sj != si; ++sj) {
172 ShoveData &sd2 = (*sj);
173 if (sd2._valid) {
174 PN_stdfloat d = sd._vector.dot(sd2._vector);
175 if (collide_cat.is_debug()) {
176 collide_cat.debug()
177 << "Considering dot product " << d << "\n";
178 }
179
180 if (d > 0.9) {
181 // These two shoves are largely in the same direction; save
182 // the larger of the two.
183 if (sd2._length < sd._length) {
184 sd2._valid = false;
185 } else {
186 sd._valid = false;
187 }
188 } else {
189 // These two shoves are not in the same direction. If they
190 // are both from polygons that are a child of the same node,
191 // try to determine the shape of the corner (convex or
192 // concave).
193 const CollisionSolid *s1 = sd._entry->get_into();
194 const CollisionSolid *s2 = sd2._entry->get_into();
195 if (s1 != nullptr &&
196 s2 != nullptr &&
197 s1->is_of_type(CollisionPolygon::get_class_type()) &&
198 s2->is_of_type(CollisionPolygon::get_class_type()) &&
199 sd._entry->get_into_node_path() ==
200 sd2._entry->get_into_node_path()) {
201 const CollisionPolygon *p1 = DCAST(CollisionPolygon, s1);
202 const CollisionPolygon *p2 = DCAST(CollisionPolygon, s2);
203 if (p1->dist_to_plane(p2->get_collision_origin()) < 0 &&
204 p2->dist_to_plane(p1->get_collision_origin()) < 0) {
205 // Each polygon is behind the other one. That means we
206 // have a convex corner, and therefore we should discard
207 // one of the shoves (or the user will get stuck coming
208 // at a convex corner).
209 if (collide_cat.is_debug()) {
210 collide_cat.debug()
211 << "Discarding shove from convex corner.\n";
212 }
213
214 // This time, unlike the case of two parallel walls
215 // above, we discard the larger of the two shoves, not
216 // the smaller. This is because as we slide off the
217 // convex corner, the wall we are sliding away from will
218 // get a bigger and bigger shove--and we need to keep
219 // ignoring the same wall as we slide.
220 if (sd2._length < sd._length) {
221 sd._valid = false;
222 } else {
223 sd2._valid = false;
224 }
225 }
226 }
227 }
228 }
229 }
230 }
231
232 // Now we can determine the net shove.
233 LVector3 net_shove(0.0f, 0.0f, 0.0f);
234 LVector3 force_normal(0.0f, 0.0f, 0.0f);
235 for (si = shoves.begin(); si != shoves.end(); ++si) {
236 const ShoveData &sd = (*si);
237 if (sd._valid) {
238 net_shove += sd._vector * sd._length;
239 force_normal += sd._vector;
240 }
241 }
242
243 #ifndef NDEBUG
244 if (collide_cat.is_debug()) {
245 collide_cat.debug()
246 << "Net shove on " << from_node_path << " is: "
247 << net_shove << "\n";
248 }
249 #endif
250
251 // This is the part where the node actually gets moved:
252 CPT(TransformState) trans = def._target.get_transform();
253 LVecBase3 pos = trans->get_pos();
254 pos += net_shove * trans->get_mat();
255 def._target.set_transform(trans->set_pos(pos));
256 def.updated_transform();
257
258 // We call this to allow derived classes to do other fix-ups as they
259 // see fit:
260 apply_net_shove(def, net_shove, force_normal);
261 apply_linear_force(def, force_normal);
262 }
263 }
264 }
265 }
266
267 return okflag;
268}
269
270/**
271 * This is an optional hook for derived classes to do some work with the
272 * ColliderDef and the force vector.
273 */
274void CollisionHandlerPusher::
275apply_net_shove(ColliderDef &def, const LVector3 &net_shove,
276 const LVector3 &force_normal) {
277}
278
279/**
280 * This is an optional hook for derived classes to do some work with the
281 * ColliderDef and the force vector.
282 */
283void CollisionHandlerPusher::
284apply_linear_force(ColliderDef &def, const LVector3 &force_normal) {
285}
Defines a single collision event.
get_into
Returns the CollisionSolid pointer for the particular solid was collided into.
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...
bool get_all(const NodePath &space, LPoint3 &surface_point, LVector3 &surface_normal, LPoint3 &interior_point) const
Simultaneously transforms the surface point, surface normal, and interior point of the collision into...
void read_datagram(DatagramIterator &source)
Restores the object state from the given datagram, previously obtained using __getstate__.
void write_datagram(Datagram &destination) const
Serializes this object, to implement pickle support.
void write_datagram(Datagram &destination) const
Serializes this object, to implement pickle support.
void read_datagram(DatagramIterator &source)
Restores the object state from the given datagram, previously obtained using __getstate__.
virtual LPoint3 get_collision_origin() const
Returns the point in space deemed to be the "origin" of the solid for collision purposes.
The abstract base class for all things that can collide with other things in the world,...
A class to retrieve the individual data elements previously stored in a Datagram.
bool get_bool()
Extracts a boolean value.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition datagram.I:34
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition nodePath.h:159
NodePath find(const std::string &path) const
Searches for a node below the referenced node that matches the indicated string.
Definition nodePath.cxx:315
Indicates a coordinate-system transform on vertices.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition typedObject.I:28
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.