JNR
laPivot.cpp
1 /*
2 
3 Jump'n'Run Engine
4 http://www.atanaslaskov.com/jnr/
5 
6 BSD LICENSE
7 Copyright (c) 2007-2013, Atanas Laskov
8 All rights reserved.
9 
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions are met:
12 1. Redistributions of source code must retain the above copyright notice,
13 this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright notice,
15 this list of conditions and the following disclaimer in the documentation
16 and/or other materials provided with the distribution.
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL ATANAS LASKOV BE LIABLE FOR ANY
21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 */
29 
30 //
31 // FILE: laPivot.cpp
32 // Material point simulation class
33 //
34 // Copyright (C) 2007-2013 Atanas Laskov, <latanas@gmail.com>
35 //
36 #include "stdafx.h"
37 #include "Core.h"
38 
39 laCollider* laPivot::_pCollider = NULL;
40 laCollisionDomain *laPivot::_pFirstDomain = NULL;
41 unsigned long laPivot::_nDomains = 0;
42 
43 laPivot::laPivot(void)
44 {
45  angleX = angleY = angleZ = 0;
46 
47  bSimulateCollision = bSimulateGravitation = M_TRUE;
48 
49  pTrap = NULL;
50  bOnGround = M_FALSE;
51  dShadowY = 0;
52 
53  velocity = laPoint3();
54  size = laPoint3(M_UNIT/2.0, M_UNIT/2.0);
55  mass = 1;
56 
57  // Instantiate collider algorithm
58  //
59  if( ! laPivot::_pCollider ) {
60  laPivot::_pCollider = new laCollider();
61  }
62 }
63 
64 // Simulate gravitation
65 // NOTE: This method updates the velocity.y() in accordance to gravitation,
66 // also taking in account collisions
67 //
68 void laPivot::_sim_gravitation(laTimer &t)
69 {
70  PROFILE_COL(laPivot__sim_gravitation);
71  laCollisionScenario csGravitation;
72 
73  csGravitation.pFirstDomain = _pFirstDomain;
74  csGravitation.nDomains = _nDomains;
75 
76  // Baseline used for checking if the player is on the ground
77  //
78  // NOTE: The +-M_NORMAL_RESPONSE is a fail-safe margin, and guarantees no false positives for (bOnGround);
79  // In the same time it's important to have a *very small* margin ( like M_NORMAL_RESPONSE ),
80  // otherwise there is a chance for false negatives when character lands on the very edge of the bounding box;
81  //
82  laLine2 lnBase( laPoint3(-size.x()*0.5 + M_NORMAL_RESPONSE, 0), laPoint3(+size.x()*0.5 - M_NORMAL_RESPONSE, 0) );
83 
84  // Initialize csGravitation to detect whether the object is flying or is on the ground
85  //
86  csGravitation.ptPosition = (laPoint3)(*this);
87  csGravitation.ptVector = laPoint3(0, +M_GRAVITATIONAL_HOVER);
88 
89  _pCollider->collideLineWithDomain(lnBase, &csGravitation, 1, M_FALSE);
90  bOnGround = csGravitation.bCollision;
91  pTrap = NULL;
92 
93  if( csGravitation.bCollision )
94  {
95  // The object is on the ground, so nullify velocity along (y);
96  // This prevents the object from gaining momentum while resting on a surface;
97  //
98  velocity[1] = M_MIN(0, velocity.y());
99 
100  // Triggered a trap?
101  if( csGravitation.bCollision && (csGravitation.pTrap!=NULL) )
102  pTrap = csGravitation.pTrap;
103  }
104  else
105  {
106  // Apply force of gravity
107  velocity[1] += M_GRAVITATION_ACC*t.delta()*M_UNIT * mass;
108 
109  // Prevent from getting stuck at the ceiling when jumping
110  //
111  laLine2 lnTop( laPoint3(-size.x()*0.5 - M_NORMAL_RESPONSE, -size.y()), laPoint3(+size.x()*0.5 + M_NORMAL_RESPONSE, -size.y()) );
112  csGravitation.ptVector.y( csGravitation.ptVector.y() * -1 );
113  _pCollider->collideLineWithDomain(lnTop, &csGravitation, 1, M_FALSE);
114 
115  // If there was a collision with the ceiling, start dropping
116  //
117  if( csGravitation.bCollision ) velocity[1] = M_MAX(0, velocity.y());
118  }
119 }
120 
121 
122 // Simulate collisions
123 //
124 laPoint3 laPivot::_sim_collisions(laTimer &t)
125 {
126  PROFILE_COL(laPivot__sim_collisions);
127  laCollisionScenario cs;
128 
129  cs.pFirstDomain = _pFirstDomain;
130  cs.nDomains = _nDomains;
131 
132  // Sim collisions
133  //
134  cs.ptVector = _displacement_vector(t, velocity);
135  cs.ptPosition = (laPoint3)(*this);
136 
137  // Object envelope
138  //
139  laLine2 ln[4];
140 
141  // NOTE: The upper line seems to resolve (partially) the 1-lonely-blcok penetration bug
142  // Filtering it would require solving this bug
143  //
144  //if( cs.ptVector.y() >= 0)
145  ln[0] = laLine2(laPoint2(-size.x()*0.5, 0), laPoint2(+size.x()*0.5, 0));
146  //else
147  ln[1] = laLine2(laPoint2(-size.x()*0.5, -size.y()), laPoint2(+size.x()*0.5, -size.y()));
148 
149  //if( cs.ptVector.x() >= 0)
150  ln[2] = laLine2(laPoint2(+size.x()*0.5, 0), laPoint2(+size.x()*0.5, -size.y()));
151  //else
152  ln[3] = laLine2(laPoint2(-size.x()*0.5, 0), laPoint2(-size.x()*0.5, -size.y()));
153 
154  ::laSystemIntegrator::getRenderer()->styleSet( laColor(0,0,255) );
155  ::laSystemIntegrator::getRenderer()->styleLine( 1 );
156  for(unsigned i=0; i<4; i++) ln[i].draw(::laSystemIntegrator::getRenderer(), cs.ptPosition);
157  ::laSystemIntegrator::getRenderer()->drawLine(cs.ptPosition, cs.ptPosition+cs.ptVector);
158 
159  _pCollider->collideLinesWithDomain(ln, 4, &cs, 3);
160  return cs.ptModifiedVector;
161 }
162 
163 // Project a false shadow
164 //
165 void laPivot::projectShadow()
166 {
167  PROFILE_COL(laPivot_projectShadow);
168  ASSERT(_pCollider, "Nil collider");
169  ASSERT(_pFirstDomain, "Nil first collision domain");
170  laCollisionScenario csShadow;
171 
172  csShadow.pFirstDomain = _pFirstDomain;
173  csShadow.nDomains = _nDomains;
174  csShadow.ptPosition = (laPoint3)(*this);
175  csShadow.ptVector = laPoint2(0, M_UNIT*M_SEGH);
176 
177  _pCollider->collidePointWithDomain(&csShadow, 0, M_FALSE);
178  dShadowY = y() + csShadow.ptModifiedVector.y() - M_NORMAL_RESPONSE*0.1;
179 }
180 
181 // Query the collider with a vector
182 // NOTE: Can be used for implementing AI "tentacles" i.e. sensing the surroundsings of a monster
184 laPoint3 laPivot::projectVector( laPoint3 vector, M_BOOL *pTrapFlag, rpgTrap** ppTrap )
185 {
186  PROFILE_COL(laPivot_projectVector);
187  ASSERT(_pCollider, "Nil collider");
188  ASSERT(_pFirstDomain, "Nil first collision domain domain");
189 
190  laCollisionScenario VectorCol;
191 
192  VectorCol.pFirstDomain = _pFirstDomain;
193  VectorCol.nDomains = _nDomains;
194  VectorCol.ptPosition = (laPoint3)(*this);
195  VectorCol.ptVector = vector;
196 
197  _pCollider->collidePointWithDomain(&VectorCol, 1, M_FALSE);
198 
199  if(VectorCol.bCollision && pTrapFlag)
200  {
201  if(VectorCol.pTrap)
202  {
203  *pTrapFlag = M_TRUE;
204  if(ppTrap) { *ppTrap = VectorCol.pTrap; }
205  }
206  else *pTrapFlag = M_FALSE;
207  }
208 
209  return VectorCol.ptModifiedVector;
210 }
211 
212 
213 // Update velocity ( opt. without moving the object )
214 //
215 /*void laPivot::_sim_forces(laTimer &t, M_BOOL bAnimatePosition)
216 {
217  laPoint3 acceleration;
218 
219  //Use all acting forces to calculate the acceleration
220  for(unsigned i=0; i<lsForces.size(); i++)
221  {
222  lsForces[i]->_cbTrig.animate(t);
223 
224  acceleration[0] += lsForces[i]->compX()/mass;
225  acceleration[1] += lsForces[i]->compY()/mass;
226 
227  if( lsForces[i]->_cbTrig.isEnabled() && (!lsForces[i]->_cbTrig.isElapsed()) )
228  forceRemove(i);
229  }
230 
231  //Apply the acceleration
232  velocity += acceleration*t.delta();
233 
234  //Move the object according to the calculated speed (if requested)
235 
236  if(bAnimatePosition)
237  {
238  x += velocity.x()*t.delta()*M_UNIT;
239  y += velocity.y()*t.delta()*M_UNIT;
240  }
241 }*/
242 
243 /*unsigned laPivot::forceAdd(laPhForce* f)
244 {
245  lsForces.push_back(f);
246  return lsForces.size()-1;
247 }
248 
249 unsigned laPivot::forceAdd(laPhForce* f, double sec)
250 {
251  unsigned i = forceAdd(f);
252  lsForces[i]->_cbTrig.setHoldTime(sec);
253  lsForces[i]->_cbTrig.enable();
254  lsForces[i]->_cbTrig.reset();
255  return i;
256 }
257 
258 laPhForce* laPivot::forceRemove(unsigned id)
259 {
260  ASSERT( id<lsForces.size(), "Attempt to remove unregistered force (%d)", id);
261 
262  lsForces.erase(lsForces.begin()+id);
263  return NULL;
264 }
265 
266 laPhForce* laPivot::forceGet(unsigned id)
267 {
268  ASSERT( id<lsForces.size(), "Attempt to get unregistered force (%d)", id);
269  return lsForces[id];
270 }*/
#define M_GRAVITATION_ACC
Force of gravity accelleration;.
#define M_NORMAL_RESPONSE
Distance an object "bounces back" form a collision surface.
#define M_UNIT
Unit of 1 meter.
2D Point
Definition: laPoint_novec.h:41
Trap Properties.
Definition: rpgTrap.h:42
Collision Detection and Response.
Definition: laCollider.h:41
2D line segment
Definition: laLine2.h:40
Collision Domain.
#define M_GRAVITATIONAL_HOVER
Gravity surface distance.