void PhysicalObj::SetXY(const Point2d &position) { CheckOverlapping(); // Don't use METER_PER_PIXEL here: bad truncation occurs if (IsOutsideWorldXY(Point2i(position.x, position.y)) && can_be_ghost) { SetPhysXY(position / PIXEL_PER_METER); Ghost(); SignalOutOfMap(); } else { SetPhysXY(position / PIXEL_PER_METER); if (FootsInVacuum()) StartMoving(); } }
PhysicalObj* PhysicalObj::CollidedObjectXY(const Point2i & position) const { if (IsOutsideWorldXY(position)) return NULL; Rectanglei rect(position.x + m_test_left, position.y + m_test_top, m_width - m_test_right - m_test_left, m_height - m_test_bottom - m_test_top); if (m_collides_with_characters) { FOR_ALL_LIVING_CHARACTERS(team,character) { // We check both objet if one overlapses the other if (&(*character) != this && !IsOverlapping(&(*character)) && !character->IsOverlapping(this) && character->Intersect(rect)) { return (PhysicalObj*) &(*character); } else if (IsOverlapping(&(*character)) != character->IsOverlapping(this)) { //printf("Check 0\n"); } } } if (m_collides_with_objects) { if (m_is_character) { FOR_EACH_OBJECT(it) { PhysicalObj * object=*it; // We check both objet if one overlapses the other if (object->m_collides_with_characters) { if (object != this && !IsOverlapping(object) && !object->IsOverlapping(this) && object->m_collides_with_objects && object->Intersect(rect)) { return object; } else if (IsOverlapping(object) != object->IsOverlapping(this)) { //printf("Check1\n"); } } } } else { FOR_EACH_OBJECT(it) { PhysicalObj * object=*it; // We check both objet if one overlapses the other if (object != this && !IsOverlapping(object) && !object->IsOverlapping(this) && object->m_collides_with_objects && object->Intersect(rect)) { return object; } else if (IsOverlapping(object) != object->IsOverlapping(this)) { //printf("Check2\n"); } } } }
bool PhysicalObj::IsInVacuumXY(const Point2i &position, bool check_object) const { if (IsOutsideWorldXY(position)) return GetWorld().IsOpen(); if (check_object && !m_go_through_objects && CollidedObjectXY(position)) return false; int width = m_width - m_test_right - m_test_left; int height = m_height -m_test_bottom - m_test_top; width = !width ? 1 : width; height = !height ? 1 : height; Rectanglei rect(position.x + m_test_left, position.y + m_test_top, width, height); return GetWorld().RectIsInVacuum(rect); }
void BulletParticle::Refresh() { if(IsOutsideWorldXY(GetPosition())) { m_left_time_to_live = 0; return; } int current_time = Time::GetInstance()->Read(); UpdatePosition(); image->Update(); if(start_to_fade > 0) { m_left_time_to_live = start_to_fade + BULLET_PARTICLE_FADE_TIME - current_time; m_left_time_to_live = (m_left_time_to_live > 0 ? m_left_time_to_live : 0); image->SetAlpha(ONE - ((Double)(current_time - start_to_fade)) / BULLET_PARTICLE_FADE_TIME); } else { // FIXME this is still a ugly hack image->SetRotation_rad((Time::GetInstance()->Read()/4) % 3 /* 3 is arbitrary */ ); } }
// Move to a point with collision test collision_t PhysicalObj::NotifyMove(Point2d oldPos, Point2d newPos) { if (IsGhost()) return NO_COLLISION; Point2d contactPos; Double contactAngle; Point2d pos, offset; PhysicalObj* collided_obj = NULL; collision_t collision = NO_COLLISION; // Convert meters to pixels. oldPos *= PIXEL_PER_METER; newPos *= PIXEL_PER_METER; // Compute distance between old and new position. Double lg = oldPos.SquareDistance(newPos); MSG_DEBUG("physic.move", "%s moves (%s, %s) -> (%s, %s), square distance: %s", GetName().c_str(), Double2str(oldPos.x).c_str(), Double2str(oldPos.y).c_str(), Double2str(newPos.x).c_str(), Double2str(newPos.y).c_str(), Double2str(lg).c_str()); if (!lg.IsNotZero()) return NO_COLLISION; // Compute increments to move the object step by step from the old // to the new position. lg = sqrt(lg); offset = (newPos - oldPos) / lg; // First iteration position. pos = oldPos + offset; if (!m_collides_with_ground || IsInWater()) { MSG_DEBUG("physic.move", "%s moves (%s, %s) -> (%s, %s), collides ground:%d, water:%d", GetName().c_str(), Double2str(oldPos.x).c_str(), Double2str(oldPos.y).c_str(), Double2str(newPos.x).c_str(), Double2str(newPos.y).c_str(), m_collides_with_ground, IsInWater()); SetXY(newPos); return NO_COLLISION; } do { Point2i tmpPos(uround(pos.x), uround(pos.y)); // Check if we exit the GetWorld(). If so, we stop moving and return. if (IsOutsideWorldXY(tmpPos)) { if (!GetWorld().IsOpen()) { tmpPos.x = InRange_Long(tmpPos.x, 0, GetWorld().GetWidth() - GetWidth() - 1); tmpPos.y = InRange_Long(tmpPos.y, 0, GetWorld().GetHeight() - GetHeight() - 1); MSG_DEBUG("physic.state", "%s - DeplaceTestCollision touche un bord : %d, %d", GetName().c_str(), tmpPos.x, tmpPos.y); collision = COLLISION_ON_GROUND; break; } SetXY(pos); MSG_DEBUG("physic.move", "%s moves (%f, %f) -> (%f, %f) : OUTSIDE WORLD", GetName().c_str(), oldPos.x.tofloat(), oldPos.y.tofloat(), newPos.x.tofloat(), newPos.y.tofloat()); return NO_COLLISION; } // Test if we collide... collided_obj = CollidedObjectXY(tmpPos); if (collided_obj) { if (!m_go_through_objects || m_last_collided_object != collided_obj) { MSG_DEBUG("physic.state", "%s collide on %s", GetName().c_str(), collided_obj->GetName().c_str()); if (m_go_through_objects) { SignalObjectCollision(GetSpeed(), collided_obj, collided_obj->GetSpeed()); collision = NO_COLLISION; } else { collision = COLLISION_ON_OBJECT; } m_last_collided_object = collided_obj; } else { collided_obj = NULL; collision = NO_COLLISION; } } else if (!IsInVacuumXY(tmpPos, false)) { collision = COLLISION_ON_GROUND; m_last_collided_object = NULL; } if (collision != NO_COLLISION) { // Nothing more to do! MSG_DEBUG("physic.state", "%s - Collision at %d,%d : on %s", GetName().c_str(), tmpPos.x, tmpPos.y, collision == COLLISION_ON_GROUND ? "ground" : "an object"); // Set the object position to the current position. SetXY(Point2d(pos.x - offset.x, pos.y - offset.y)); break; } // Next motion step pos += offset; lg -= ONE; } while (ZERO < lg); Point2d speed_before_collision = GetSpeed(); Point2d speed_collided_obj; if (collided_obj) { speed_collided_obj = collided_obj->GetSpeed(); } ContactPointAngleOnGround(pos, contactPos, contactAngle); Collide(collision, collided_obj, pos); // =================================== // it's time to signal object(s) about collision! // WARNING: the following calls can send Action(s) over the network (cf bug #11232) // Be sure to keep it isolated here // =================================== ActiveTeam().AccessWeapon().NotifyMove(!!collision); switch (collision) { case NO_COLLISION: // Nothing more to do! break; case COLLISION_ON_GROUND: SignalGroundCollision(speed_before_collision, contactAngle); break; case COLLISION_ON_OBJECT: SignalObjectCollision(speed_before_collision, collided_obj, speed_collided_obj); collided_obj->SignalObjectCollision(speed_collided_obj, this, speed_before_collision); break; } // =================================== return collision; }