コード例 #1
0
        protected void DoClimbing()
        {
            float fHorAxis = 0f;
            float fVerAxis = 0f;

            if (GetActionState(eControllerActions.Right))
            {
                fHorAxis += m_horSpeedScale;
            }
            if (GetActionState(eControllerActions.Left))
            {
                fHorAxis -= m_horSpeedScale;
            }
            if (GetActionState(eControllerActions.Up))
            {
                fVerAxis += m_verSpeedScale;
            }
            if (GetActionState(eControllerActions.Down))
            {
                fVerAxis -= m_verSpeedScale;
            }
            if (m_isClimbing)
            {
                if (
                    GetIfActionHasChanged(eControllerActions.Jump) && GetActionState(eControllerActions.Jump) ||
                    GetIfActionHasChanged(eControllerActions.PlatformDropDown) && GetActionState(eControllerActions.PlatformDropDown))
                {
                    m_isClimbing = false;
                    m_currentClimbingCollider = null;
                    m_isGrounded = true;
                    return;
                }

                // isLadder is true when the collider width is small enough to avoid moving horizontal and center the player in the center of the collider.
                // By default, it is true when collider width is less than two times the smart rect collider width
                bool isLadder = m_currentClimbingCollider.bounds.size.x < m_ladderWidthFactor * m_smartCollider.Size.x;

                Vector3 vDisp = new Vector3(isLadder ? 0f : fHorAxis, fVerAxis);

                //debug climbing area
                DebugEx.DebugDrawRect(Vector2.zero, new Rect(m_currentClimbingCollider.bounds.min, m_currentClimbingCollider.bounds.size), Color.blue);


                if (isLadder)
                {
                    // Snap to ladder
                    Vector3 center  = m_currentClimbingCollider.bounds.center;
                    Vector3 snapPos = Vector3.Project(transform.position - center, m_currentClimbingCollider.transform.up); // this allow rotated ladders, like in pirate ship demo
                    snapPos           += center;
                    snapPos.z          = transform.position.z;
                    transform.position = Vector3.Lerp(transform.position, snapPos, 0.5f);
                }

                if (vDisp.magnitude > 0.2f)
                {
                    transform.position += transform.rotation * vDisp * ClimbingSpeed * Time.deltaTime;
                }

                m_isGrounded = m_smartCollider.enabled && m_smartCollider.IsGrounded();
            }

            // Check if going down and there is a climbing collider below
            float      SkinBottomWidthFactor = 1.1f; //NOTE: set a value > 1f to allow climbing down when climb collision and platform collision are close
            Collider2D climbingColliderBelow = GetClimbingColliderBelow(SkinBottomWidthFactor);
            Collider2D climbingColliderAbove = GetClimbingColliderAbove();

            if (fVerAxis < -0.5f && m_currentClimbingCollider == null)
            {
                if (climbingColliderBelow != null)
                {
                    if (m_currentClimbingCollider == null && climbingColliderAbove == null)
                    {
                        //Teleport the player. TeleportTo will skip any collider in between the current position and the new position to skip any platform in between
                        m_smartCollider.TeleportTo(transform.position - transform.up * m_smartCollider.SkinBottomWidth * SkinBottomWidthFactor);
                    }
                    m_currentClimbingCollider = climbingColliderBelow;
                    StartClimbing();
                }
                else
                {
                    StopClimbing();
                }
            }
            // Check if going up and it is inside a climbing collider
            else if (fVerAxis > 0.5f)
            {
                if (climbingColliderAbove != null && !GetIfActionHasChanged(eControllerActions.Jump))
                {
                    m_currentClimbingCollider = climbingColliderAbove;
                    StartClimbing();
                }
                else if (m_smartCollider.SkinBottomRayContacts.Contains(true) || climbingColliderBelow == null)
                {
                    StopClimbing();
                }
            }
            // Stop climbing once the top is reached
            else if (m_isGrounded || (climbingColliderBelow == null && climbingColliderAbove == null))
            {
                StopClimbing();
            }
        }
コード例 #2
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);
        }