24 normal = other.normal;
28 for (
size_t i = 0; i < other.count; i++) {
29 points[i] = other.points[i];
32 staticFriction = other.staticFriction;
33 dynamicFriction = other.dynamicFriction;
34 restitution = other.restitution;
38 vec2 normal = { Float(0.0), Float(0.0) };
39 Float depth = std::numeric_limits<Float>::max();
42 std::array<vec2, 2> points;
44 Float staticFriction = Float(1.0);
45 Float dynamicFriction = Float(1.0);
46 Float restitution = Float(0.0);
54 return !isNaN(normal) &&
58 !isNaN(staticFriction) &&
59 !isNaN(dynamicFriction) &&
66 std::vector<CollisionManifold> manifolds;
67 std::vector<std::array<vec2, 4>> tileAABBs;
68 std::vector<std::array<vec2, 4>> chunkAABBs;
71 std::vector<CollideInfo> collideInfos;
88template<
class BoxVertexContainer,
class NormalContainer>
89bool satBoxTest(
const BoxVertexContainer& vertices1,
const BoxVertexContainer& vertices2,
const NormalContainer& normals,
CollisionManifold& manifold) {
90 assert(normals.size() == 2);
91 assert(vertices1.size() == 4);
92 assert(vertices2.size() == 4);
94 for (
size_t i = 0; i < normals.size(); i++) {
96 const vec2& normal = normals[i];
98 MinMax proj1 = projectBoxOnNormal(vertices1, normal);
99 MinMax proj2 = projectBoxOnNormal(vertices2, normal);
101 if (!(proj1.second >= proj2.first && proj2.second >= proj1.first)) {
106 Float newDepth = std::max(Float(0.0), std::min(proj1.second, proj2.second) - std::max(proj1.first, proj2.first));
107 if (newDepth <= manifold.depth) {
108 manifold.normal = normal;
109 manifold.depth = newDepth;
112 Float direction = proj1.second - proj2.second;
114 manifold.normal *= -1.0f;
138template<
typename Container,
typename Integer>
140 const Container& points1,
const Container& points2) {
141 for (Integer i = 0; i < points1.size(); i++) {
144 for (Integer j = 0; j < points2.size(); j++) {
145 vec2 cur = points2[j];
146 vec2 next = points2[(j + 1) % points2.size()];
149 Float distance = pointSegmentDistance(p, cur, next, cp);
151 if (nearlyEqual(distance, distance1, 0.1f)) {
152 if (!nearlyEqual(cp, cp1, 0.005f)) {
157 else if (distance <= distance1) {
160 distance1 = distance;
176template<
typename Container>
178 std::array<vec2, 2> edge1;
179 std::array<vec2, 2> edge2;
182 Float max = -std::numeric_limits<Float>::max();
183 for (
size_t i = 0; i < 4; i++) {
184 const vec2 p1 = points1[i];
185 const vec2 p2 = points1[(i + 1) % 4];
186 const vec2 edge = p2 - p1;
187 const vec2 normal = { -edge.y, edge.x };
189 const Float dot = glm::dot(normal, -manifold.normal);
198 max = -std::numeric_limits<Float>::max();
199 for (
size_t i = 0; i < 4; i++) {
200 const vec2 p1 = points2[i];
201 const vec2 p2 = points2[(i + 1) % 4];
202 const vec2 edge = p2 - p1;
203 const vec2 normal = { -edge.y, edge.x };
205 const Float dot = glm::dot(normal, manifold.normal);
213 Float minDist = std::numeric_limits<Float>::max();
214 findClosestPoint(manifold.points[0], manifold.points[1], manifold.count, minDist, edge1, edge2);
216 assert(manifold.count >= 1);
235template<
class TileData>
238 const glm::i32vec2& tilePos1,
239 const vec2& body1Offset,
241 const glm::i32vec2& tilePos2,
242 const vec2& body2Offset,
248 auto normals1 = body1.
normals();
249 if (!
satBoxTest(tileObb1, tileObb2, normals1, manifold))
252 auto normals2 = body2.
normals();
253 if (!
satBoxTest(tileObb1, tileObb2, normals2, manifold))
257 if (manifold.depth == 0.0f)
266 manifold.dynamicFriction = convertToFloat(tile1.dynamicFriction) * convertToFloat(tile2.dynamicFriction);
267 manifold.staticFriction = convertToFloat(tile1.staticFriction) * convertToFloat(tile2.staticFriction);
268 manifold.restitution = convertToFloat(std::max(tile1.restitution, tile2.restitution));
277template<
class TileData>
279 using SpatialIndex = typename ::t2d::TileBody<TileData>::SpatialIndex;
281 std::vector<SpatialIndex> results1;
282 std::vector<SpatialIndex> results2;
283 std::vector<std::pair<AABB<Float>,
AABB<Float>>> approxAreas;
298template<
class TileData>
303 std::vector<CollisionManifold>& manifolds,
307 if (std::isnan(approxAreaOfBody1Local.min().x))
311 if (std::isnan(approxAreaOfBody2Local.min().x))
314 cache.results1.clear();
315 cache.results2.clear();
316 cache.approxAreas.clear();
318 body1.
queryChunks(approxAreaOfBody1Local, std::back_inserter(cache.results1));
319 body2.
queryChunks(approxAreaOfBody2Local, std::back_inserter(cache.results2));
323 for (
auto& r1 : cache.results1)
324 collideInfo.chunkAABBs.push_back(body1.getLocalAABBWorldVertices(r1.aabb));
326 for (
auto& r2 : cache.results2)
327 collideInfo.chunkAABBs.push_back(body2.getLocalAABBWorldVertices(r2.aabb));
330 for (
auto& chunk1 : cache.results1) {
331 for (
auto& chunk2 : cache.results2) {
333 if (std::isnan(approxAreaOfChunk1Local.min().x))
337 if (std::isnan(approxAreaOfChunk2Local.min().x))
340 cache.approxAreas.push_back(std::pair(approxAreaOfChunk1Local, approxAreaOfChunk2Local));
344 for (
const auto& approxArea : cache.approxAreas) {
345 cache.results1.clear();
346 cache.results2.clear();
348 body1.
queryTiles(approxArea.first, std::back_inserter(cache.results1));
349 body2.
queryTiles(approxArea.second, std::back_inserter(cache.results2));
352 for (
auto& r1 : cache.results1)
353 collideInfo.tileAABBs.push_back(body1.getLocalAABBWorldVertices(body1.
getTileLocalAABB(r1.pos)));
355 for (
auto& r2 : cache.results2)
356 collideInfo.tileAABBs.push_back(body2.getLocalAABBWorldVertices(body2.
getTileLocalAABB(r2.pos)));
360 for (
auto& tile1 : cache.results1) {
361 for (
auto& tile2 : cache.results2) {
365 Float body1Mass = body1.
mass() * (Float)!body1.
isStatic();
366 Float body2Mass = body2.
mass() * (Float)!body2.
isStatic();
367 Float totalMass = body1Mass + body2Mass;
368 Float body1Depth = (body1Mass / totalMass) * manifold.depth;
369 Float body2Depth = (body2Mass / totalMass) * manifold.depth;
371 body1Offset -= manifold.normal * body1Depth * Float(0.5);
372 body2Offset += manifold.normal * body2Depth * Float(0.5);
374 manifolds.emplace_back(manifold);
376 collideInfo.manifolds.emplace_back(manifold);
384 debug::collideInfos.emplace_back(std::move(collideInfo));
399 vec2 r1 = {Float(0.0), Float(0.0)};
400 vec2 r2 = {Float(0.0), Float(0.0)};
402 vec2 friction_impulse = { 0.0f, 0.0f };
407 vec2 average = manifold.points[0];
409 if (manifold.count == 2) {
410 average += manifold.points[1];
418 vec2 r1_perp = { impulse.r1.y, -impulse.r1.x };
419 vec2 r2_perp = { impulse.r2.y, -impulse.r2.x };
421 vec2 angular_linear1 = r1_perp * body1.m_angularVelocity;
422 vec2 angular_linear2 = r2_perp * body2.m_angularVelocity;
425 (body2.m_linearVelocity + angular_linear2) -
426 (body1.m_linearVelocity + angular_linear1);
428 Float rel_vel_dot_n = glm::dot(rel_vel, manifold.normal);
429 if (rel_vel_dot_n > 0.0f)
432 Float r1_perp_dot_n = glm::dot(r1_perp, manifold.normal);
433 Float r2_perp_dot_n = glm::dot(r2_perp, manifold.normal);
436 body1.m_inverseMass + body2.m_inverseMass +
437 (sqaure(r1_perp_dot_n) * body1.m_inverseI) +
438 (sqaure(r2_perp_dot_n) * body2.m_inverseI);
440 impulse.j = -(1.0f + manifold.restitution) * rel_vel_dot_n;
442 impulse.j /= (Float)manifold.count;
445 vec2 impulsej = impulse.j * manifold.normal;
447 body1.m_linearVelocity -= impulsej * body1.m_inverseMass;
448 body1.m_angularVelocity -= cross(impulsej, impulse.r1) * body1.m_inverseI;
449 body2.m_linearVelocity += impulsej * body2.m_inverseMass;
450 body2.m_angularVelocity += cross(impulsej, impulse.r2) * body2.m_inverseI;
454 vec2 r1_perp = { impulse.r1.y, -impulse.r1.x };
455 vec2 r2_perp = { impulse.r2.y, -impulse.r2.x };
457 vec2 angular_linear1 = r1_perp * body1.m_angularVelocity;
458 vec2 angular_linear2 = r2_perp * body2.m_angularVelocity;
461 (body2.m_linearVelocity + angular_linear2) - (body1.m_linearVelocity + angular_linear1);
463 vec2 tangent = rel_vel - glm::dot(rel_vel, manifold.normal) * manifold.normal;
464 if (nearlyEqual(tangent, { 0.0f, 0.0f }))
467 tangent = glm::normalize(tangent);
469 Float r1_perp_dot_t = glm::dot(r1_perp, tangent);
470 Float r2_perp_dot_t = glm::dot(r2_perp, tangent);
473 body1.m_inverseMass + body2.m_inverseMass +
474 (sqaure(r1_perp_dot_t) * body1.m_inverseI) +
475 (sqaure(r2_perp_dot_t) * body2.m_inverseI);
477 Float jt = -glm::dot(rel_vel, tangent);
479 jt /= manifold.count;
481 if (glm::abs(jt) <= impulse.j * manifold.staticFriction) {
482 impulse.friction_impulse = jt * tangent;
485 impulse.friction_impulse = -impulse.j * tangent * manifold.dynamicFriction;
488 body1.m_linearVelocity -= impulse.friction_impulse * body1.m_inverseMass;
489 body1.m_angularVelocity -= cross(impulse.friction_impulse, impulse.r1) * body1.m_inverseI;
491 body2.m_linearVelocity += impulse.friction_impulse * body2.m_inverseMass;
492 body2.m_angularVelocity += cross(impulse.friction_impulse, impulse.r2) * body2.m_inverseI;
Extends the functionality of WorldBody to allow for things such as angular velocity.
Definition body.hpp:238
const vec2 & com() const
Returns the center of mass of this body.
Definition body.hpp:321
virtual vec2 getWorldPos() override
Returns the world position of this body.
Definition body.hpp:286
For use with a TileMap<>, allows collisions with other rigid bodies inside World<>
Definition tileMap.hpp:271
TileMap< TileType > & tileMap() const
Returns the tile map attached to this rigid body.
Definition tileMap.hpp:322
void queryChunks(const AABB< Float > &intersectBox, OutIt chunks) const
Will get the list of chunks that intersect intersectBox, along with their AABBS.
Definition tileMap.hpp:450
virtual AABB< Float > getAABB() const override
Returns the AABB of this body.
Definition tileMap.hpp:313
std::array< vec2, 2 > normals() const
Returns the normals of this body. Can be used for all tiles of this body.
Definition tileMap.hpp:331
void queryTiles(const AABB< Float > &intersectBox, OutIt tiles) const
Will get the list of tiles that intersect intersectBox.
Definition tileMap.hpp:478
std::array< vec2, 4 > getTileWorldOBBOffsetVertices(const glm::i32vec2 &iPos, const vec2 &worldOffset) const
Returns the world vertices of the tile located at iPos. with an added offset.
Definition tileMap.hpp:399
AABB< Float > getTileLocalAABB(const glm::i32vec2 &iPos) const
Returns the local AABB of a tile located at iPos.
Definition tileMap.hpp:434
Transform & transform()
Returns the REFERENCE transform of this body.
Definition body.hpp:64
bool isStatic() const
Returns if the body is static, meaning it cannot be moved by forces or other bodies.
Definition body.hpp:135
Float mass() const
Returns the mass of this body.
Definition body.hpp:189
bool satBoxTest(const BoxVertexContainer &vertices1, const BoxVertexContainer &vertices2, const NormalContainer &normals, CollisionManifold &manifold)
Returns the normal and depth of two polygons defined by the vertices vertices1 and vertices2 by using...
Definition collide.hpp:89
bool detectNarrowCollision(const TileBody< TileData > &body1, const glm::i32vec2 &tilePos1, const vec2 &body1Offset, const TileBody< TileData > &body2, const glm::i32vec2 &tilePos2, const vec2 &body2Offset, CollisionManifold &manifold)
Detects the collision between the tile in tilePos1 of body1 and the tile tilePos2 of body2.
Definition collide.hpp:236
void findClosestPoint(vec2 &cp1, vec2 &cp2, Integer &count, Float &distance1, const Container &points1, const Container &points2)
Finds the closest point between points1 and the faces defined by points2.
Definition collide.hpp:139
void computeBoxManifold(const Container &points1, const Container &points2, CollisionManifold &manifold)
Finds the closest point between points1 and the faces defined by points2.
Definition collide.hpp:177
void detectTileBodyCollision(const TileBody< TileData > &body1, const TileBody< TileData > &body2, TileBodyCollisionCache< TileData > &cache, std::vector< CollisionManifold > &manifolds, vec2 &body1Offset, vec2 &body2Offset)
Detects the collision between the tiles bodies, body1 and body2.
Definition collide.hpp:299
Defines the relevant collision information generated by detectNarrowColllision() to both resolve the ...
Definition collide.hpp:20
bool isValid() const
If any members are NaN, normal is not normalized, or the contact count is more then 2,...
Definition collide.hpp:53
Definition collide.hpp:398
Resolves the collision between two bodies using the impulse method.
Definition collide.hpp:397
Contains the physical properties of a tile, such as elasticity.
Definition tileMap.hpp:45
Used to speed up the collision detection between two tile bodies.
Definition collide.hpp:278
Definition collide.hpp:65
Defines TileMap<> and TileBody<>