void ClearRaysCollisionInfo(CharacterRay2D[] rays)
 {
     for (int i = 0; i < rays.Length; i++)
     {
         CharacterRay2D curRay = rays[i];
         curRay.m_collider = null;
     }
 }
    void LaunchCallbacks(CharacterRay2D[] rays, RayType rayType)
    {
        m_curHits.Clear();
        for (int i = 0; i < rays.Length; i++)
        {
            CharacterRay2D curRay = rays[i];

            // do not send message twice for same collider & same raytype
            if (curRay.m_collider != null && !m_curHits.Contains(curRay.m_collider))
            {
                m_curHits.Add(curRay.m_collider);
                APHitable hitable = curRay.m_collider.GetComponent <APHitable>();
                if (hitable)
                {
                    hitable.OnCharacterTouch(m_character, rayType);
                }
            }
        }
    }
    bool MoveHorizontal(ref Vector2 moveOffset, bool bFront, bool bCorrectPos)
    {
        bool  bPenetrated     = false;
        float fMinPenetration = 0f;
        float fMaxAllowedMove = Mathf.Abs(moveOffset.x);

        bool    bRayDirRight = (m_faceRight && bFront) || (!m_faceRight && !bFront);
        bool    bCorrectVel  = (moveOffset.x > 0f && bRayDirRight) || (moveOffset.x < 0f && !bRayDirRight);
        Vector2 rayDir       = bRayDirRight ? Vector2.right : -Vector2.right;

        Vector2 v2SavedPos = transform.position;

        transform.position = m_curPos;

        // Launch ground cast from destination position
        CharacterRay2D[] rays = bFront ? m_RaysFront : m_RaysBack;
        for (int i = 0; i < rays.Length; i++)
        {
            CharacterRay2D curRay        = rays[i];
            float          fRayPen       = curRay.m_penetration * Mathf.Abs(transform.lossyScale.x) * m_scale.x;
            float          fCurRayLength = fRayPen + curRay.m_extraDistance;

            // add move offset if needed
            if (bCorrectVel)
            {
                fCurRayLength += Mathf.Abs(moveOffset.x);
            }

            // launch ray
            Vector2 rayOrigin = transform.TransformPoint(Vector2.Scale(curRay.m_position, m_scale) + m_offset);

            if (m_DrawRays)
            {
                Debug.DrawLine(rayOrigin, rayOrigin + rayDir * fCurRayLength);
            }

            int hitCount = Physics2D.RaycastNonAlloc(rayOrigin, rayDir, m_rayResults, fCurRayLength, m_rayLayer);
            if (hitCount > 0)
            {
                float fClosestHit = float.MaxValue;
                for (int hitId = 0; hitId < hitCount; hitId++)
                {
                    RaycastHit2D hit = m_rayResults[hitId];

                    // ignore insides
                    if (hit.fraction == 0f)
                    {
                        continue;
                    }

                    // ignore character himself
                    if (hit.rigidbody == rigidbody2D)
                    {
                        continue;
                    }

                    // ignore triggers
                    if (hit.collider.isTrigger)
                    {
                        continue;
                    }

                    // ignore non facing normals or in invalid slope range
                    if ((bRayDirRight && hit.normal.x > 0f) || (!bRayDirRight && hit.normal.x < 0f))
                    {
                        continue;
                    }

                    if (m_DrawRays)
                    {
                        Debug.DrawLine(hit.point, hit.point + hit.normal * 0.1f, Color.red);
                    }

                    // if we are in skin width
                    float fHitLength = hit.fraction * fCurRayLength;
                    if (fHitLength <= fRayPen + curRay.m_extraDistance)
                    {
                        if (bFront)
                        {
                            m_touchFront = true;
                        }
                        else
                        {
                            m_touchBack = true;
                        }

                        // keep hit with maximum penetration (allow small penetration to prevent djitering)
                        float fPen = fHitLength - fRayPen;
                        if ((fPen + m_allowedPenetration) < fMinPenetration)
                        {
                            bPenetrated     = true;
                            fMinPenetration = fPen;
                        }

                        // save collider of closest hit in skin width
                        if (hit.fraction < fClosestHit)
                        {
                            fClosestHit       = hit.fraction;
                            curRay.m_collider = hit.collider;
                        }
                    }

                    // Compute velocity correction
                    if (bCorrectVel)
                    {
                        fMaxAllowedMove = Mathf.Min(fMaxAllowedMove, fHitLength - fRayPen);
                        fMaxAllowedMove = Mathf.Max(0f, fMaxAllowedMove);                         // cannot be negative
                    }
                }
            }
        }

        // correction by velocity
        if (bCorrectVel)
        {
            moveOffset.x = bRayDirRight ? fMaxAllowedMove : -fMaxAllowedMove;

            // integrate this move
            m_curPos.x += moveOffset.x;
        }

        // correction by position
        if (bPenetrated && bCorrectPos)
        {
            Vector2 v2PosErr = Mathf.Max(fMinPenetration, -m_PosErrorMaxVel * Time.deltaTime) * rayDir;
            m_curPos += v2PosErr;

            // keep this value
            m_posError += v2PosErr;
        }

        transform.position = v2SavedPos;
        return(bPenetrated);
    }
    bool MoveVertical(ref Vector2 moveOffset, bool bDown, bool bCorrectPos)
    {
        bool  bPenetrated     = false;
        float fMinPenetration = 0f;
        float fMaxAllowedMove = Mathf.Abs(moveOffset.y);
        bool  bCorrectVel     = (bDown && moveOffset.y < 0f) || (!bDown && moveOffset.y > 0f);

        Vector2 rayDir            = bDown ? -Vector2.up : Vector2.up;
        float   fClosestGroundHit = float.MaxValue;
        Vector2 v2SavedPos        = transform.position;

        transform.position = m_curPos;

        if (bDown)
        {
            m_touchGround = false;
        }

        // Launch ground cast from destination position
        CharacterRay2D[] rays = bDown ? m_RaysGround : m_RaysUp;
        for (int i = 0; i < rays.Length; i++)
        {
            CharacterRay2D curRay        = rays[i];
            float          fRayPen       = curRay.m_penetration * Mathf.Abs(transform.lossyScale.y) * m_scale.y;
            float          fCurRayLength = fRayPen + curRay.m_extraDistance;

            // add move offset in raycast if needed
            if (bCorrectVel)
            {
                fCurRayLength += Mathf.Abs(moveOffset.y);
            }

            // launch ray
            Vector2 rayOrigin = transform.TransformPoint(Vector2.Scale(curRay.m_position, m_scale) + m_offset);

            if (m_DrawRays)
            {
                Debug.DrawLine(rayOrigin, rayOrigin + rayDir * fCurRayLength);
            }

            int hitCount = Physics2D.RaycastNonAlloc(rayOrigin, rayDir, m_rayResults, fCurRayLength, m_rayLayer);
            if (hitCount > 0)
            {
                float fClosestHit = float.MaxValue;
                for (int hitId = 0; hitId < hitCount; hitId++)
                {
                    RaycastHit2D hit = m_rayResults[hitId];

                    // ignore insides
                    if (hit.fraction == 0f)
                    {
                        continue;
                    }

                    // ignore character himself
                    if (hit.rigidbody == rigidbody2D)
                    {
                        continue;
                    }

                    // ignore triggers
                    if (hit.collider.isTrigger)
                    {
                        continue;
                    }

                    // ignore non opposite normals
                    if ((bDown && hit.normal.y <= 0f) || (!bDown && hit.normal.y >= 0f))
                    {
                        continue;
                    }

                    if (m_DrawRays)
                    {
                        Debug.DrawLine(hit.point, hit.point + hit.normal * 0.1f, Color.red);
                    }

                    // keep hit with maximum penetration
                    float fHitLength = hit.fraction * fCurRayLength;
                    float fPen       = fHitLength - fRayPen;
                    if ((fPen + m_allowedPenetration) < fMinPenetration)
                    {
                        bPenetrated     = true;
                        fMinPenetration = fPen;
                    }

                    // Compute velocity correction
                    if (bCorrectVel)
                    {
                        fMaxAllowedMove = Mathf.Min(fMaxAllowedMove, fHitLength - fRayPen);
                        fMaxAllowedMove = Mathf.Max(0f, fMaxAllowedMove);                         // cannot be negative
                    }

                    // we are in skin width
                    if (bDown)
                    {
                        m_touchGround = true;

                        // keep normal of closest hit for all rays
                        float fDistToGround = fHitLength - fRayPen;
                        if (fDistToGround < fClosestGroundHit)
                        {
                            fClosestGroundHit = fDistToGround;
                            m_groundNormal    = hit.normal;
                            m_distToGround    = fDistToGround;
                        }
                    }
                    else
                    {
                        m_touchHead = true;
                    }

                    // save collider of closest hit for this ray
                    if (hit.fraction < fClosestHit)
                    {
                        fClosestHit       = hit.fraction;
                        curRay.m_collider = hit.collider;
                    }
                }
            }
        }

        float fPrevPosY = m_curPos.y;

        // correction by velocity
        if (bCorrectVel)
        {
            moveOffset.y = bDown ? -fMaxAllowedMove : fMaxAllowedMove;

            // integrate
            m_curPos.y += moveOffset.y;
        }

        // correction by position
        if (bPenetrated && bCorrectPos)
        {
            Vector2 v2PosErr = Mathf.Max(fMinPenetration, -m_PosErrorMaxVel * Time.deltaTime) * rayDir;
            m_curPos += v2PosErr;

            // keep this value so it is removed from velocity computing later
            m_posError += v2PosErr;
        }

        // fix distance to ground
        if (bDown && m_touchGround)
        {
            m_distToGround += (m_curPos.y - fPrevPosY);
        }

        transform.position = v2SavedPos;
        return(bPenetrated);
    }
Exemple #5
0
    public Vector2 GetRayPositionWs(CharacterRay2D ray)
    {
        Vector2 rayOrigin = transform.TransformPoint(Vector2.Scale(ray.m_position - m_scaleOffset, m_scale) + m_scaleOffset);

        return(rayOrigin);
    }