/// <summary> /// Move the character without going through things /// </summary> /// <param name="movement">offset to move the character</param> void CharacterMove(Vector3 movement) { Vector3 nTotal = Vector3.zero; // reset all collision flags Collisions = CC_Collision.None; Vector3 movNormalized = movement.normalized; float distance = movement.magnitude; #if STAIRS StepDelta = Mathf.Clamp(StepDelta - Time.fixedDeltaTime * 1.5f, 0, Mathf.Infinity); if (IsGrounded && !CPMSettings.FlyingCharacter) { MoveOnSteps1(movNormalized); } #endif //const float minimumStepDistance = 0.1f; // Greater than 0 to prevent infinite loop //float stepDistance = Math.Min((ownCollider as CapsuleCollider).radius, minimumStepDistance); float stepDistance = 0.05f; Vector3 nResult; if (distance > 0) { for (float curDist = 0; curDist < distance; curDist += stepDistance) { float curMagnitude = Math.Min(stepDistance, distance - curDist); Vector3 start = transform.position; Vector3 end = start + movNormalized * curMagnitude; transform.position = FixOverlaps(end, movNormalized * curMagnitude, out nResult); nTotal += nResult; } } else { // when character doesn't move transform.position = FixOverlaps(transform.position, Vector3.zero, out nResult); nTotal += nResult; } // handles collision OnCCHit(nTotal.normalized); }
/// <summary> /// Move the transform trying to stop being overlaping other colliders /// </summary> /// <param name="position">start position. Bottom of the collider</param> /// <returns>Final position</returns> Vector3 FixOverlaps(Vector3 position, Vector3 offset, out Vector3 nResult) { Vector3 nTemp = Vector3.zero; // what if you sum all the penetration directions to give the final result // and with each collision, add a CollisionFlag accordingly with the axis collided? CapsuleCollider coll = ownCollider as CapsuleCollider; //Vector3 p = position - (position - coll.transform.position) + (coll.bounds.center - new Vector3(0, coll.bounds.extents.y, 0)); //int nColls = Physics.OverlapCapsuleNonAlloc(p, new Vector3(p.x, p.y + coll.height, p.z), coll.radius, overlapingColliders, GroundLayer, QueryTriggerInteraction.Ignore); // when dead, collide onlly with the world LayerMask overlapMask; if (IsAlive) { overlapMask = m_SolidLayer | m_EnemyLayer; } else { overlapMask = m_SolidLayer; } int nColls = PhysicsExtensions.OverlapCapsuleNonAlloc(coll, offset, overlapingColliders, overlapMask, QueryTriggerInteraction.Ignore); for (int i = 0; i < nColls; i++) { Collider c = overlapingColliders[i]; if (c == ownCollider) { continue; // ignore itself } Vector3 normal; float dist; float dot; if (Physics.ComputePenetration(ownCollider, position, transform.rotation, c, c.transform.position, c.transform.rotation, out normal, out dist)) { // TODO: report bug if (float.IsNaN(normal.x) || float.IsNaN(normal.y) || float.IsNaN(normal.y)) { continue; } // depenetration value for preventing doors // from overlapping with player when it shouldn't dist += Depenetration; dot = Vector3.Dot(normal, Vector3.up); if (dot > m_Settings.SlopeLimit && dot <= 1) { Collisions = Collisions | CC_Collision.CollisionBelow; position += normal * dist; State &= ~CC_State.OnPlatform; } if (dot >= 0 && dot < m_Settings.SlopeLimit) { Collisions = Collisions | CC_Collision.CollisionSides; } if (dot < 0) { Collisions = Collisions | CC_Collision.CollisionAbove; } nTemp += normal; } } nResult = nTemp; return(position); }
/// <summary> /// Move the character without going through things /// </summary> /// <param name="movement">offset to move the character</param> void CharacterMove(Vector3 movement) { Vector3 nTotal = Vector3.zero; // reset all collision flags Collisions = CC_Collision.None; Vector3 totalMovNorm = movement.normalized; float distance = movement.magnitude; #if STAIRS StepDelta = Mathf.Clamp(StepDelta - Time.fixedDeltaTime * 1.5f, 0, Mathf.Infinity); if (IsGrounded && !CPMSettings.FlyingCharacter) { MoveOnSteps1(movNormalized); } #endif //const float minimumStepDistance = 0.1f; // Greater than 0 to prevent infinite loop //float stepDistance = Math.Min((ownCollider as CapsuleCollider).radius, minimumStepDistance); float stepDistance = 0.05f; int nHits = 0; for (int i = 0; i < 3; i++) { Vector3 movNormalized = Vector3.zero; switch (i) { case 0: movNormalized = Vector3.right; break; case 1: movNormalized = Vector3.up; break; case 2: movNormalized = Vector3.forward; break; } movNormalized *= totalMovNorm[i]; Vector3 normal; if (distance > 0) { for (float curDist = 0; curDist < distance; curDist += stepDistance) { float curMagnitude = Mathf.Min(stepDistance, distance - curDist); Vector3 start = transform.position; Vector3 end = start + movNormalized * curMagnitude; transform.position = FixOverlaps(end, movNormalized * curMagnitude, out normal); if (nHits < hitNormals.Length) { hitNormals[nHits] = normal; nHits++; } } } else { // when character doesn't move transform.position = FixOverlaps(transform.position, Vector3.zero, out normal); if (nHits < hitNormals.Length) { hitNormals[nHits] = normal; nHits++; } } } Vector3 resultNormal = Vector3.zero; for (int n = 0; n < nHits; n++) { // handles collision OnCCHit(hitNormals[n]); resultNormal += hitNormals[n]; } // align with planes var copyVelocity = Velocity; var newDir = Vector3.ProjectOnPlane(copyVelocity.normalized, resultNormal.normalized); Velocity = (newDir * copyVelocity.magnitude); //FloorAlign(); }
//Vector2 GetKeyInput() //{ // WalkForward = (InputManager.GetButton("Forward") ? 1 : 0) - (InputManager.GetButton("Backwards") ? 1 : 0); // Strafe = (InputManager.GetButton("Strafe_Right") ? 1 : 0) - (InputManager.GetButton("Strafe_Left") ? 1 : 0); // SwimUp = InputManager.GetAxisRaw("SwimUp"); // JumpInput = InputManager.GetButtonDown("Jump"); // if (JumpInput && triedJumping == 0) // triedJumping = jumpInputWindow; // return new Vector2(Strafe, WalkForward); //} /// <summary> Check if the player view is under water layer </summary> private bool HasCollisionFlag(CC_Collision flag) { return((Collisions & flag) != 0); }
void MoveOnSteps1(Vector3 movNormalized) { Vector3 p0, p1; // capsule point 0 and 1 float radius; // capsule radius // ignore gravity pull stepDir = movNormalized; stepDir.y = 0; stepDist = stepDir.magnitude; // for debug purposes ownCollider.ToWorldSpaceCapsule(out p0, out p1, out radius); p0 += (stepDir * stepDist) + (Vector3.up * CPMSettings.StepOffset); p1 += (stepDir * stepDist) + (Vector3.up * CPMSettings.StepOffset); if (stepDist <= Mathf.Epsilon) { return; } // check if collides in the next step if (Physics.CheckCapsule(p0, p1, radius, m_SolidLayer, QueryTriggerInteraction.Ignore)) { // collided with a solid object, probably a wall return; // doesn't do anything } else { // didn't found a collision, so there is a step // try to find the step point stepCenter = ((p0 + p1) / 2) + stepDir * radius; Vector3 size = new Vector3(ownCollider.radius * 2, ownCollider.height, ownCollider.radius * 2); //if (Physics.Raycast(stepCenter, Vector3.down, out stepHit, Mathf.Infinity, Game.Settings.SOLID_LAYER, QueryTriggerInteraction.Ignore)) //{ // var bottom = ownCollider.center + transform.position + (Vector3.down * ownCollider.height / 2); // var dot = Vector3.Dot(stepHit.normal, Vector3.up); // if (stepHit.point.y > bottom.y && dot > 0.95f) // { // float upDist = Mathf.Abs(stepHit.point.y - bottom.y); // transform.position += Vector3.up * upDist; //raise the player on the step size // } //} if (Physics.CapsuleCast(p0 + stepDir * radius, p1 + stepDir * radius, radius, Vector3.down, out stepHit, Mathf.Infinity, m_SolidLayer, QueryTriggerInteraction.Ignore)) { var bottom = ownCollider.center + transform.position + (Vector3.down * ownCollider.height / 2); if (Physics.Raycast(stepHit.point + Vector3.up * CPMSettings.StepOffset, Vector3.down, out cornerHit, Mathf.Infinity, m_SolidLayer, QueryTriggerInteraction.Ignore)) { var dot = Vector3.Dot(cornerHit.normal, Vector3.up); if (stepHit.point.y > bottom.y && dot >= 0.98999999f) { float upDist = Mathf.Abs(stepHit.point.y - bottom.y); transform.position += Vector3.up * upDist; //raise the player on the step size if (upDist > StepDelta) { StepDelta = upDist; } Collisions |= CC_Collision.CollisionBelow; } } } } }
public void RemoveCollision(CC_Collision collision) { Collisions &= ~collision; }
public void AddCollision(CC_Collision collision) { Collisions |= collision; }
public bool HasCollision(CC_Collision collision) { return((Collisions & collision) != 0); }
public bool HasCollisionFlag(CC_Collision flag) { return(HasCollision(flag)); //return (Collisions & flag) != 0; }