Exemplo n.º 1
0
bool Board::find(cv::Point const& target, Ball::PtrList & myballs) const
{
  for(auto bb = balls.rbegin(); bb!=balls.rend();++bb)
  {
    for(auto b : *bb)
    {
      if(b->disable == true) continue ;
      if(circlesColliding(b->point.x, b->point.y, radius*0.7, target.x, target.y, radius*0.8))
      {
        myballs.push_back(b);
      }
    }
  }
  return myballs.size() > 0;
}
Exemplo n.º 2
0
// TODO: split this beast up into sub functions!
// returns true if there is a collision occuring between the two entities.
bool SCollision::collisionOccurring(EntityManager * entM,
									PPosition* pos1,
									PBoundingBox* ent1,
									PPosition* pos2,
									PBoundingBox* ent2)
{
	VECTOR2 collisionVector;
	collisionVector.y = 0.0f;
	collisionVector.x = 0.0f;
	int count = 0;

	if(ent1->collisionType == PBoundingBoxNS::LINE && ent2->collisionType == PBoundingBoxNS::CIRCLE)
	{
		PGravity * gobj = entM->getProperty<PGravity>(ent2->entity_id);
		PMobile * mob = entM->getProperty<PMobile>(ent2->entity_id);

		// store the entity's current position in temporary variables. we will be checking collision with the entity's
		// upcoming position that has yet to be computed for this frame (the SMovement system computes new entity positions
		// after the SCollision system resolves collisions).
		float tempX = pos2->x, tempY = pos2->y;

		if ( mob != nullptr )
		{
			// determine the entity's upcoming position for this frame, and resolve collision
			// with this new position
			pos2->x = pos2->x + mob->direction.x*mob->velocity.x*_Game->getDeltaTime();
			pos2->y = pos2->y + mob->direction.y*mob->velocity.y*_Game->getDeltaTime();

			if( gobj != nullptr && !gobj->grounded && lineCircleColliding(pos1, ent1, pos2, ent2, collisionVector))
			{
				// reset y position
				pos2->y = tempY;

				/* 
				   if collisionVector.y != 0, then this line is representative of the "ground" or "floor".
				   collisionVector.y == 0 only if the line's rise is greater than its run, in which case
				   we treat the line as an impassable "wall" and restrict the colliding entity's movement in the x-direction
				   with which it is colliding with the wall.	
				   additionally, we only resolve collisions with the ground when falling (velocity.y >= 0)
				*/
				if ( collisionVector.y < 0.0f && mob->velocity.y >= 0 )
				{
					/* 
					   Determine how much of the radius is factored into shifting the entity upwards away from the line
					   that is being collided with. 
					   (In other words, find the y position of the circle tangent to the line being collided with)
					   
					   For one extreme case, when the slope is zero, the entirety of the
					   entity's radius is subtracted from the y point of collision on the line (a line with slope zero is tangent to
					   the bottom (or top) of the circle. So we can simply do y_collision_point - center of entity - radius to
					   determine the dy with which to move our entity as to position it so that its circle hitbox is tangent to the line.) 
					  
					   On the other hand, if the slope were infinite instead of zero (a vertical line), then none of the entity's 
					   radius is subtracted from the y point of collision, because in this case the line is tangent to the 
					   left or right of the circle (the horizontal radius is perpendicular to the line), and so we do not adjust
					   the entity's y position at all (as adjusting the y position does nothing to separate these colliding entities
					   if the line intersecting the circle is vertical).

					   For lines with intermediate slopes, we can multiply the radius by the cosine of the triangle whose
					   hypotenuse is the line being collided with to determine how far we can shift the entity so that its
					   comprised circle is tangent to the line.
					*/
					
					float slope = ent1->line.B.y / ent1->line.B.x;
					float magnitude = sqrt( ent1->line.B.x*ent1->line.B.x + ent1->line.B.y*ent1->line.B.y);

					// cosine of the triangle whose hypotenuse is the line 
					float cosine = ent1->line.B.x/magnitude;
					// sine of the triangle whose hypotenuse is the line
					float sine = -ent1->line.B.y/magnitude;

					// determine the y point of collision on the line
					float y = slope*( pos2->getCenterX() + ent2->radius*sine - pos1->x ) + pos1->y;

					// subtract the y point of collision from the entity's center, minus the y component of the vector 
					// perpendicular to the line ( whose magnitude is the circle's radius ).
					// to the line
					float dy = ( y - pos2->getCenterY() ) - ent2->radius*cosine;

					// reset the entity's x position ( we reset it here because we needed to use the upcoming x position
					// in the above computation of y )
					pos2->x = tempX;
					SMovement::moveEntity(pos2, 0, dy);
				
					// set the entity's gravity property's grounded field to true so that the SGravity system
					// knows not to "pull down" on the entity. 
					gobj->grounded = true;

					// set this entity's downward velocity to zero.
					// set this entity's downward velocity to zero.
					mob->velocity.y = 0.0f;
				}
				else if ( collisionVector.x != 0.0f )	// if colliding with a vertical line
				{
					// reset entity's x position after checking collision of future position
					pos2->x = tempX;

					// if entity is to the right of the vertical line, shift factor is the colliding entity's radius. 
					// otherwise, the shift factor is the negative of this radius.
					float shift = collisionVector.x == -1.0f ? ent2->radius*-1 - 2.0f : ent2->radius + 2.0f;
					float dx = pos1->x - pos2->getCenterX() + shift;

					SMovement::moveEntity(pos2, dx, 0);
					mob->velocity.x = 0;
				}

				return true;
			}
			
			pos2->x = tempX;
			pos2->y = tempY;
		}
		
		return false;
	}
	else if(ent1->collisionType == PBoundingBoxNS::CIRCLE && ent2->collisionType == PBoundingBoxNS::LINE)
	{
		PGravity * gobj = entM->getProperty<PGravity>(ent1->entity_id);
		PMobile * mob = entM->getProperty<PMobile>(ent1->entity_id);

		float tempX = pos1->x, tempY = pos1->y;

		if ( mob != nullptr )
		{
			// determine the entity's upcoming position for this frame, and resolve collision
			// with this new position
			pos1->x = pos1->x + mob->direction.x*mob->velocity.x*_Game->getDeltaTime();
			pos1->y = pos1->y + mob->direction.y*mob->velocity.y*_Game->getDeltaTime();

			if( gobj != nullptr && !gobj->grounded && lineCircleColliding(pos2, ent2, pos1, ent1, collisionVector))
			{
				// reset y position
				pos1->y = tempY;

				if ( collisionVector.y < 0.0f && mob->velocity.y >= 0 )
				{
					
					float slope = ent2->line.B.y / ent2->line.B.x;
					float magnitude = sqrt( ent2->line.B.x*ent2->line.B.x + ent2->line.B.y*ent2->line.B.y);

					// cosine of the triangle whose hypotenuse is the line 
					float cosine = ent2->line.B.x/magnitude;
					// sine of the triangle whose hypotenuse is the line
					float sine = -ent2->line.B.y/magnitude;

					// determine the y point of collision on the line
					float y = slope*( pos1->getCenterX() + ent1->radius*sine - pos2->x ) + pos2->y;

					float dy = y - pos1->getCenterY() - ent1->radius*cosine;

					pos1->x = tempX;
					SMovement::moveEntity(pos1, 0, dy);
				
					// set the entity's gravity property's grounded field to true so that the SGravity system
					// knows not to "pull down" on the entity. 
					gobj->grounded = true;

					// set this entity's downward velocity to zero.
					mob->velocity.y = 0.0f;
				}
				else if ( collisionVector.x != 0.0f )	// if colliding with a vertical line
				{
					pos1->x = tempX;

					float shift = collisionVector.x == -1.0f ? ent1->radius*-1 - 2.0f : ent1->radius + 2.0f;
					float dx = pos2->x - pos1->getCenterX() + shift;

					SMovement::moveEntity(pos1, dx, 0);
					mob->velocity.x = 0;
				}

				return true;
			}
			
			pos1->x = tempX;
			pos1->y = tempY;
		}
		
		return false;
	}
	else if(ent1->collisionType == PBoundingBoxNS::CIRCLE && ent2->collisionType == PBoundingBoxNS::BOX)
	{
		float x1 = 0.0f, x2= 0.0f, y1= 0.0f, y2= 0.0f;
		while((ent1->deflect || ent2->deflect) && count < 10 && boxCircleColliding(pos2, ent2, pos1, ent1, collisionVector))
		{
			if(ent2->deflect)
			{
				y1 += collisionVector.y;
				x1 += collisionVector.x;
			}
			if(ent1->deflect)
			{
				y2 -= collisionVector.y;
				x2 -= collisionVector.x;
			}
			count++;
		}

		SMovement::moveEntity(pos1, x1, y1);
		SMovement::moveEntity(pos2, x2, y2);

		if(count == 0)
		{
			return boxCircleColliding(pos2, ent2, pos1, ent1, collisionVector);
		}
		
		return true;
	}
	else if(ent1->collisionType == PBoundingBoxNS::BOX && ent2->collisionType == PBoundingBoxNS::CIRCLE)
	{
		float x1 = 0.0f, x2= 0.0f, y1= 0.0f, y2= 0.0f;
		while((ent1->deflect || ent2->deflect) && count < 10 && boxCircleColliding(pos1, ent1, pos2, ent2, collisionVector))
		{
			if(ent2->deflect)
			{
				y1 += collisionVector.y;
				x1 += collisionVector.x;
			}
			if(ent1->deflect)
			{
				y2 -= collisionVector.y;
				x2 -= collisionVector.x;
			}
			count++;
		}

		SMovement::moveEntity(pos1, x1, y1);
		SMovement::moveEntity(pos2, x2, y2);

		if(count == 0)
		{
			return boxCircleColliding(pos1, ent1, pos2, ent2, collisionVector);
		}
		
		return true;
	}
	else if(ent1->collisionType == PBoundingBoxNS::CIRCLE && ent2->collisionType == PBoundingBoxNS::CIRCLE)
	{
		float x1 = 0.0f, x2= 0.0f, y1= 0.0f, y2= 0.0f;
		while((ent1->deflect || ent2->deflect) && count < 10 && circlesColliding(pos1, ent1, pos2, ent2, collisionVector))
		{
			Graphics::Vector2Normalize(&collisionVector);
			if(ent2->deflect)
			{
				y1 += collisionVector.y;
				x1 += collisionVector.x;
			}
			if(ent1->deflect)
			{
				y2 -= collisionVector.y;
				x2 -= collisionVector.x;
			}

			count++;
		}

		SMovement::moveEntity(pos1, x1, y1);
		SMovement::moveEntity(pos2, x2, y2);

		if( count == 0 )
		{
			return circlesColliding(pos1, ent1, pos2, ent2, collisionVector);
		}
		
		return false;
	}
	else if(ent1->collisionType == PBoundingBoxNS::BOX)
	{
		while(count < 10 && (ent1->deflect || ent2->deflect) && boxesColliding(pos1, ent1, pos2, ent2, collisionVector))
		{
			if(ent2->deflect)
				SMovement::moveEntity(pos1, collisionVector.x, collisionVector.y);
			if(ent1->deflect)
				SMovement::moveEntity(pos2, -collisionVector.x, -collisionVector.y);

			count++;
		}

		if(count == 0)
			return false;

		return true;
	}

	return false;
}