Skip to content

Commit

Permalink
Ghost Collision Fix (doctest#607)
Browse files Browse the repository at this point in the history
- Addresses doctest#553, doctest#341, and doctest#286
- Edge shapes are now either one-sided or two-sided
- Only one-sided edges support smooth collision and must be connected to other edges on both sides
- Edge and chain shapes APIs updated to reflect changes
  • Loading branch information
erincatto authored Jul 11, 2020
1 parent 1025f9a commit 8118426
Show file tree
Hide file tree
Showing 54 changed files with 622 additions and 760 deletions.
25 changes: 8 additions & 17 deletions include/box2d/b2_chain_shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@
class b2EdgeShape;

/// A chain shape is a free form sequence of line segments.
/// The chain has two-sided collision, so you can use inside and outside collision.
/// Therefore, you may use any winding order.
/// Since there may be many vertices, they are allocated using b2Alloc.
/// The chain has one-sided collision, with the surface normal pointing to the right of the edge.
/// This provides a counter-clockwise winding like the polygon shape.
/// Connectivity information is used to create smooth collisions.
/// WARNING: The chain will not collide properly if there are self-intersections.
/// @warning the chain will not collide properly if there are self-intersections.
class b2ChainShape : public b2Shape
{
public:
Expand All @@ -49,18 +48,13 @@ class b2ChainShape : public b2Shape
/// @param count the vertex count
void CreateLoop(const b2Vec2* vertices, int32 count);

/// Create a chain with isolated end vertices.
/// Create a chain with ghost vertices to connect multiple chains together.
/// @param vertices an array of vertices, these are copied
/// @param count the vertex count
void CreateChain(const b2Vec2* vertices, int32 count);

/// Establish connectivity to a vertex that precedes the first vertex.
/// Don't call this for loops.
void SetPrevVertex(const b2Vec2& prevVertex);

/// Establish connectivity to a vertex that follows the last vertex.
/// Don't call this for loops.
void SetNextVertex(const b2Vec2& nextVertex);
/// @param prevVertex previous vertex from chain that connects to the start
/// @param nextVertex next vertex from chain that connects to the end
void CreateChain(const b2Vec2* vertices, int32 count,
const b2Vec2& prevVertex, const b2Vec2& nextVertex);

/// Implement b2Shape. Vertices are cloned using b2Alloc.
b2Shape* Clone(b2BlockAllocator* allocator) const override;
Expand Down Expand Up @@ -93,7 +87,6 @@ class b2ChainShape : public b2Shape
int32 m_count;

b2Vec2 m_prevVertex, m_nextVertex;
bool m_hasPrevVertex, m_hasNextVertex;
};

inline b2ChainShape::b2ChainShape()
Expand All @@ -102,8 +95,6 @@ inline b2ChainShape::b2ChainShape()
m_radius = b2_polygonRadius;
m_vertices = nullptr;
m_count = 0;
m_hasPrevVertex = false;
m_hasNextVertex = false;
}

#endif
21 changes: 14 additions & 7 deletions include/box2d/b2_edge_shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,21 @@
#include "b2_shape.h"

/// A line segment (edge) shape. These can be connected in chains or loops
/// to other edge shapes. The connectivity information is used to ensure
/// correct contact normals.
/// to other edge shapes. Edges created independently are two-sided and do
/// no provide smooth movement accross junctions.
class b2EdgeShape : public b2Shape
{
public:
b2EdgeShape();

/// Set this as an isolated edge.
void Set(const b2Vec2& v1, const b2Vec2& v2);
/// Set this as a part of a sequence. Vertex v0 precedes the edge and vertex v3
/// follows. These extra vertices are used to provide smooth movement
/// across junctions. This also makes the collision one-sided. The edge
/// normal points to the right looking from v1 to v2.
void SetOneSided(const b2Vec2& v0, const b2Vec2& v1,const b2Vec2& v2, const b2Vec2& v3);

/// Set this as an isolated edge. Collision is two-sided.
void SetTwoSided(const b2Vec2& v1, const b2Vec2& v2);

/// Implement b2Shape.
b2Shape* Clone(b2BlockAllocator* allocator) const override;
Expand All @@ -60,7 +66,9 @@ class b2EdgeShape : public b2Shape

/// Optional adjacent vertices. These are used for smooth collision.
b2Vec2 m_vertex0, m_vertex3;
bool m_hasVertex0, m_hasVertex3;

/// Uses m_vertex0 and m_vertex3 to create smooth collision.
bool m_oneSided;
};

inline b2EdgeShape::b2EdgeShape()
Expand All @@ -71,8 +79,7 @@ inline b2EdgeShape::b2EdgeShape()
m_vertex0.y = 0.0f;
m_vertex3.x = 0.0f;
m_vertex3.y = 0.0f;
m_hasVertex0 = false;
m_hasVertex3 = false;
m_oneSided = false;
}

#endif
30 changes: 3 additions & 27 deletions src/collision/b2_chain_shape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,9 @@ void b2ChainShape::CreateLoop(const b2Vec2* vertices, int32 count)
m_vertices[count] = m_vertices[0];
m_prevVertex = m_vertices[m_count - 2];
m_nextVertex = m_vertices[1];
m_hasPrevVertex = true;
m_hasNextVertex = true;
}

void b2ChainShape::CreateChain(const b2Vec2* vertices, int32 count)
void b2ChainShape::CreateChain(const b2Vec2* vertices, int32 count, const b2Vec2& prevVertex, const b2Vec2& nextVertex)
{
b2Assert(m_vertices == nullptr && m_count == 0);
b2Assert(count >= 2);
Expand All @@ -81,34 +79,15 @@ void b2ChainShape::CreateChain(const b2Vec2* vertices, int32 count)
m_vertices = (b2Vec2*)b2Alloc(count * sizeof(b2Vec2));
memcpy(m_vertices, vertices, m_count * sizeof(b2Vec2));

m_hasPrevVertex = false;
m_hasNextVertex = false;

m_prevVertex.SetZero();
m_nextVertex.SetZero();
}

void b2ChainShape::SetPrevVertex(const b2Vec2& prevVertex)
{
m_prevVertex = prevVertex;
m_hasPrevVertex = true;
}

void b2ChainShape::SetNextVertex(const b2Vec2& nextVertex)
{
m_nextVertex = nextVertex;
m_hasNextVertex = true;
}

b2Shape* b2ChainShape::Clone(b2BlockAllocator* allocator) const
{
void* mem = allocator->Allocate(sizeof(b2ChainShape));
b2ChainShape* clone = new (mem) b2ChainShape;
clone->CreateChain(m_vertices, m_count);
clone->m_prevVertex = m_prevVertex;
clone->m_nextVertex = m_nextVertex;
clone->m_hasPrevVertex = m_hasPrevVertex;
clone->m_hasNextVertex = m_hasNextVertex;
clone->CreateChain(m_vertices, m_count, m_prevVertex, m_nextVertex);
return clone;
}

Expand All @@ -126,27 +105,24 @@ void b2ChainShape::GetChildEdge(b2EdgeShape* edge, int32 index) const

edge->m_vertex1 = m_vertices[index + 0];
edge->m_vertex2 = m_vertices[index + 1];
edge->m_oneSided = true;

if (index > 0)
{
edge->m_vertex0 = m_vertices[index - 1];
edge->m_hasVertex0 = true;
}
else
{
edge->m_vertex0 = m_prevVertex;
edge->m_hasVertex0 = m_hasPrevVertex;
}

if (index < m_count - 2)
{
edge->m_vertex3 = m_vertices[index + 2];
edge->m_hasVertex3 = true;
}
else
{
edge->m_vertex3 = m_nextVertex;
edge->m_hasVertex3 = m_hasNextVertex;
}
}

Expand Down
Loading

0 comments on commit 8118426

Please sign in to comment.