public SphereTriangleCollisionManager() { gravityEnabled = true; gravityForce = new Vector3(0, -10, 0); slideFactor = 1.3f; lastCollisionNormal = Vector3.Empty; movementSphere = new TgcBoundingSphere(); objetosCandidatos = new List<Collider>(); 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<Collider> colliders, int recursionDepth, TgcBoundingSphere movementSphere, bool sliding, float slidingMinY) { //Limitar recursividad if (recursionDepth > 5) { return; } //Posicion deseada Vector3 originalSphereCenter = characterSphere.Center; Vector3 nextSphereCenter = originalSphereCenter + movementVector; //Buscar el punto de colision mas cercano de todos los objetos candidatos collision = false; Vector3 q; float t; Vector3 n; float minT = float.MaxValue; foreach (Collider 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; Vector3 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 Vector3 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 Vector3 slidePlaneOrigin = lastCollisionPoint; Vector3 slidePlaneNormal = characterSphere.Center - lastCollisionPoint; slidePlaneNormal.Normalize(); Plane slidePlane = Plane.FromPointNormal(slidePlaneOrigin, slidePlaneNormal); //Calcular vector de movimiento para sliding, proyectando el punto de destino original sobre el plano de sliding float distance = TgcCollisionUtils.distPointPlane(nextSphereCenter, slidePlane); Vector3 newDestinationPoint = nextSphereCenter - distance * slidePlaneNormal; Vector3 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); } } }