Panda3D
collisionHandlerFloor.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 collisionHandlerFloor.cxx
10  * @author drose
11  * @date 2002-03-16
12  */
13 
14 #include "collisionHandlerFloor.h"
15 #include "collisionNode.h"
16 #include "collisionEntry.h"
17 #include "config_collide.h"
18 
19 #include "clockObject.h"
20 
21 using std::cout;
22 using std::endl;
23 
24 TypeHandle CollisionHandlerFloor::_type_handle;
25 
26 /**
27  *
28  */
29 CollisionHandlerFloor::
30 CollisionHandlerFloor() {
31  _offset = 0.0f;
32  _reach = 1.0f;
33  _max_velocity = 0.0f;
34 }
35 
36 /**
37  *
38  */
39 CollisionHandlerFloor::
40 ~CollisionHandlerFloor() {
41 }
42 
43 /**
44  * Serializes this object, to implement pickle support.
45  */
47 write_datagram(Datagram &dg) const {
49 
50  dg.add_float64(_offset);
51  dg.add_float64(_reach);
52  dg.add_float64(_max_velocity);
53 }
54 
55 /**
56  * Restores the object state from the given datagram, previously obtained using
57  * __getstate__.
58  */
62 
63  _offset = scan.get_float64();
64  _reach = scan.get_float64();
65  _max_velocity = scan.get_float64();
66 }
67 
68 /**
69  *
70  */
71 PN_stdfloat CollisionHandlerFloor::
72 set_highest_collision(const NodePath &target_node_path, const NodePath &from_node_path, const Entries &entries) {
73  // Get the maximum height for all collisions with this node. This is really
74  // the distance to-the-ground, so it will be negative when the avatar is
75  // above the ground. Larger values (less negative) are higher elevation
76  // (assuming the avatar is right-side-up (or the ray is plumb)).
77  bool got_max = false;
78  bool got_min = false;
79  PN_stdfloat max_height = 0.0f;
80  PN_stdfloat min_height = 0.0f;
81  CollisionEntry *highest = nullptr;
82  CollisionEntry *lowest = nullptr;
83 
84  Entries::const_iterator ei;
85  for (ei = entries.begin(); ei != entries.end(); ++ei) {
86  CollisionEntry *entry = (*ei);
87  nassertr(entry != nullptr, 0.0f);
88  nassertr(from_node_path == entry->get_from_node_path(), 0.0f);
89 
90  if (entry->has_surface_point()) {
91  LPoint3 point = entry->get_surface_point(target_node_path);
92  if (collide_cat.is_debug()) {
93  collide_cat.debug()
94  << "Intersection point detected at " << point << "\n";
95  }
96 
97  PN_stdfloat height = point[2];
98  if (height < _offset + _reach &&
99  (!got_max || height > max_height)) {
100  got_max = true;
101  max_height = height;
102  highest = entry;
103  }
104  if (!got_min || height < min_height) {
105  got_min = true;
106  min_height = height;
107  lowest = entry;
108  }
109  }
110  }
111  if (!got_max && got_min) {
112  // We've fallen through the world, but we're also under some walkable
113  // geometry. Move us up to the lowest surface:
114  got_max = true;
115  max_height = min_height;
116  highest = lowest;
117  }
118  // #*#_has_contact = got_max;
119 
120  #if 0
121  cout<<"\ncolliding with:\n";
122  for (Colliding::const_iterator i = _current_colliding.begin(); i != _current_colliding.end(); ++i) {
123  (**i).write(cout, 2);
124  }
125  cout<<"\nhighest:\n";
126  highest->write(cout, 2);
127  cout<<endl;
128  #endif
129  #if 1
130  // We only collide with things we are impacting with. Remove the
131  // collisions:
132  _current_colliding.clear();
133  // Add only the one that we're impacting with:
134  add_entry(highest);
135  #endif
136 
137  return max_height;
138 }
139 
140 /**
141  * Called by the parent class after all collisions have been detected, this
142  * manages the various collisions and moves around the nodes as necessary.
143  *
144  * The return value is normally true, but it may be false to indicate the
145  * CollisionTraverser should disable this handler from being called in the
146  * future.
147  */
148 bool CollisionHandlerFloor::
149 handle_entries() {
150  bool okflag = true;
151 
152  // Reset the set of things our parent class CollisionHandlerEvent recorded a
153  // collision with. We'll only consider ourselves collided with the topmost
154  // object for each from_entry.
155  _current_colliding.clear();
156 
157  FromEntries::const_iterator fi;
158  for (fi = _from_entries.begin(); fi != _from_entries.end(); ++fi) {
159  const NodePath &from_node_path = (*fi).first;
160  const Entries &entries = (*fi).second;
161 
162  Colliders::iterator ci;
163  ci = _colliders.find(from_node_path);
164  if (ci == _colliders.end()) {
165  // Hmm, someone added a CollisionNode to a traverser and gave it this
166  // CollisionHandler pointer--but they didn't tell us about the node.
167  collide_cat.error()
168  << get_type() << " doesn't know about "
169  << from_node_path << ", disabling.\n";
170  okflag = false;
171  } else {
172  ColliderDef &def = (*ci).second;
173  {
174  #if 0
175  // Get the maximum height for all collisions with this node.
176  bool got_max = false;
177  PN_stdfloat max_height = 0.0f;
178  CollisionEntry *max_entry = nullptr;
179 
180  Entries::const_iterator ei;
181  for (ei = entries.begin(); ei != entries.end(); ++ei) {
182  CollisionEntry *entry = (*ei);
183  nassertr(entry != nullptr, false);
184  nassertr(from_node_path == entry->get_from_node_path(), false);
185 
186  if (entry->has_surface_point()) {
187  LPoint3 point = entry->get_surface_point(def._target);
188  if (collide_cat.is_debug()) {
189  collide_cat.debug()
190  << "Intersection point detected at " << point << "\n";
191  }
192 
193  PN_stdfloat height = point[2];
194  if (!got_max || height > max_height) {
195  got_max = true;
196  max_height = height;
197  max_entry = entry;
198  }
199  }
200  }
201 
202  // Record a collision with the topmost element for the
203  // CollisionHandlerEvent base class.
204  _current_colliding.insert(max_entry);
205 
206  // Now set our height accordingly.
207  PN_stdfloat adjust = max_height + _offset;
208  #else
209  PN_stdfloat max_height = set_highest_collision(def._target, from_node_path, entries);
210 
211  // Now set our height accordingly.
212  PN_stdfloat adjust = max_height + _offset;
213  #endif
214  if (!IS_THRESHOLD_ZERO(adjust, 0.001)) {
215  if (collide_cat.is_debug()) {
216  collide_cat.debug()
217  << "Adjusting height by " << adjust << "\n";
218  }
219 
220  if (adjust < 0.0f && _max_velocity != 0.0f) {
221  PN_stdfloat max_adjust =
222  _max_velocity * ClockObject::get_global_clock()->get_dt();
223  adjust = std::max(adjust, -max_adjust);
224  }
225 
226  CPT(TransformState) trans = def._target.get_transform();
227  LVecBase3 pos = trans->get_pos();
228  pos[2] += adjust;
229  def._target.set_transform(trans->set_pos(pos));
230  def.updated_transform();
231 
232  apply_linear_force(def, LVector3(0.0f, 0.0f, adjust));
233  } else {
234  if (collide_cat.is_spam()) {
235  collide_cat.spam()
236  << "Leaving height unchanged.\n";
237  }
238  }
239  }
240  }
241  }
242 
243  return okflag;
244 }
245 
246 /**
247  *
248  */
249 void CollisionHandlerFloor::
250 apply_linear_force(ColliderDef &def, const LVector3 &force) {
251 }
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.
Definition: clockObject.I:215
Defines a single collision event.
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.
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.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
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:316
Indicates a coordinate-system transform on vertices.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.