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); }
public Vector2 GetRayPositionWs(CharacterRay2D ray) { Vector2 rayOrigin = transform.TransformPoint(Vector2.Scale(ray.m_position - m_scaleOffset, m_scale) + m_scaleOffset); return(rayOrigin); }