mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-04 05:13:11 +02:00
add PhysicalEntity class
Model and RagDoll derive from PhysicalEntity Shape gets back pointer to its Entity (shape sharing not possible) CollisionInfo gets backpointers the shapes involved
This commit is contained in:
parent
e0ebc61b25
commit
5be470bcbc
10 changed files with 145 additions and 52 deletions
|
@ -16,15 +16,15 @@
|
|||
#include <glm/gtx/transform.hpp>
|
||||
#include <glm/gtx/norm.hpp>
|
||||
|
||||
#include <CapsuleShape.h>
|
||||
#include <GeometryUtil.h>
|
||||
#include <PhysicalEntity.h>
|
||||
#include <ShapeCollider.h>
|
||||
#include <SphereShape.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Model.h"
|
||||
|
||||
#include <SphereShape.h>
|
||||
#include <CapsuleShape.h>
|
||||
#include <ShapeCollider.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static int modelPointerTypeId = qRegisterMetaType<QPointer<Model> >();
|
||||
|
@ -33,6 +33,7 @@ static int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();
|
|||
|
||||
Model::Model(QObject* parent) :
|
||||
QObject(parent),
|
||||
PhysicalEntity(PhysicalEntity::ENTITY_MODEL),
|
||||
_scale(1.0f, 1.0f, 1.0f),
|
||||
_scaleToFit(false),
|
||||
_scaleToFitLargestDimension(0.0f),
|
||||
|
@ -775,34 +776,6 @@ AnimationHandlePointer Model::createAnimationHandle() {
|
|||
return handle;
|
||||
}
|
||||
|
||||
quint8 BITS_FOR_SHAPE_INDEX = 15;
|
||||
int MAX_SIMULATION_ID = 1 << (31 - BITS_FOR_SHAPE_INDEX);
|
||||
|
||||
void Model::setSimulationIndex(int index) {
|
||||
_simulationIndex = index;
|
||||
|
||||
if (_simulationIndex < 0 || _simulationIndex > MAX_SIMULATION_ID) {
|
||||
// clear simulation ID's of all the shapes
|
||||
for (int i = 0; i < _jointShapes.size(); i++) {
|
||||
Shape* shape = _jointShapes[i];
|
||||
if (shape) {
|
||||
shape->setSimulationID(-1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// update the simulation ID's of the shapes
|
||||
// upper bits store this Model's index...
|
||||
int shiftedIndex = _simulationIndex << BITS_FOR_SHAPE_INDEX;
|
||||
for (int i = 0; i < _jointShapes.size(); i++) {
|
||||
Shape* shape = _jointShapes[i];
|
||||
if (shape) {
|
||||
// ... lower bits are for the shape's index
|
||||
shape->setSimulationID(shiftedIndex + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Model::clearShapes() {
|
||||
for (int i = 0; i < _jointShapes.size(); ++i) {
|
||||
delete _jointShapes[i];
|
||||
|
@ -836,10 +809,12 @@ void Model::rebuildShapes() {
|
|||
}
|
||||
if (type == Shape::CAPSULE_SHAPE) {
|
||||
CapsuleShape* capsule = new CapsuleShape(radius, halfHeight);
|
||||
capsule->setEntity(this);
|
||||
_jointShapes.push_back(capsule);
|
||||
} else if (type == Shape::SPHERE_SHAPE) {
|
||||
SphereShape* sphere = new SphereShape(radius, glm::vec3(0.0f));
|
||||
_jointShapes.push_back(sphere);
|
||||
sphere->setEntity(this);
|
||||
} else {
|
||||
// this shape type is not handled and the joint shouldn't collide,
|
||||
// however we must have a Shape* for each joint, so we push NULL
|
||||
|
@ -1815,6 +1790,10 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re
|
|||
}
|
||||
}
|
||||
|
||||
void Model::setShapeBackPointers() {
|
||||
PhysicalEntity::setShapeBackPointers(_jointShapes, this);
|
||||
}
|
||||
|
||||
void AnimationHandle::setURL(const QUrl& url) {
|
||||
if (_url != url) {
|
||||
_animation = Application::getInstance()->getAnimationCache()->getAnimation(_url = url);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <QUrl>
|
||||
|
||||
#include <CapsuleShape.h>
|
||||
#include <PhysicalEntity.h>
|
||||
|
||||
#include <AnimationCache.h>
|
||||
|
||||
|
@ -33,7 +34,7 @@ typedef QSharedPointer<AnimationHandle> AnimationHandlePointer;
|
|||
typedef QWeakPointer<AnimationHandle> WeakAnimationHandlePointer;
|
||||
|
||||
/// A generic 3D model displaying geometry loaded from a URL.
|
||||
class Model : public QObject {
|
||||
class Model : public QObject, public PhysicalEntity {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -137,7 +138,6 @@ public:
|
|||
|
||||
const QList<AnimationHandlePointer>& getRunningAnimations() const { return _runningAnimations; }
|
||||
|
||||
void setSimulationIndex(int index);
|
||||
void clearShapes();
|
||||
void rebuildShapes();
|
||||
void resetShapePositions(); // DEBUG method
|
||||
|
@ -167,6 +167,7 @@ public:
|
|||
const CapsuleShape& getBoundingShape() const { return _boundingShape; }
|
||||
|
||||
protected:
|
||||
virtual void setShapeBackPointers();
|
||||
|
||||
QSharedPointer<NetworkGeometry> _geometry;
|
||||
|
||||
|
|
|
@ -47,8 +47,8 @@ void CollisionList::clear() {
|
|||
//collision._intData = 0;
|
||||
//collision._floatDAta = 0.0f;
|
||||
//collision._vecData = glm::vec3(0.0f);
|
||||
//collision._shapeA = -1;
|
||||
//collision._shapeB = -1;
|
||||
//collision._shapeA = NULL;
|
||||
//collision._shapeB = NULL;
|
||||
//collision._damping;
|
||||
//collision._elasticity;
|
||||
//collision._contactPoint;
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include <QVector>
|
||||
|
||||
class Shape;
|
||||
|
||||
const quint32 COLLISION_GROUP_ENVIRONMENT = 1U << 0;
|
||||
const quint32 COLLISION_GROUP_AVATARS = 1U << 1;
|
||||
const quint32 COLLISION_GROUP_VOXELS = 1U << 2;
|
||||
|
@ -33,8 +35,8 @@ public:
|
|||
CollisionInfo()
|
||||
: _data(NULL),
|
||||
_intData(0),
|
||||
_shapeA(-1),
|
||||
_shapeB(-1),
|
||||
_shapeA(NULL),
|
||||
_shapeB(NULL),
|
||||
_damping(0.f),
|
||||
_elasticity(1.f),
|
||||
_contactPoint(0.f),
|
||||
|
@ -45,8 +47,8 @@ public:
|
|||
CollisionInfo(qint32 type)
|
||||
: _data(NULL),
|
||||
_intData(0),
|
||||
_shapeA(-1),
|
||||
_shapeB(-1),
|
||||
_shapeA(NULL),
|
||||
_shapeB(NULL),
|
||||
_damping(0.f),
|
||||
_elasticity(1.f),
|
||||
_contactPoint(0.f),
|
||||
|
@ -62,8 +64,11 @@ public:
|
|||
float _floatData;
|
||||
glm::vec3 _vecData;
|
||||
|
||||
int _shapeA; // ID of shapeA in its SimulationEngine
|
||||
int _shapeB; // ID of shapeB in its SimulationEngine
|
||||
Shape* getShapeA() const { return const_cast<Shape*>(_shapeA); }
|
||||
Shape* getShapeB() const { return const_cast<Shape*>(_shapeB); }
|
||||
|
||||
const Shape* _shapeA; // pointer to shapeA in this collision
|
||||
const Shape* _shapeB; // pointer to shapeB in this collision
|
||||
|
||||
float _damping; // range [0,1] of friction coeficient
|
||||
float _elasticity; // range [0,1] of energy conservation
|
||||
|
|
24
libraries/shared/src/PhysicalEntity.cpp
Normal file
24
libraries/shared/src/PhysicalEntity.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// PhysicalEntity.cpp
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows 2014.06.11
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "PhysicalEntity.h"
|
||||
#include "Shape.h"
|
||||
|
||||
// static
|
||||
void PhysicalEntity::setShapeBackPointers(const QVector<Shape*>& shapes, PhysicalEntity* entity) {
|
||||
for (int i = 0; i < shapes.size(); i++) {
|
||||
Shape* shape = shapes[i];
|
||||
if (shape) {
|
||||
shape->setEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
43
libraries/shared/src/PhysicalEntity.h
Normal file
43
libraries/shared/src/PhysicalEntity.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// PhysicalEntity.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows 2014.05.30
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_PhysicalEntity_h
|
||||
#define hifi_PhysicalEntity_h
|
||||
|
||||
#include <QVector>
|
||||
|
||||
class Shape;
|
||||
|
||||
// PhysicalEntity is the base class for anything that owns one or more Shapes that collide in a
|
||||
// SimulationEngine. Each CollisionInfo generated by a SimulationEngine has back pointers to the
|
||||
// two Shapes involved, and those Shapes may (optionally) have valid back pointers to their PhysicalEntity.
|
||||
|
||||
class PhysicalEntity {
|
||||
|
||||
public:
|
||||
enum EntityType {
|
||||
ENTITY_UNKNOWN,
|
||||
ENTITY_MODEL,
|
||||
ENTITY_RAGDOLL,
|
||||
};
|
||||
|
||||
static void setShapeBackPointers(const QVector<Shape*>& shapes, PhysicalEntity* entity);
|
||||
|
||||
PhysicalEntity(EntityType type = ENTITY_UNKNOWN) : _entityType(type) {}
|
||||
virtual ~PhysicalEntity() {}
|
||||
|
||||
EntityType getEntityType() const { return _entityType; }
|
||||
|
||||
protected:
|
||||
EntityType _entityType;
|
||||
};
|
||||
|
||||
#endif // hifi_PhysicalEntity_h
|
|
@ -94,7 +94,7 @@ void DistanceConstraint::updateProxyShape(Shape* shape, const glm::quat& rotatio
|
|||
// RagDoll
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
RagDoll::RagDoll() : _shapes(NULL) {
|
||||
RagDoll::RagDoll() : PhysicalEntity(PhysicalEntity::ENTITY_RAGDOLL), _shapes(NULL) {
|
||||
}
|
||||
|
||||
RagDoll::~RagDoll() {
|
||||
|
@ -121,6 +121,9 @@ void RagDoll::init(QVector<Shape*>* shapes, const QVector<int>& parentIndices, c
|
|||
_constraints.push_back(stick);
|
||||
}
|
||||
}
|
||||
if (_shapes) {
|
||||
PhysicalEntity::setShapeBackPointers(*_shapes, this);
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete all data.
|
||||
|
@ -131,6 +134,10 @@ void RagDoll::clear() {
|
|||
}
|
||||
_constraints.clear();
|
||||
_points.clear();
|
||||
if (_shapes) {
|
||||
PhysicalEntity::setShapeBackPointers(*_shapes, NULL);
|
||||
}
|
||||
_shapes = NULL;
|
||||
}
|
||||
|
||||
float RagDoll::enforceConstraints() {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include <QVector>
|
||||
|
||||
class Shape;
|
||||
#include "PhysicalEntity.h"
|
||||
|
||||
class Constraint {
|
||||
public:
|
||||
|
@ -61,7 +61,7 @@ private:
|
|||
glm::vec3* _points[2];
|
||||
};
|
||||
|
||||
class RagDoll {
|
||||
class RagDoll : public PhysicalEntity {
|
||||
public:
|
||||
|
||||
RagDoll();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
class PhysicalEntity;
|
||||
|
||||
class Shape {
|
||||
public:
|
||||
|
@ -26,7 +27,7 @@ public:
|
|||
LIST_SHAPE
|
||||
};
|
||||
|
||||
Shape() : _type(UNKNOWN_SHAPE), _simulationID(-1), _boundingRadius(0.f), _position(0.f), _rotation() { }
|
||||
Shape() : _type(UNKNOWN_SHAPE), _owningEntity(NULL), _boundingRadius(0.f), _position(0.f), _rotation() { }
|
||||
virtual ~Shape() {}
|
||||
|
||||
int getType() const { return _type; }
|
||||
|
@ -37,23 +38,23 @@ public:
|
|||
virtual void setPosition(const glm::vec3& position) { _position = position; }
|
||||
virtual void setRotation(const glm::quat& rotation) { _rotation = rotation; }
|
||||
|
||||
void setSimulationID(int id) { _simulationID = id; }
|
||||
int getSimulationID() const { return _simulationID; }
|
||||
void setEntity(PhysicalEntity* entity) { _owningEntity = entity; }
|
||||
PhysicalEntity* getEntity() const { return _owningEntity; }
|
||||
|
||||
protected:
|
||||
// these ctors are protected (used by derived classes only)
|
||||
Shape(Type type) : _type(type), _boundingRadius(0.f), _position(0.f), _rotation() {}
|
||||
Shape(Type type) : _type(type), _owningEntity(NULL), _boundingRadius(0.f), _position(0.f), _rotation() {}
|
||||
|
||||
Shape(Type type, const glm::vec3& position)
|
||||
: _type(type), _boundingRadius(0.f), _position(position), _rotation() {}
|
||||
: _type(type), _owningEntity(NULL), _boundingRadius(0.f), _position(position), _rotation() {}
|
||||
|
||||
Shape(Type type, const glm::vec3& position, const glm::quat& rotation)
|
||||
: _type(type), _boundingRadius(0.f), _position(position), _rotation(rotation) {}
|
||||
: _type(type), _owningEntity(NULL), _boundingRadius(0.f), _position(position), _rotation(rotation) {}
|
||||
|
||||
void setBoundingRadius(float radius) { _boundingRadius = radius; }
|
||||
|
||||
int _type;
|
||||
int _simulationID; // shape's simulation ID in SimulationEngine
|
||||
PhysicalEntity* _owningEntity;
|
||||
float _boundingRadius;
|
||||
glm::vec3 _position;
|
||||
glm::quat _rotation;
|
||||
|
|
|
@ -87,6 +87,9 @@ bool collideShapesCoarse(const QVector<const Shape*>& shapesA, const QVector<con
|
|||
}
|
||||
collision._penetration = totalPenetration;
|
||||
collision._contactPoint = averageContactPoint / (float)(tempCollisions.size());
|
||||
// there are no valid shape pointers for this collision so we set them NULL
|
||||
collision._shapeA = NULL;
|
||||
collision._shapeB = NULL;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -135,6 +138,8 @@ bool sphereSphere(const SphereShape* sphereA, const SphereShape* sphereB, Collis
|
|||
collision->_penetration = BA * (totalRadius - distance);
|
||||
// contactPoint is on surface of A
|
||||
collision->_contactPoint = sphereA->getPosition() + sphereA->getRadius() * BA;
|
||||
collision->_shapeA = sphereA;
|
||||
collision->_shapeB = sphereB;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -179,6 +184,8 @@ bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, Col
|
|||
collision->_penetration = (totalRadius - radialDistance) * radialAxis; // points from A into B
|
||||
// contactPoint is on surface of sphereA
|
||||
collision->_contactPoint = sphereA->getPosition() + sphereA->getRadius() * radialAxis;
|
||||
collision->_shapeA = sphereA;
|
||||
collision->_shapeB = capsuleB;
|
||||
} else {
|
||||
// A is on B's axis, so the penetration is undefined...
|
||||
if (absAxialDistance > capsuleB->getHalfHeight()) {
|
||||
|
@ -200,6 +207,8 @@ bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, Col
|
|||
collision->_penetration = (sign * (totalRadius + capsuleB->getHalfHeight() - absAxialDistance)) * capsuleAxis;
|
||||
// contactPoint is on surface of sphereA
|
||||
collision->_contactPoint = sphereA->getPosition() + (sign * sphereA->getRadius()) * capsuleAxis;
|
||||
collision->_shapeA = sphereA;
|
||||
collision->_shapeB = capsuleB;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -215,6 +224,8 @@ bool spherePlane(const SphereShape* sphereA, const PlaneShape* planeB, Collision
|
|||
}
|
||||
collision->_penetration = penetration;
|
||||
collision->_contactPoint = sphereA->getPosition() + sphereA->getRadius() * glm::normalize(penetration);
|
||||
collision->_shapeA = sphereA;
|
||||
collision->_shapeB = planeB;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -264,6 +275,8 @@ bool capsuleSphere(const CapsuleShape* capsuleA, const SphereShape* sphereB, Col
|
|||
collision->_penetration = (radialDistance - totalRadius) * radialAxis; // points from A into B
|
||||
// contactPoint is on surface of capsuleA
|
||||
collision->_contactPoint = closestApproach - capsuleA->getRadius() * radialAxis;
|
||||
collision->_shapeA = capsuleA;
|
||||
collision->_shapeB = sphereB;
|
||||
} else {
|
||||
// A is on B's axis, so the penetration is undefined...
|
||||
if (absAxialDistance > capsuleA->getHalfHeight()) {
|
||||
|
@ -284,6 +297,8 @@ bool capsuleSphere(const CapsuleShape* capsuleA, const SphereShape* sphereB, Col
|
|||
collision->_penetration = (sign * (totalRadius + capsuleA->getHalfHeight() - absAxialDistance)) * capsuleAxis;
|
||||
// contactPoint is on surface of sphereA
|
||||
collision->_contactPoint = closestApproach + (sign * capsuleA->getRadius()) * capsuleAxis;
|
||||
collision->_shapeA = capsuleA;
|
||||
collision->_shapeB = sphereB;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -355,6 +370,8 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB,
|
|||
collision->_penetration = BA * (totalRadius - distance);
|
||||
// contactPoint is on surface of A
|
||||
collision->_contactPoint = centerA + distanceA * axisA + capsuleA->getRadius() * BA;
|
||||
collision->_shapeA = capsuleA;
|
||||
collision->_shapeB = capsuleB;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
@ -420,6 +437,8 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB,
|
|||
// average the internal pair, and then do the math from centerB
|
||||
collision->_contactPoint = centerB + (0.5f * (points[1] + points[2])) * axisB
|
||||
+ (capsuleA->getRadius() - distance) * BA;
|
||||
collision->_shapeA = capsuleA;
|
||||
collision->_shapeB = capsuleB;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -439,6 +458,8 @@ bool capsulePlane(const CapsuleShape* capsuleA, const PlaneShape* planeB, Collis
|
|||
collision->_penetration = penetration;
|
||||
glm::vec3 deepestEnd = (glm::dot(start, glm::vec3(plane)) < glm::dot(end, glm::vec3(plane))) ? start : end;
|
||||
collision->_contactPoint = deepestEnd + capsuleA->getRadius() * glm::normalize(penetration);
|
||||
collision->_shapeA = capsuleA;
|
||||
collision->_shapeB = planeB;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -454,6 +475,8 @@ bool planeSphere(const PlaneShape* planeA, const SphereShape* sphereB, Collision
|
|||
collision->_penetration = -penetration;
|
||||
collision->_contactPoint = sphereB->getPosition() +
|
||||
(sphereB->getRadius() / glm::length(penetration) - 1.0f) * penetration;
|
||||
collision->_shapeA = planeA;
|
||||
collision->_shapeB = sphereB;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -472,6 +495,8 @@ bool planeCapsule(const PlaneShape* planeA, const CapsuleShape* capsuleB, Collis
|
|||
collision->_penetration = -penetration;
|
||||
glm::vec3 deepestEnd = (glm::dot(start, glm::vec3(plane)) < glm::dot(end, glm::vec3(plane))) ? start : end;
|
||||
collision->_contactPoint = deepestEnd + (capsuleB->getRadius() / glm::length(penetration) - 1.0f) * penetration;
|
||||
collision->_shapeA = planeA;
|
||||
collision->_shapeB = capsuleB;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -664,6 +689,8 @@ bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm::
|
|||
}
|
||||
collision->_floatData = cubeSide;
|
||||
collision->_vecData = cubeCenter;
|
||||
collision->_shapeA = NULL;
|
||||
collision->_shapeB = NULL;
|
||||
return true;
|
||||
} else if (sphereRadius + halfCubeSide > distance) {
|
||||
// NOTE: for cocentric approximation we collide sphere and cube as two spheres which means
|
||||
|
@ -677,6 +704,8 @@ bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm::
|
|||
|
||||
collision->_floatData = cubeSide;
|
||||
collision->_vecData = cubeCenter;
|
||||
collision->_shapeA = NULL;
|
||||
collision->_shapeB = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -712,6 +741,8 @@ bool sphereAACube_StarkAngles(const glm::vec3& sphereCenter, float sphereRadius,
|
|||
collision->_penetration = glm::dot(surfaceAB, direction) * direction;
|
||||
// contactPoint is on surface of A
|
||||
collision->_contactPoint = sphereCenter + sphereRadius * direction;
|
||||
collision->_shapeA = NULL;
|
||||
collision->_shapeB = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -724,6 +755,8 @@ bool sphereAACube_StarkAngles(const glm::vec3& sphereCenter, float sphereRadius,
|
|||
collision->_penetration = (sphereRadius + 0.5f * cubeSide) * glm::vec3(0.0f, -1.0f, 0.0f);
|
||||
// contactPoint is on surface of A
|
||||
collision->_contactPoint = sphereCenter + collision->_penetration;
|
||||
collision->_shapeA = NULL;
|
||||
collision->_shapeB = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue