src/PhysicsObject.cc
changeset 428 712b943195a6
parent 427 01e77fe8c040
child 447 fc9e4305fddf
equal deleted inserted replaced
427:01e77fe8c040 428:712b943195a6
    24     if (enabled)
    24     if (enabled)
    25         enable();  
    25         enable();  
    26 }
    26 }
    27 
    27 
    28 PhysicsObject::~PhysicsObject (void) {
    28 PhysicsObject::~PhysicsObject (void) {
    29 //    Engine::log(DEBUG, "PhysicsObject.destructor") << this /* << ": objects.size=" << ((int) world.objects.size()) */;
    29 
    30 }
    30 }
    31 
    31 
    32 /**
    32 /*
    33  * Player walks on floor.
    33  * Player walks on floor.
    34  */
    34  */
    35 Vector PhysicsObject::walk_one_step (float partial, bool right) {
    35 Vector PhysicsObject::walk_one_step (float partial, bool right) {
    36     // which way we are walking
    36     // which way we are walking
    37     float deltaX = right ? partial : -partial;
    37     float deltaX = right ? partial : -partial;
   132     
   132     
   133     // If the object (practically player) has a pivot point add
   133     // If the object (practically player) has a pivot point add
   134     // a force towards that
   134     // a force towards that
   135     if (pivot != NULL) {
   135     if (pivot != NULL) {
   136         applyForce(getPivotForce());
   136         applyForce(getPivotForce());
       
   137 
   137         if (pivot->type == PLAYER) {
   138         if (pivot->type == PLAYER) {
   138             pivot->applyForce(getPivotForce()*(-1));
   139             pivot->applyForce(-getPivotForce());
   139         }
   140         }
   140     }
   141     }
   141 
   142 
   142     std::pair<Force, TimeMS> force;
   143     std::pair<Force, TimeMS> force;
   143     std::queue<std::pair<Force, TimeMS> > newfq;
   144     std::queue<std::pair<Force, TimeMS> > newfq;
       
   145 
   144     Force total;
   146     Force total;
       
   147 
   145     while (!forceq.empty()) {
   148     while (!forceq.empty()) {
   146         force = forceq.front();
   149         force = forceq.front();
       
   150 
   147         if (force.second > dt) {
   151         if (force.second > dt) {
   148             force.second -= dt;
   152             force.second -= dt;
   149             newfq.push(force);
   153             newfq.push(force);
   150         }
   154         }
       
   155 
   151         total += force.first;
   156         total += force.first;
   152         forceq.pop();
   157         forceq.pop();
   153     }
   158     }
       
   159 
   154     forceq = newfq;
   160     forceq = newfq;
   155 
   161 
   156     // If the player has stopped and there's some ground under some of the 3 some of the 3t
   162     // If the player has stopped and there's some ground under some of the 3 some of the 3t
   157     // set inAir false
   163     // set inAir false
   158     if (this->velocity == Vector(0,0)) {
   164     if (this->velocity == Vector(0,0)) {
   159         this->inAir = !world.terrain.collides(this->position+shape[1]+Vector(0, 1))
   165         this->inAir = !world.terrain.collides(this->position + shape[1] + Vector(0, 1))
   160                       && !world.terrain.collides(this->position+shape[2]+Vector(0, 1))
   166                       && !world.terrain.collides(this->position + shape[2] + Vector(0, 1))
   161                       && !world.terrain.collides(this->position+shape[3]+Vector(0, 1));
   167                       && !world.terrain.collides(this->position + shape[3] + Vector(0, 1));
   162         // If, however, there's a force caused by a bomb, e.g., set it in air.
   168         // If, however, there's a force caused by a bomb, e.g., set it in air.
   163         // Still, we have to be able to separate forces caused by walking attempts
   169         // Still, we have to be able to separate forces caused by walking attempts
   164         // and bombs etc (+0.1 because float comparison can be dangerous)
   170         // and bombs etc (+0.1 because float comparison can be dangerous)
   165         if (total.y < 0.01 || fabs(total.x) > PLAYER_MOVE_FORCE + 0.1)
   171         if (total.y < 0.01 || fabs(total.x) > PLAYER_MOVE_FORCE + 0.1)
   166             this->inAir = true;
   172             this->inAir = true;
   167     }
   173     }
   168 
   174 
   169     if(!possibleLocation(position)) {
   175     if (!possibleLocation(position)) {
   170         //if we are trapped in ground form dirtball or something
   176         //if we are trapped in ground form dirtball or something
   171         //we might want to just return and set velocity to some value
   177         //we might want to just return and set velocity to some value
   172         //return;
   178         //return;
   173     }
   179     }
   174 
   180 
   198     bool collided = false;
   204     bool collided = false;
   199     Vector collisionPoint;
   205     Vector collisionPoint;
   200    
   206    
   201     const Vector diffVec = newPosition - position;
   207     const Vector diffVec = newPosition - position;
   202     const Vector unitVector = diffVec / diffVec.length();
   208     const Vector unitVector = diffVec / diffVec.length();
   203     if(unitVector == Vector(0, 0)) {
   209     if (unitVector == Vector(0, 0)) {
   204         return;
   210         return;
   205     }
   211     }
   206     Vector reached = position;
   212     Vector reached = position;
   207     
   213     
   208     while ((position - reached).sqrLength() < diffVec.sqrLength()) {
   214     while ((position - reached).sqrLength() < diffVec.sqrLength()) {
   237 
   243 
   238     // In case of some float error check the final coordinate
   244     // In case of some float error check the final coordinate
   239     if (!collided) {
   245     if (!collided) {
   240         if (!possibleLocation(newPosition)) {
   246         if (!possibleLocation(newPosition)) {
   241             newPosition = reached;
   247             newPosition = reached;
       
   248 
   242         } else {
   249         } else {
   243             // This means everything was ok, so no need to do anything
   250             // This means everything was ok, so no need to do anything
   244         }
   251         }
   245 
   252 
   246         setPosition (newPosition);
   253         setPosition(newPosition);
   247 
   254 
   248     } else {
   255     } else {
   249         newPosition = reached;
   256         newPosition = reached;
   250         setPosition (newPosition);
   257         setPosition(newPosition);
   251 
   258 
   252         // the following may delete this object, so it must be the last thing called
   259         // the following may delete this object, so it must be the last thing called
   253         onCollision(collisionPoint);
   260         onCollision(collisionPoint);
   254 
   261 
   255         return;
   262         return;
   262  */
   269  */
   263 void PhysicsObject::bounce (Vector normal) {
   270 void PhysicsObject::bounce (Vector normal) {
   264     // normal.sqrLength can't be 0 when got from getNormal()
   271     // normal.sqrLength can't be 0 when got from getNormal()
   265     if (normal.sqrLength() != 0) {
   272     if (normal.sqrLength() != 0) {
   266         Vector nvel = velocity;
   273         Vector nvel = velocity;
       
   274 
   267         // We project the velocity on normal and remove twice that much from velocity
   275         // We project the velocity on normal and remove twice that much from velocity
   268         nvel = nvel - ((2)*((nvel*normal)/(normal*normal))*normal);
   276         nvel = nvel - (2 * ((nvel * normal) / (normal * normal)) * normal);
   269         velocity = nvel;
   277         velocity = nvel;
       
   278 
   270         // We lose some of our speed on collision
   279         // We lose some of our speed on collision
   271         this->velocity *= this->collision_elasticity;
   280         this->velocity *= this->collision_elasticity;
   272     }
   281     }
   273 }
   282 }
   274 
   283 
   276  * Integrates given force over time and stores new position to
   285  * Integrates given force over time and stores new position to
   277  * posAfterTick and new velocity to velAfterTick.
   286  * posAfterTick and new velocity to velAfterTick.
   278  * @param force Force vector.
   287  * @param force Force vector.
   279  * @param dt The time the force is applied (<=PHYSICS_TICK_MS)
   288  * @param dt The time the force is applied (<=PHYSICS_TICK_MS)
   280  */
   289  */
   281 void PhysicsObject::integrate(Force force, TimeMS dt, Vector &posAfterTick, Vector &velAfterTick) {
   290 void PhysicsObject::integrate (Force force, TimeMS dt, Vector &posAfterTick, Vector &velAfterTick) {
   282     posAfterTick = position;
   291     posAfterTick = position;
   283     velAfterTick = velocity;
   292     velAfterTick = velocity;
       
   293 
   284     Derivative tmpd;
   294     Derivative tmpd;
   285     Derivative k1 = evaluate(force, 0, tmpd, posAfterTick, velAfterTick);
   295     Derivative k1 = evaluate(force, 0, tmpd, posAfterTick, velAfterTick);
   286     Derivative k2 = evaluate(force, dt / 2, k1, posAfterTick, velAfterTick);
   296     Derivative k2 = evaluate(force, dt / 2, k1, posAfterTick, velAfterTick);
   287     Derivative k3 = evaluate(force, dt / 2, k2, posAfterTick, velAfterTick);
   297     Derivative k3 = evaluate(force, dt / 2, k2, posAfterTick, velAfterTick);
   288     Derivative k4 = evaluate(force, dt, k3, posAfterTick, velAfterTick);
   298     Derivative k4 = evaluate(force, dt, k3, posAfterTick, velAfterTick);
   289     
   299     
   290 
   300     const Vector dxdt = (k1.dx + (k2.dx + k3.dx) * 2.0f + k4.dx) * 1.0f / 6.0f;
   291     const Vector dxdt = (k1.dx + (k2.dx + k3.dx) * 2.0f + k4.dx) * 1.0f/6.0f;
   301     const Vector dvdt = (k1.dv + (k2.dv + k3.dv) * 2.0f + k4.dv) * 1.0f / 6.0f;
   292     const Vector dvdt = (k1.dv + (k2.dv + k3.dv) * 2.0f + k4.dv) * 1.0f/6.0f;
   302     
   293     
   303     posAfterTick = posAfterTick + (dxdt * dt) / 1000;
   294     //    Engine::log(DEBUG, "PhysicsObject.integrate") << "Changes: "<< dxdt << " " << dvdt << " Time: " <<dt;
   304     velAfterTick = velAfterTick + (dvdt * dt) / 1000;
   295     posAfterTick = posAfterTick + (dxdt * dt)/1000;
   305 }
   296     velAfterTick = velAfterTick + (dvdt * dt)/1000;
   306 
   297     //Engine::log(DEBUG, "PhysicsObject.integrate") << "velAfterTick: " << velAfterTick;
   307 Derivative PhysicsObject::evaluate (Force force, TimeMS dt, const Derivative &d, const Vector &posAfterTick, const Vector &velAfterTick) {
   298 }
   308     Vector curPos = posAfterTick + (d.dx * dt) / 1000;
   299 
   309     Vector curVel = velAfterTick + (d.dv * dt) / 1000;
   300 Derivative PhysicsObject::evaluate(Force force, TimeMS dt, Derivative &d, const Vector &posAfterTick, const Vector &velAfterTick) {
   310 
   301     Vector curPos = posAfterTick + (d.dx*dt)/1000;
   311     return Derivative(curVel, acceleration(force));
   302     Vector curVel = velAfterTick + (d.dv*dt)/1000;
       
   303 
       
   304     Derivative out;
       
   305     out.dx = curVel;
       
   306     out.dv = acceleration(force);
       
   307     //Engine::log(DEBUG, "PhysicsObject.evaluate") << "Out.dx: " << out.dx;
       
   308     return out;
       
   309 }
   312 }
   310 
   313 
   311 Vector PhysicsObject::acceleration(const Force &force) {
   314 Vector PhysicsObject::acceleration(const Force &force) {
   312     return (force/mass);
   315     return (force / mass);
   313 }
   316 }
   314 
   317 
   315 void PhysicsObject::applyForce (Force force, TimeMS dt) {
   318 void PhysicsObject::applyForce (Force force, TimeMS dt) {
   316     // Add applied force to the queue
   319     // Add applied force to the queue
   317     forceq.push(std::make_pair(force, dt));
   320     forceq.push(std::make_pair(force, dt));
   321     this->aim += da;
   324     this->aim += da;
   322 
   325 
   323     if (this->aim > PLAYER_AIM_MAX) this->aim = PLAYER_AIM_MAX;
   326     if (this->aim > PLAYER_AIM_MAX) this->aim = PLAYER_AIM_MAX;
   324     if (this->aim < PLAYER_AIM_MIN) this->aim = PLAYER_AIM_MIN;
   327     if (this->aim < PLAYER_AIM_MIN) this->aim = PLAYER_AIM_MIN;
   325     //Engine::log(DEBUG, "PhysicsObject.changeAim") << "Player aim: " << this->aim;
   328     //Engine::log(DEBUG, "PhysicsObject.changeAim") << "Player aim: " << this->aim;
   326 }
       
   327 
       
   328 ObjectType PhysicsObject::getType (void) const {
       
   329     return this->type;
       
   330 }
       
   331 
       
   332 void PhysicsObject::setFacing (FacingDirection facing) {
       
   333     this->facing = facing;
       
   334 }
   329 }
   335 
   330 
   336 void PhysicsObject::updatePhysics (Vector position, Vector velocity, bool inAir, FacingDirection facing, float aim) {
   331 void PhysicsObject::updatePhysics (Vector position, Vector velocity, bool inAir, FacingDirection facing, float aim) {
   337     setPosition (position);
   332     setPosition (position);
   338     this->velocity = velocity;
   333     this->velocity = velocity;
   339     this->inAir = inAir;
   334     this->inAir = inAir;
   340     this->facing = facing;
   335     this->facing = facing;
   341     this->aim = aim;
   336     this->aim = aim;
   342 }
   337 }
   343 
   338 
   344 Vector PhysicsObject::getPosition (void) const {
       
   345     return position;
       
   346 }
       
   347     
       
   348 Vector PhysicsObject::getPreviousPosition (void) const {
       
   349     return previousPosition;
       
   350 }
       
   351        
       
   352 PixelCoordinate PhysicsObject::getCoordinate (void) const {
   339 PixelCoordinate PhysicsObject::getCoordinate (void) const {
   353     return world.terrain.getPixelCoordinate(position);
   340     return world.terrain.getPixelCoordinate(position);
   354 }
   341 }
   355 
   342 
   356 Vector PhysicsObject::getVelocity (void) const {
       
   357     return velocity;
       
   358 }
       
   359 
       
   360 FacingDirection PhysicsObject::getFacing (void) const {
       
   361     return facing;
       
   362 }
       
   363 
       
   364 float PhysicsObject::getAim (void) const {
       
   365     return aim;
       
   366 }
       
   367 
       
   368 Vector PhysicsObject::getDirection (void) const {
   343 Vector PhysicsObject::getDirection (void) const {
   369     return facing == FACING_RIGHT ? Vector(cos(aim), -sin(aim)) : Vector(-cos(aim), -sin(aim));
   344     return facing == FACING_RIGHT ? Vector(cos(aim), -sin(aim)) : Vector(-cos(aim), -sin(aim));
   370 }
       
   371 
       
   372 const std::vector<Vector>& PhysicsObject::getShape () const {
       
   373     return shape;
       
   374 }
       
   375 
       
   376 void PhysicsObject::setShape (std::vector<Vector> shape) {
       
   377     this->shape = shape;
       
   378 }
       
   379 
       
   380 PhysicsObject *PhysicsObject::getPivot (void) {
       
   381     return this->pivot;
       
   382 }
       
   383 
       
   384 void PhysicsObject::setPivot (PhysicsObject *pivot) {
       
   385     this->pivot = pivot;
       
   386 }
   345 }
   387 
   346 
   388 void PhysicsObject::tick (TimeMS tick_length) {
   347 void PhysicsObject::tick (TimeMS tick_length) {
   389     this->updatePosition(tick_length);
   348     this->updatePosition(tick_length);
   390 }
   349 }
   410     // mark as disabled and for deletion
   369     // mark as disabled and for deletion
   411     alive = false;
   370     alive = false;
   412     shouldDelete = true;
   371     shouldDelete = true;
   413 }
   372 }
   414     
   373     
   415 bool PhysicsObject::isAlive (void) {
       
   416     return alive;
       
   417 }
       
   418     
       
   419 bool PhysicsObject::removeIfDestroyed (void) {
   374 bool PhysicsObject::removeIfDestroyed (void) {
   420     if (!alive) {
   375     if (!alive) {
   421         if (shouldDelete)
   376         if (shouldDelete)
   422             delete this;
   377             delete this;
   423 
   378 
   431 Vector PhysicsObject::getPivotForce (void) { 
   386 Vector PhysicsObject::getPivotForce (void) { 
   432     return Vector(0,0); 
   387     return Vector(0,0); 
   433 }
   388 }
   434 
   389 
   435 bool PhysicsObject::collides (const PhysicsObject &obj) {
   390 bool PhysicsObject::collides (const PhysicsObject &obj) {
   436     const std::vector<Vector> oShape = obj.getShape();
   391     const std::vector<Vector> oShape = obj.shape;
   437     Vector p1, p2, p3;
   392     Vector p1, p2, p3;
   438     int8_t sign, nsign;
   393     int8_t sign, nsign;
   439     for (std::vector<Vector>::const_iterator i = oShape.begin(); i != oShape.end(); i++) { // For every point in other shape
   394     for (std::vector<Vector>::const_iterator i = oShape.begin(); i != oShape.end(); i++) { // For every point in other shape
   440         p3 = *i + obj.getPosition();
   395         p3 = *i + obj.getPosition();
   441         sign = 0;
   396         sign = 0;
   468 void PhysicsObject::setPosition (Vector pos) {
   423 void PhysicsObject::setPosition (Vector pos) {
   469     this->previousPosition = this->position;
   424     this->previousPosition = this->position;
   470     this->position = pos;
   425     this->position = pos;
   471 }
   426 }
   472 
   427 
   473 void PhysicsObject::setVelocity (Vector velocity) {
   428 void PhysicsObject::reset (void) {
   474     this->velocity = velocity;
   429     // zero velocity
   475 }
   430     this->velocity = Vector(0, 0);
       
   431 
       
   432     // disable
       
   433     disable();
       
   434 }
       
   435     
       
   436 void PhysicsObject::resume (Vector position) {
       
   437     // update position
       
   438     setPosition(position);
       
   439 
       
   440     // enable again
       
   441     enable();
       
   442 }