Ejemplo n.º 1
0
BSPTree2D* BSPTree2D::create( const PointList& inPointList, std::string& outState, double inTol /*= 1.0e-13*/, size_t inMaxNodeCount /*= 7000*/, size_t numAxialDivsn /*= 0*/ )
{
	Segment::List seglist;
	PointList::const_iterator itrP1 = inPointList.begin();
	PointList::const_iterator itrP2 = inPointList.begin();
	for(itrP2++;itrP2 != inPointList.end();itrP1++,itrP2++)
		seglist.push_back(Segment(*itrP1,*itrP2));
	outState.clear();
	Node* baseNode = new Node(seglist,outState,inTol,inMaxNodeCount,numAxialDivsn);
	if(!outState.empty())
	{
		delete baseNode;
		return nullptr;
	}
	return new BSPTree2D(baseNode,inTol);
}
Ejemplo n.º 2
0
BSPTree2D* BSPTree2D::create( const PointArray& inPointArray, std::string& outState, double inTol /*= 1.0e-13*/, size_t inMaxNodeCount /*= 7000*/, size_t numAxialDivsn /*= 0*/ )
{
	Segment::List seglist;
	for(auto itPoint = inPointArray.begin(); itPoint != --inPointArray.end();)
	{
		auto & p1 = *itPoint, & p2 = *(++itPoint);
		seglist.push_back(Segment(p1, p2));
	}
	outState.clear();
	Node* baseNode = new Node(seglist,outState,inTol,inMaxNodeCount,numAxialDivsn);
	if(!outState.empty())
	{
		delete baseNode;
		return nullptr;
	}
	return new BSPTree2D(baseNode,inTol);
}
Ejemplo n.º 3
0
void Object::doCollision(Background &bg)
{
	WallSet set;
	const TileMap &tilemap = bg.getTileMap();

	/* get tile bounds of circle */
	int l = (int)floor((pos.x-radius)/8), r = (int)ceil((pos.x+radius)/8);
	int t = (int)floor((pos.y-radius)/8), b = (int)ceil((pos.y+radius)/8);

	/* add all walls declared for the tiles */
	for (int j= t; j < b; j++)
		for (int i= l; i < r; i++)
		{
			const TileMapEntry *tme = tilemap.index(i,j);
			set.addFromTile(tme);
		}

	/* we want to ignore certain walls (tops of ladders when climbing through 
		them, and one way walls). This loop removes walls from the ignore list
		if the object doesn't intersect with it */
	{
		Wall::CPListIterator i;
		for (i = ignore.begin(); i != ignore.end();)
		{
			const Segment &s = (**i).wall.segment;

			if (!s.intersect(Circle(pos, radius)))
				ignore.erase(i++);
			else
				++i;
		}
	}

	/* all the collision gets messed up when the sometimes here/sometimes
		not walls enter the equation */
	bool irregularWalls = false;
	{
		WallSet::Iterator i;
		for (i = set.begin(); i != set.end(); ++i)
		{
			const Edge::EdgeType &type = (**i).wall.type;
			if (type == Edge::LADDER_TOP || type == Edge::ONE_WAY)
			{
				irregularWalls = true;
				break;
			}
		}
	}

	/* check all walls found above for collision */

	WallSet::Iterator i;
	Segment::List collide;

	for (i = set.begin(); i != set.end(); ++i)
	{
		const Wall &w = (**i);
		const Segment &s = w.wall.segment;

		preProcessWall(**i);

		/* don't process it if it's in the ignore list... */
		if (std::find(ignore.begin(), ignore.end(), &w) != ignore.end())
			continue;
		
		/* we wait to do segment-circle collision if we're doing complicated
			collision */
		if (!irregularWalls)
		{
			/* ...or if it doesn't even intersect the circle */
			if (!s.intersect(Circle(pos, radius)))
				continue;
		}

		if (processWall(**i))
		{
			if (irregularWalls)
				collide.push_back((**i).wall.segment);
			else
				collideWall((**i).wall.segment);
		}
	}

	/* the problem with using normal collision:
		if we have some walls that are here today/gone tomorrow the collision
		will be irregular because of the way segment-circle collision works.
		
		when the circle collides with two walls with the same normal near their
		intersection point, one of the segments will (probably) provide a shunt 
		vector that is not the normal, whereas the other (probably) will. This
		will push the object in the direction of the vector, even though it
		shouldn't.

		how to fix it (basic idea):
		* combine collinear segment that intersect at a point like in 
			Walls::addWall
		* sometimes walls will exist on the other side of this newly created
			wall. If the object is on the normal side, remove this "T-Bone" wall.
	*/
	if (irregularWalls)
	{
		/* combine collinear segments that intersect at a point,
			like in Walls::addWall */
		Segment::ListIterator k, l;

		for (k = collide.begin(); k != collide.end();)
		{
			bool removed = false;

			const Segment &s = *k;
			l = k;
			for (++l; l != collide.end(); ++l)
			{
				const Segment &t = *l;
				Point p0, p1;
				Segment::IntersectType it = s.intersect(t,p0,p1);

				if (it != Segment::COLLINEAR_POINT) continue;
				if (s.normal != t.normal) continue;

				if (p0 == t.p0)
					collide.push_back(Segment(s.p0, t.p1));
				else
					collide.push_back(Segment(t.p0, s.p1));

				collide.erase(k++);
				if (k == l)
					collide.erase(k++);
				else
					collide.erase(l);

				removed = true;
				break;
			}

			if (!removed) ++k;
		}

		/* look for edges that T-bone another segment */
		for (k = collide.begin(); k != collide.end();)
		{
			bool removed = false;
			const Segment &s = *k;
			l = k;
			for (++l; l != collide.end(); ++l)
			{
				const Segment &t = *l;
				Point p0, p1;
				Segment::IntersectType it = s.intersect(t,p0,p1);

				if (it != Segment::POINT) continue;
				/* we know that the combined segments are at the end of the
					collide list, therefore if two segments are T-boned, the
					top of the "T" must be t and the base of the "T" must be
					s.

					Therefore, if the intersection point is t, we know it can't
					be a T-bone.
				*/
				if (p0 == t.p0 || p0 == t.p1) continue;
				
				/* find which point connects the top of the "T" to the base. */
				if (p0 == s.p0)
				{
					/* we'll erase the base if the top normal points away from
						the base and if the object is on the top normal side */
					if (!t.faces(s.p1) && t.faces(pos))
					{
						collide.erase(k++);
						removed = true;
						break;
					}
				}
				else if (p0 == s.p1)
				{
					/* we'll erase the base if the top normal points away from
						the base and if the object is on the top normal side */
					if (!t.faces(s.p0) && t.faces(pos))
					{
						collide.erase(k++);
						removed = true;
						break;
					}
				}
			}
			if (!removed) ++k;
		}

		/* shunt object around to avoid collision */
		for (k = collide.begin(); k != collide.end(); ++k)
		{
			const Segment &s = *k;
			/* this check is necessary, if we check walls without moving the
				object, we get false positives */
			if (s.intersect(Circle(pos, radius)))
				collideWall(*k);
		}
	}
}