public SphereTriangleCollisionManager() { GravityEnabled = true; GravityForce = new Vector3(0, -10, 0); SlideFactor = 1.3f; LastCollisionNormal = Vector3.Empty; movementSphere = new TgcBoundingSphere(); objetosCandidatos = new List <Colisionador>(); lastCollider = null; OnGroundMinDotValue = 0.8f; Collision = false; LastMovementVector = Vector3.Empty; }
/// <summary> /// Detección de colisiones recursiva /// </summary> public void doCollideWithWorld(TgcBoundingSphere characterSphere, Vector3 movementVector, List <Colisionador> colliders, int recursionDepth, TgcBoundingSphere movementSphere, bool sliding, float slidingMinY) { //Limitar recursividad if (recursionDepth > 5) { return; } //Posicion deseada var originalSphereCenter = characterSphere.Center; var nextSphereCenter = originalSphereCenter + movementVector; //Buscar el punto de colision mas cercano de todos los objetos candidatos Collision = false; Vector3 q; float t; Vector3 n; var minT = float.MaxValue; foreach (var collider in colliders) { //Colisionar Sphere en movimiento contra Collider (cada Collider resuelve la colision) if (collider.intersectMovingSphere(characterSphere, movementVector, movementSphere, out t, out q, out n)) { //Quedarse con el menor instante de colision if (t < minT) { minT = t; Collision = true; LastCollisionPoint = q; LastCollisionNormal = n; lastCollider = collider; } } } //Si nunca hubo colisión, avanzar todo lo requerido if (!Collision) { //Avanzar todo lo pedido //lastCollisionDistance = movementVector.Length(); characterSphere.moveCenter(movementVector); return; } //Solo movernos si ya no estamos muy cerca if (minT >= EPSILON) { //Restar un poco al instante de colision, para movernos hasta casi esa distancia minT -= EPSILON; var realMovementVector = movementVector * minT; //Mover el BoundingSphere characterSphere.moveCenter(realMovementVector); //Quitarle al punto de colision el EPSILON restado al movimiento, para no afectar al plano de sliding var v = Vector3.Normalize(realMovementVector); LastCollisionPoint -= v * EPSILON; } if (sliding) { //Calcular plano de Sliding, como un plano tangete al punto de colision con la esfera, apuntando hacia el centro de la esfera var slidePlaneOrigin = LastCollisionPoint; var slidePlaneNormal = characterSphere.Center - LastCollisionPoint; slidePlaneNormal.Normalize(); var slidePlane = Plane.FromPointNormal(slidePlaneOrigin, slidePlaneNormal); //Calcular vector de movimiento para sliding, proyectando el punto de destino original sobre el plano de sliding var distance = TgcCollisionUtils.distPointPlane(nextSphereCenter, slidePlane); var newDestinationPoint = nextSphereCenter - distance * slidePlaneNormal; var slideMovementVector = newDestinationPoint - LastCollisionPoint; //No hacer recursividad si es muy pequeño slideMovementVector.Scale(SlideFactor); if (slideMovementVector.Length() < EPSILON) { return; } if (LastCollisionNormal.Y <= slidingMinY) { //Recursividad para aplicar sliding doCollideWithWorld(characterSphere, slideMovementVector, colliders, recursionDepth + 1, movementSphere, sliding, slidingMinY); } } }