Ejemplo n.º 1
0
        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;
        }
Ejemplo n.º 3
0
        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);
        }