/// <summary> /// Solve collisions of moving objects. /// This is automatically called by FixedUpdate, but if you change the translation.position from code, /// you have to call this method to be sure collisions are solved before rendering the object. /// </summary> protected DynamicCollisionPoint DoSolveDynamicCollisions() { Vector3 vDisp = (transform.position - m_prevPos); Vector3 vDir = vDisp.normalized; Vector3 vLocalDisp = transform.rotation != Quaternion.identity ? Quaternion.Inverse(transform.rotation) * vDisp : vDisp; //NOTE: One Way collisions will be checked separately LayerMask layerCollision = LayerCollision & ~(OneWayCollisionRight | OneWayCollisionLeft | OneWayCollisionUp | OneWayCollisionDown); bool flipX = transform.localScale.x < 0; bool flipY = transform.localScale.y < 0; List <Vector3> vRightCheckPoints = flipX ? m_vLeftCheckPoints : m_vRightCheckPoints; List <Vector3> vLeftCheckPoints = flipX ? m_vRightCheckPoints : m_vLeftCheckPoints; List <Vector3> vTopCheckPoints = flipY ? m_vBottomCheckPoints : m_vTopCheckPoints; List <Vector3> vBottomCheckPoints = flipY ? m_vTopCheckPoints : m_vBottomCheckPoints; DynamicCollisionPoint closestCollisionPoint = new DynamicCollisionPoint(float.MaxValue, Vector3.zero); // check for right movement //if (vLocalDisp.x >= 0.5f * SkinRightWidth * Mathf.Abs(transform.localScale.x)) if (vLocalDisp.x >= Vector3.kEpsilon) //NOTE: safer, but slower { closestCollisionPoint = DynamicCollisionPoint.Min(closestCollisionPoint, _DoSolveDynamicCollisionSide(vRightCheckPoints, vDisp, vDir, Vector3.zero, layerCollision)); closestCollisionPoint = DynamicCollisionPoint.Min(closestCollisionPoint, _DoSolveDynamicCollisionSide(vRightCheckPoints, vDisp, vDir, transform.right, OneWayCollisionRight)); } // check for left movement //else if (vLocalDisp.x <= -SkinLeftWidth * Mathf.Abs(transform.localScale.x)) else if (vLocalDisp.x <= -Vector3.kEpsilon) { closestCollisionPoint = DynamicCollisionPoint.Min(closestCollisionPoint, _DoSolveDynamicCollisionSide(vLeftCheckPoints, vDisp, vDir, Vector3.zero, layerCollision)); closestCollisionPoint = DynamicCollisionPoint.Min(closestCollisionPoint, _DoSolveDynamicCollisionSide(vLeftCheckPoints, vDisp, vDir, -transform.right, OneWayCollisionLeft)); } // check for up movement //if (vLocalDisp.y >= SkinTopWidth * Mathf.Abs(transform.localScale.y)) if (vLocalDisp.y >= Vector3.kEpsilon) { closestCollisionPoint = DynamicCollisionPoint.Min(closestCollisionPoint, _DoSolveDynamicCollisionSide(vTopCheckPoints, vDisp, vDir, Vector3.zero, layerCollision)); closestCollisionPoint = DynamicCollisionPoint.Min(closestCollisionPoint, _DoSolveDynamicCollisionSide(vTopCheckPoints, vDisp, vDir, transform.up, OneWayCollisionUp)); } // check for down movement //else if (vLocalDisp.y <= -SkinBottomWidth * Mathf.Abs(transform.localScale.y)) else if (vLocalDisp.y <= -Vector3.kEpsilon) { closestCollisionPoint = DynamicCollisionPoint.Min(closestCollisionPoint, _DoSolveDynamicCollisionSide(vBottomCheckPoints, vDisp, vDir, Vector3.zero, layerCollision)); closestCollisionPoint = DynamicCollisionPoint.Min(closestCollisionPoint, _DoSolveDynamicCollisionSide(vBottomCheckPoints, vDisp, vDir, -transform.up, OneWayCollisionDown)); } // check if there was a collision if (closestCollisionPoint.distance < float.MaxValue) { // new body Vector3 scaledSize = Vector3.Scale(Size, transform.localScale); DebugEx.DebugDrawRect(transform.transform.TransformPoint(Center - (Vector3)Size / 2f), new Rect(0f, 0f, scaledSize.x, scaledSize.y), Color.red, 0.5f); transform.position = m_prevPos + (closestCollisionPoint.distance - k_SkinMinWidth) * vDir; //NOTE: subtracting k_SkinMinWidth avoid precision errors } return(closestCollisionPoint); }
public static DynamicCollisionPoint Min(DynamicCollisionPoint a, DynamicCollisionPoint b) { if (a.distance < b.distance) { return(a); } else { return(b); } }
void ResolveCollisions() { //fix: calling UpdateCheckPoints when Size or Center is being change through animation if (m_prevSize != m_size || m_prevCenter != m_center) { m_prevSize = m_size; m_prevCenter = m_center; UpdateCheckPoints(); } m_instantVelocity = (transform.position - m_prevPos) / Time.deltaTime; if (m_movingPlatforms.Count > 0) { Vector3 vMovingPlarformDisp = Vector3.zero; for (int i = 0; i < m_movingPlatforms.Count; ++i) { //NOTE: // - kvp.Key is the moving platform transform // - kvp.Value is the InverseTransformPoint of the Smart Collider saved during previous FixedUpdate call // This is adding the moving platform displacement, translation and scaling to the smart collider on it KeyValuePair <Transform, Vector3> kvp = m_movingPlatforms[i]; if (kvp.Key != null) { vMovingPlarformDisp += kvp.Key.TransformPoint(kvp.Value) - m_prevPos; } } vMovingPlarformDisp /= m_movingPlatforms.Count; m_movingPlatforms.Clear(); transform.position += vMovingPlarformDisp; } /* NOTE: this code is buggy and affected by framerate, making the player to move down when it's over a platform, for example. * Vector3 movingVect = (transform.position - m_prevPos); * float movementDist = movingVect.magnitude; * bool checkToContinue; * int maxCycles = 5; * do * { * DynamicCollisionPoint closestCollPoint = DoSolveDynamicCollisions(); * movementDist -= (transform.position - m_prevPos).magnitude; * checkToContinue = (movementDist > 0.001f && closestCollPoint.distance != float.MaxValue && --maxCycles > 0); * if (checkToContinue) * { * Vector3 surfaceDir = Vector3.Cross(closestCollPoint.normal, transform.forward); * movingVect = Vector3.Project(movingVect, surfaceDir).normalized * movementDist; * m_prevPos = transform.position; * transform.position += movingVect; * } * } * while (checkToContinue);*/ Vector3 vSavedPos = transform.position; DynamicCollisionPoint dynCollPnt = DoSolveDynamicCollisions(); // If there was a dynamic collision and it is a wall, try to move it vertically if (dynCollPnt.normal.x != 0f && dynCollPnt.normal.y == 0f) { Vector3 vPos = transform.position; vPos.y = vSavedPos.y; transform.position = vPos; DoSolveDynamicCollisions(); } DoSolveStaticCollisions(); m_prevPos = transform.position; if (m_rigidBody != null) { m_prevVelocity = m_rigidBody.velocity; } else if (m_rigidBody2D != null) { m_prevVelocity = m_rigidBody2D.velocity; } }
void ResolveCollisions() { //fix: calling UpdateCheckPoints when Size or Center is being change through animation if (m_prevSize != m_size || m_prevCenter != m_center) { m_prevSize = m_size; m_prevCenter = m_center; UpdateCheckPoints(); } m_instantVelocity = (transform.position - m_prevPos) / Time.deltaTime; if (m_movingPlatforms.Count > 0) { Vector3 vMovingPlarformDisp = Vector3.zero; for (int i = 0; i < m_movingPlatforms.Count; ++i) { //NOTE: // - kvp.Key is the moving platform transform // - kvp.Value is the InverseTransformPoint of the Smart Collider saved during previous FixedUpdate call // This is adding the moving platform displacement, translation and scaling to the smart collider on it KeyValuePair <Transform, Vector3> kvp = m_movingPlatforms[i]; if (kvp.Key != null) { vMovingPlarformDisp += kvp.Key.TransformPoint(kvp.Value) - m_prevPos; } } vMovingPlarformDisp /= m_movingPlatforms.Count; m_movingPlatforms.Clear(); transform.position += vMovingPlarformDisp; } Vector3 movingVect = (transform.position - m_prevPos); float movementDist = movingVect.magnitude; bool checkToContinue; int maxCycles = 5; do { DynamicCollisionPoint closestCollPoint = DoSolveDynamicCollisions(); movementDist -= (transform.position - m_prevPos).magnitude; checkToContinue = (movementDist > 0.001f && closestCollPoint.distance != float.MaxValue && --maxCycles > 0); if (checkToContinue) { Vector3 surfaceDir = Vector3.Cross(closestCollPoint.normal, transform.forward); movingVect = Vector3.Project(movingVect, surfaceDir).normalized *movementDist; m_prevPos = transform.position; transform.position += movingVect; } }while (checkToContinue); DoSolveStaticCollisions(); m_prevPos = transform.position; if (m_rigidBody != null) { m_prevVelocity = m_rigidBody.velocity; } else if (m_rigidBody2D != null) { m_prevVelocity = m_rigidBody2D.velocity; } }