Panda3D
Loading...
Searching...
No Matches
collisionHandlerGravity.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 collisionHandlerGravity.cxx
10 * @author drose
11 * @date 2002-03-16
12 */
13
15#include "collisionNode.h"
16#include "collisionEntry.h"
17#include "config_collide.h"
18#include "collisionPlane.h"
19#include "clockObject.h"
20
21using std::cout;
22using std::endl;
23
24TypeHandle CollisionHandlerGravity::_type_handle;
25
26/**
27 *
28 */
29CollisionHandlerGravity::
30CollisionHandlerGravity() {
31 _offset = 0.0f;
32 _reach = 1.0f;
33 _airborne_height = 0.0f;
34 _impact_velocity = 0.0f;
35 _gravity = 32.174;
36 _current_velocity = 0.0f;
37 _max_velocity = 400.0f;
38 _contact_normal = LVector3::zero();
39 _legacy_mode = false;
40}
41
42/**
43 *
44 */
45CollisionHandlerGravity::
46~CollisionHandlerGravity() {
47}
48
49/**
50 * Serializes this object, to implement pickle support.
51 */
53write_datagram(Datagram &dg) const {
55
56 dg.add_float64(_offset);
57 dg.add_float64(_reach);
58 dg.add_float64(_max_velocity);
59 dg.add_float64(_gravity);
60 dg.add_bool(_legacy_mode);
61}
62
63/**
64 * Restores the object state from the given datagram, previously obtained using
65 * __getstate__.
66 */
70
71 _offset = scan.get_float64();
72 _reach = scan.get_float64();
73 _max_velocity = scan.get_float64();
74 _gravity = scan.get_float64();
75 _legacy_mode = scan.get_bool();
76}
77
78/**
79 *
80 */
81#define OLD_COLLISION_HANDLER_GRAVITY 0
82#if OLD_COLLISION_HANDLER_GRAVITY
83PN_stdfloat CollisionHandlerGravity::
84set_highest_collision(const NodePath &target_node_path, const NodePath &from_node_path, const Entries &entries) {
85 // Get the maximum height for all collisions with this node.
86 bool got_max = false;
87 PN_stdfloat max_height = 0.0f;
88 CollisionEntry *highest = nullptr;
89
90 Entries::const_iterator ei;
91 for (ei = entries.begin(); ei != entries.end(); ++ei) {
92 CollisionEntry *entry = (*ei);
93 nassertr(entry != nullptr, 0.0f);
94 nassertr(from_node_path == entry->get_from_node_path(), 0.0f);
95
96 if (entry->has_surface_point()) {
97 LPoint3 point = entry->get_surface_point(target_node_path);
98 if (collide_cat.is_debug()) {
99 collide_cat.debug()
100 << "Intersection point detected at " << point << "\n";
101 }
102
103 PN_stdfloat height = point[2];
104 if (!got_max || height > max_height) {
105 got_max = true;
106 max_height = height;
107 highest = entry;
108 }
109 }
110 }
111 // #*#_has_contact = got_max;
112
113 #if 0
114 cout<<"\ncolliding with:\n";
115 for (Colliding::const_iterator i = _current_colliding.begin(); i != _current_colliding.end(); ++i) {
116 (**i).write(cout, 2);
117 }
118 cout<<"\nhighest:\n";
119 highest->write(cout, 2);
120 cout<<endl;
121 #endif
122
123 if (_legacy_mode) {
124 // We only collide with things we are impacting with. Remove the
125 // collisions:
126 _current_colliding.clear();
127 // Add only the one that we're impacting with:
128 add_entry(highest);
129 }
130
131 return max_height;
132}
133#else
134PN_stdfloat CollisionHandlerGravity::
135set_highest_collision(const NodePath &target_node_path, const NodePath &from_node_path, const Entries &entries) {
136 // Get the maximum height for all collisions with this node. This is really
137 // the distance to-the-ground, so it will be negative when the avatar is
138 // above the ground. Larger values (less negative) are higher elevation
139 // (assuming the avatar is right-side-up (or the ray is plumb)).
140 bool got_max = false;
141 bool got_min = false;
142 PN_stdfloat max_height = 0.0f;
143 PN_stdfloat min_height = 0.0f;
144 CollisionEntry *highest = nullptr;
145 CollisionEntry *lowest = nullptr;
146
147 pvector<PT(CollisionEntry)> valid_entries;
148
149 Entries::const_iterator ei;
150 for (ei = entries.begin(); ei != entries.end(); ++ei) {
151 CollisionEntry *entry = (*ei);
152 nassertr(entry != nullptr, 0.0f);
153 nassertr(from_node_path == entry->get_from_node_path(), 0.0f);
154
155 if (entry->has_surface_point()) {
156 LPoint3 point = entry->get_surface_point(target_node_path);
157 if (collide_cat.is_debug()) {
158 collide_cat.debug()
159 << "Intersection point detected at " << point << "\n";
160 }
161 PN_stdfloat height = point[2];
162 if(height < _offset + _reach) {
163 valid_entries.push_back(entry);
164 if (!got_max || height > max_height) {
165 got_max = true;
166 max_height = height;
167 highest = entry;
168 }
169 }
170 if (!got_min || height < min_height) {
171 got_min = true;
172 min_height = height;
173 lowest = entry;
174 }
175 }
176 }
177 if (!got_max && got_min) {
178 // We've fallen through the world, but we're also under some walkable
179 // geometry. Move us up to the lowest surface:
180 got_max = true;
181 max_height = min_height;
182 highest = lowest;
183 valid_entries.push_back(lowest);
184 }
185 // #*#_has_contact = got_max;
186
187 #if 0
188 cout<<"\ncolliding with:\n";
189 for (Colliding::const_iterator i = _current_colliding.begin(); i != _current_colliding.end(); ++i) {
190 (**i).write(cout, 2);
191 }
192 cout<<"\nhighest:\n";
193 highest->write(cout, 2);
194 cout<<endl;
195 #endif
196
197 // We only collide with things we are impacting with. Remove the
198 // collisions:
199 _current_colliding.clear();
200 if (_legacy_mode) {
201 // Add only the one that we're impacting with:
202 add_entry(highest);
203 } else {
204 // Add all of them.
205 pvector<PT(CollisionEntry)>::iterator vi;
206 for (vi = valid_entries.begin(); vi != valid_entries.end(); ++vi) {
207 add_entry(*vi);
208 }
209 }
210
211
212 // Set the contact normal so that other code can make use of the surface
213 // slope:
214 if (highest->get_into()->is_of_type(CollisionPlane::get_class_type())) {
215/*
216 * This is asking: what is the normal of the plane that the avatar is
217 * colliding with relative to the avatar. A positive y valye means the avatar
218 * is facing downhill and a negative y value means the avatar is facing
219 * uphill. _contact_normal = DCAST(CollisionPlane,
220 * highest->get_into())->get_normal() *
221 * from_node_path.get_mat(highest->get_into_node_path()); _contact_normal =
222 * DCAST(CollisionPlane, highest->get_into())->get_normal(); This is asking:
223 * what is the normal of the avatar that the avatar is colliding with relative
224 * to the plane.
225 */
226 CPT(TransformState) transform = highest->get_into_node_path().get_transform(from_node_path);
227 _contact_normal = DCAST(CollisionPlane, highest->get_into())->get_normal() * transform->get_mat();
228 } else {
229 _contact_normal = highest->get_surface_normal(from_node_path);
230 }
231
232 return max_height;
233}
234#endif
235
236/**
237 * Called by the parent class after all collisions have been detected, this
238 * manages the various collisions and moves around the nodes as necessary.
239 *
240 * The return value is normally true, but it may be false to indicate the
241 * CollisionTraverser should disable this handler from being called in the
242 * future.
243 */
244bool CollisionHandlerGravity::
245handle_entries() {
246 bool okflag = true;
247
248 FromEntries::const_iterator fi;
249 for (fi = _from_entries.begin(); fi != _from_entries.end(); ++fi) {
250 const NodePath &from_node_path = (*fi).first;
251 const Entries &entries = (*fi).second;
252
253 Colliders::iterator ci;
254 ci = _colliders.find(from_node_path);
255 if (ci == _colliders.end()) {
256 // Hmm, someone added a CollisionNode to a traverser and gave it this
257 // CollisionHandler pointer--but they didn't tell us about the node.
258 collide_cat.error()
259 << get_type() << " doesn't know about "
260 << from_node_path << ", disabling.\n";
261 okflag = false;
262 } else {
263 ColliderDef &def = (*ci).second;
264 PN_stdfloat max_height = set_highest_collision(def._target, from_node_path, entries);
265
266 // Now set our height accordingly.
267 #if OLD_COLLISION_HANDLER_GRAVITY
268 PN_stdfloat adjust = max_height + _offset;
269 #else
270 PN_stdfloat adjust = max_height + _offset;
271 #endif
272 if (_current_velocity > 0.0f || !IS_THRESHOLD_ZERO(adjust, 0.001)) {
273 if (collide_cat.is_debug()) {
274 collide_cat.debug()
275 << "Adjusting height by " << adjust << "\n";
276 }
277
278 if (_current_velocity > 0.0f || adjust) {
279 // ...we have a vertical thrust, ...or the node is above the floor,
280 // so it is airborne.
281 PN_stdfloat dt = ClockObject::get_global_clock()->get_dt();
282 // Fyi, the sign of _gravity is reversed. I think it makes the
283 // get_*() set_*() more intuitive to do it this way.
284 PN_stdfloat gravity_adjust = _current_velocity * dt + 0.5 * -_gravity * dt * dt;
285 if (adjust > 0.0f) {
286 // ...the node is under the floor, so it has landed. Keep the
287 // adjust to bring us up to the ground and then add the
288 // gravity_adjust to get us airborne:
289 adjust += std::max((PN_stdfloat)0.0, gravity_adjust);
290 } else {
291 // ...the node is above the floor, so it is airborne.
292 adjust = std::max(adjust, gravity_adjust);
293 }
294 _current_velocity -= _gravity * dt;
295 // Record the airborne height in case someone else needs it:
296 _airborne_height = -(max_height + _offset) + adjust;
297 assert(_airborne_height >= -0.001f);
298 }
299
300 if (_airborne_height < 0.001f && _current_velocity < 0.001f) {
301 // ...the node is under the floor, so it has landed.
302 _impact_velocity = _current_velocity;
303 // These values are used by is_on_ground().
304 _current_velocity = _airborne_height = 0.0f;
305 } else if (_legacy_mode) {
306 // ...we're airborne.
307 _current_colliding.clear();
308 }
309
310 CPT(TransformState) trans = def._target.get_transform();
311 LVecBase3 pos = trans->get_pos();
312 pos[2] += adjust;
313 def._target.set_transform(trans->set_pos(pos));
314 def.updated_transform();
315
316 apply_linear_force(def, LVector3(0.0f, 0.0f, adjust));
317 } else {
318 // _impact_velocity = _current_velocity;
319 _current_velocity = _airborne_height = 0.0f;
320 if (collide_cat.is_spam()) {
321 collide_cat.spam()
322 << "Leaving height unchanged.\n";
323 }
324 }
325 }
326 }
327
328 return okflag;
329}
330
331/**
332 *
333 */
334void CollisionHandlerGravity::
335apply_linear_force(ColliderDef &def, const LVector3 &force) {
336}
get_dt
Returns the elapsed time for the previous frame: the number of seconds elapsed between the last two c...
Definition clockObject.h:99
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Defines a single collision event.
get_into
Returns the CollisionSolid pointer for the particular solid was collided into.
LPoint3 get_surface_point(const NodePath &space) const
Returns the point, on the surface of the "into" object, at which a collision is detected.
get_from_node_path
Returns the NodePath that represents the CollisionNode that contains the CollisionSolid that triggere...
bool has_surface_point() const
Returns true if the surface point has been specified, false otherwise.
LVector3 get_surface_normal(const NodePath &space) const
Returns the surface normal of the "into" object at the point at which a collision is detected.
get_into_node_path
Returns the NodePath that represents the specific CollisionNode or GeomNode instance that was collide...
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 void add_entry(CollisionEntry *entry)
Called between a begin_group() .
A class to retrieve the individual data elements previously stored in a Datagram.
PN_float64 get_float64()
Extracts a 64-bit floating-point number.
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
void add_float64(PN_float64 value)
Adds a 64-bit floating-point number to the datagram.
Definition datagram.I:123
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
This is our own Panda specialization on the default STL vector.
Definition pvector.h:42
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.