private void _OnSideCollision(SmartCollision2D collision, GameObject collidedObject) { // check for horizontal collision to reset walking velocity Vector3 vLocImpulse = transform.rotation != Quaternion.identity ? Quaternion.Inverse(transform.rotation) * collision.impulse : collision.impulse; if (vLocImpulse.x <= -Vector3.kEpsilon && m_walkVeloc.x >= Vector3.kEpsilon || vLocImpulse.x >= Vector3.kEpsilon && m_walkVeloc.x <= -Vector3.kEpsilon) { float dot = Vector3.Dot(collision.contacts[0].normal, transform.up); //Debug.Log("Dot: " + dot + " Angle: " + Mathf.Acos(dot) * Mathf.Rad2Deg ); if (dot <= SmartRectCollider2D.k_OneSideSlopeNormThreshold) { m_walkVeloc = Vector3.zero; if (State == eState.Walking) { SetNextState(eState.Idle); } } } // check for bottom side collision and if this object was going up, restore the transform.position back to previous position // This means, the bottom collisions are only taking into account if moving down, not moving up if (vLocImpulse.y > Vector3.kEpsilon && // if bottom collision (m_jumpSpeed + Vector3.Project(m_rigidBody2D.velocity, transform.up).y) > m_smartRectCollider.SkinBottomWidth / Time.deltaTime) // if moving up fast enough { transform.position -= Vector3.Project(vLocImpulse, transform.up); } if (vLocImpulse.y < -Vector3.kEpsilon) // if top collision { m_jumpSpeed = 0f; // reset jump velocity } }
private void OnSideCollision(SmartCollision2D collision, GameObject collidedObject) { if (collision.impulse.y > 0 && m_smartCollider.IsGrounded()) { m_slopeAngle = Vector2.Angle(collision.contacts[0].normal, Vector2.right) - 90f; } else { m_slopeAngle = 0; } Vector3 velocity = m_platformPhysics.Velocity; // Reset vertical speed on opposite vertical collision if (collision.impulse.y > 0f && velocity.y < 0f || collision.impulse.y < 0f && velocity.y > 0f) { velocity.y = 0f; } // Reset horizontal speed on opposite horizontal collision if (collision.impulse.x > 0f && velocity.x < 0f || collision.impulse.x < 0f && velocity.x > 0f) { velocity.x = 0f; } m_platformPhysics.Velocity = velocity; }
protected Vector3 _DoSolveStaticCollisionSide(IList <Vector3> vCheckPoints, IList <bool> vRayContacts, Vector3 vSkin, Vector3 vOffset, LayerMask layerMask, LayerMask movingPlatformLayerMask) { float collClosestDist = float.MaxValue; float skinMagnitude = vSkin.magnitude; Vector3 vClosestHitNorm = Vector3.zero; Vector3 vClosestHit = Vector3.zero; GameObject collidedObject = null; Vector3 vAppliedForce = Vector3.Project(m_instantVelocity, vSkin) / vCheckPoints.Count; float fOffsetDist = Vector3.Scale(vOffset, transform.localScale).magnitude; LayerMask oneWayLayerMask = (OneWayCollisionDown | OneWayCollisionUp | OneWayCollisionLeft | OneWayCollisionRight); for (int i = 0; i < vCheckPoints.Count; ++i) { vRayContacts[i] = false; Vector3 vCheckPos = vCheckPoints[i]; Ray ray = new Ray(transform.TransformPoint(vCheckPos + vOffset), vSkin); Debug.DrawRay(ray.origin, vSkin.normalized * (skinMagnitude + fOffsetDist), Color.magenta); // 3D if (EnableCollision3D) { RaycastHit hitInfo = _GetClosestHitInfo(ray.origin, ray.direction, skinMagnitude + fOffsetDist, layerMask); if (hitInfo.collider != null && hitInfo.collider.gameObject != gameObject) { if (hitInfo.collider.isTrigger) { hitInfo.collider.gameObject.SendMessageUpwards(k_messageOnSmartTriggerStay2D, new SmartContactPoint(hitInfo.normal, this, hitInfo.point), SendMessageOptions.DontRequireReceiver); } else { vRayContacts[i] = true; DebugEx.DebugDrawDot(hitInfo.point + new Vector3(0, 0, -0.1f), 0.01f, Color.red); if ((movingPlatformLayerMask & (1 << hitInfo.collider.gameObject.layer)) != 0) { m_movingPlatforms.Add(new KeyValuePair <Transform, Vector3>(hitInfo.transform, Vector3.zero)); //NOTE: the kvp.Value will be set at the end of DoSolveStaticCollisions } // This is pushing the collided object if it has a rigid body attached if (hitInfo.rigidbody != null) { hitInfo.rigidbody.AddForceAtPosition(vAppliedForce, hitInfo.point, ForceMode.Force); } if (hitInfo.distance < collClosestDist && // avoid collision when slope is higher than threshold and collider object is one way ((0 == ((1 << hitInfo.collider.gameObject.layer) & oneWayLayerMask)) || Vector3.Dot(hitInfo.normal, -vSkin.normalized) >= k_OneSideSlopeNormThreshold) ) { collClosestDist = hitInfo.distance; vClosestHit = hitInfo.point; vClosestHitNorm = hitInfo.normal; collidedObject = hitInfo.collider.gameObject; } } } } // 2D if (EnableCollision2D) { RaycastHit2D hitInfo2D = _GetClosestHitInfo2D(ray.origin, ray.direction, skinMagnitude + fOffsetDist, layerMask, true); if (hitInfo2D.collider != null && hitInfo2D.collider.gameObject != gameObject) { if (hitInfo2D.collider.isTrigger) { hitInfo2D.collider.gameObject.SendMessageUpwards(k_messageOnSmartTriggerStay2D, new SmartContactPoint(hitInfo2D.normal, this, hitInfo2D.point), SendMessageOptions.DontRequireReceiver); } else { vRayContacts[i] = true; DebugEx.DebugDrawDot((Vector3)hitInfo2D.point + new Vector3(0, 0, transform.position.z - 0.1f), 0.01f, Color.red); if ((movingPlatformLayerMask & (1 << hitInfo2D.collider.gameObject.layer)) != 0) { m_movingPlatforms.Add(new KeyValuePair <Transform, Vector3>(hitInfo2D.transform, Vector3.zero)); //NOTE: the kvp.Value will be set at the end of DoSolveStaticCollisions } // This is pushing the collided object if it has a rigid body attached if (hitInfo2D.rigidbody != null) { hitInfo2D.rigidbody.AddForceAtPosition(vAppliedForce, hitInfo2D.point, ForceMode2D.Force); } if (hitInfo2D.distance < collClosestDist && // avoid collision when slope is higher than threshold and collider object is one way ((0 == ((1 << hitInfo2D.collider.gameObject.layer) & oneWayLayerMask)) || Vector3.Dot(hitInfo2D.normal, -vSkin.normalized) >= k_OneSideSlopeNormThreshold) ) { collClosestDist = hitInfo2D.distance; vClosestHit = hitInfo2D.point; vClosestHitNorm = hitInfo2D.normal; collidedObject = hitInfo2D.collider.gameObject; } } } } } // check if there was a collision if (collClosestDist < float.MaxValue) { //Debug.DrawRay(vClosestHit, vClosestHitNorm * 0.1f, Color.yellow, 0.5f); float fImpulseDist = (skinMagnitude + fOffsetDist) - collClosestDist + k_colliderSeparation; Vector3 vImpulse = -vSkin.normalized * fImpulseDist; //TODO: Add smooth factor by multiplying vImpulse by this factor ( make climb steps smoother ) // TODO: if this is slow because of the gravity, a collision is going to be made each fixedUpdate, improve by keeping a list of the hit objects // so this message is only sent once until there is no collision for one update and then call the OnSmartCollisionExit2D SmartCollision2D smartCollision2D = new SmartCollision2D( this, new SmartContactPoint[] { new SmartContactPoint(vClosestHitNorm, this, vClosestHit) }, gameObject, vImpulse, m_instantVelocity, transform, m_rigidBody, m_rigidBody2D); collidedObject.SendMessageUpwards(k_messageOnSmartCollisionStay2D, smartCollision2D, SendMessageOptions.DontRequireReceiver); if (OnSideCollision != null) { OnSideCollision(smartCollision2D, collidedObject); } return(vImpulse); } return(Vector3.zero); }