protected void MoveInYDirection (bool grounded) { float slope = 0.0f; int slopeCount = -1; bool isClimbing = false; bool cantClimbDown = false; bool hasHitHead = false; int climbCount = 0; groundedFeet = 0; isClimbingUpOrDown = false; // Create a copy of character input which we can modify; float characterInputY = characterInput.y; // Ignore input if stunned if (stunTimer > 0.0f) characterInputY = 0.0f; // Limit Velocity if (velocity.y < (movement.terminalVelocity * (IsSwimming ? (1 - swimming.waterResistance.y) : 1))) velocity.y = movement.terminalVelocity * (IsSwimming ? (1 - swimming.waterResistance.y) : 1); if (IsSwimming && velocity.y > swimming.maxYSpeed) velocity.y = swimming.maxYSpeed; // Apply velocity if ((myParent == null || !myParent.overrideY) && (velocity.y > movement.skinSize || velocity.y * -1 > movement.skinSize)) { myTransform.Translate (0.0f, velocity.y * frameTime, 0.0f, Space.World); } if (fallThroughTimer > 0.0f) fallThroughTimer -= frameTime; // Fall/Stop bool hasHitFeet = false; if ((velocity.y <= 0.0f || startedClimbing) && ledgeDropTimer <= 0.0f) { float maxForce = 0.0f; GameObject hitGameObject = null; float lastHitDistance = -1; float lastHitX = 0.0f; foreach (RaycastCollider2D feetCollider in feetColliders) { RaycastHit2D hitFeet = new RaycastHit2D (); RaycastHit2D hitLadder = new RaycastHit2D (); RaycastHit2D hitGround = new RaycastHit2D (); float closest = float.MaxValue; float closestLadder = float.MaxValue; RaycastHit2D[] feetCollisions = feetCollider.GetAllCollision (1 << backgroundLayer | (fallThroughTimer <= 0.0f ? 1 << passThroughLayer : 0) | (climbing.allowClimbing && fallThroughTimer <= 0.0f ? 1 << climableLayer : 0), slopes.slopeLookAhead); // Get closest collision foreach (RaycastHit2D collision in feetCollisions) { // If we got a ladder also keep reference to ground if (collision.collider != null && collision.collider.gameObject.layer == climableLayer) { if (collision.fraction * (feetCollider.distance + slopes.slopeLookAhead) < closestLadder) { hitLadder = collision; closestLadder = collision.fraction * (feetCollider.distance + slopes.slopeLookAhead); } } else if (collision.fraction * (feetCollider.distance + slopes.slopeLookAhead) < closest) { hitFeet = collision; closest = collision.fraction * (feetCollider.distance + slopes.slopeLookAhead); } if (collision.collider.gameObject.layer != climableLayer) groundedFeet++; } // If ladder is closest collider if (hitLadder.collider != null && hitFeet.collider != null && hitLadder.fraction * (feetCollider.distance + slopes.slopeLookAhead) < closest) { // Only assign ground if its a true hit, not a slope look ahead hit if (hitFeet.fraction * (feetCollider.distance + slopes.slopeLookAhead) <= feetCollider.distance && hitFeet.collider.gameObject.layer != climableLayer) { hitGround = hitFeet; hasHitFeet = true; } hitFeet = hitLadder; } // If only hitting a ladder if (hitLadder.collider != null && hitFeet.collider == null) { hitFeet = hitLadder; } float force = (hitFeet.normal * (feetCollider.distance - (hitFeet.fraction * (feetCollider.distance + slopes.slopeLookAhead)))).y; // Standing on a something that has an action when you stand on it if (hitFeet.collider != null) { Platform2D platform = hitFeet.collider.gameObject.GetComponent<Platform2D> (); if (platform != null && feetCollider.distance >= hitFeet.fraction * (feetCollider.distance + slopes.slopeLookAhead)) { platform.DoAction (feetCollider, this); Transform parentPlatform = platform.ParentOnStand (this); if (parentPlatform != null) { // Normal parenting (moving platforms etc) myParent = platform; if (myTransform.parent != parentPlatform) { myTransform.parent = parentPlatform; } hitGameObject = hitFeet.collider.gameObject; } // Special case for the top of a ladder if (platform is TopStepPlatform2D) { hasHitFeet = true; maxForce = force; hitGameObject = hitLadder.collider.gameObject; } } // Climbing if (climbing.allowClimbing && hitLadder.collider != null && hitLadder.fraction * (feetCollider.distance + slopes.slopeLookAhead) <= feetCollider.distance && jumpButtonTimer <= 0.0f) { //bool ladder = hitLadder.collider.gameObject.GetComponent<Ladder>(); //if (ladder == null) hitLadder.collider.gameObject.GetComponent<Rope>(); // && ladder != null climbCount++; if (!(myParent is TopStepPlatform2D) && (startedClimbing || (climbing.autoStick && hitGround.collider == null && (dismounting == null || (myParent != null && dismounting != ((Ladder2D)myParent).control)) || characterInputY != 0))) { if (climbCount >= climbing.collidersRequired) { startedClimbing = true; isClimbing = true; hasHitFeet = true; dismounting = null; // Allow platforms to stop us climbing if (myParent == null || !myParent.overrideY) { if (characterInputY > 0.0f) { // Ensure we dont go above step maxForce = climbing.speed * frameTime; if (maxForce > force) maxForce = force; isClimbingUpOrDown = true; } else if (!cantClimbDown && characterInputY < 0.0f) { maxForce = climbing.speed * frameTime * -1; // Ensure we don't go into ground isClimbingUpOrDown = true; if (hitGround.collider != null) { float groundForce = (hitGround.normal * (feetCollider.distance - hitGround.fraction * (feetCollider.distance + slopes.slopeLookAhead))).y; if (maxForce < groundForce) maxForce = groundForce; isClimbingUpOrDown = false; startedClimbing = false; } } } } } } else { // Calculate slope if (slopes.allowSlopes && hitFeet.collider.gameObject.layer != climableLayer) { if (lastHitDistance < 0.0f) { lastHitDistance = hitFeet.fraction * (feetCollider.distance + slopes.slopeLookAhead); lastHitX = feetCollider.offset.x; if (slopeCount == -1) slopeCount = 0; } else { slope += Mathf.Atan ((lastHitDistance - hitFeet.fraction * (feetCollider.distance + slopes.slopeLookAhead)) / (feetCollider.offset.x - lastHitX)) * Mathf.Rad2Deg; slopeCount++; lastHitDistance = hitFeet.fraction * (feetCollider.distance + slopes.slopeLookAhead); lastHitX = feetCollider.offset.x; } } } // If we are hitting our feet on the ground we can't climb down a ladder if (hitLadder.collider == null && characterInputY < 0.0f && hitFeet.fraction * (feetCollider.distance + slopes.slopeLookAhead) <= feetCollider.distance) { cantClimbDown = true; maxForce = 0.0f; } // Get force to apply if (force > maxForce && hitLadder.collider == null) { // We hit a blocker stop all climbing cantClimbDown = true; isClimbingUpOrDown = false; isClimbing = false; startedClimbing = false; hasHitFeet = true; maxForce = force; hitGameObject = hitFeet.collider.gameObject; } } } if (startedClimbing && climbCount < climbing.collidersRequired) { startedClimbing = false; } if (hasHitFeet) { dismounting = null; if ((myParent == null || !myParent.overrideY)) { if ((myParent is LadderCollider2D && ((LadderCollider2D)myParent).control.ShouldPlayLedgeClimb (this))) { if (characterInput.y < 0.0f && myParent is TopStepPlatform2D && climbCount >= climbing.collidersRequired && groundedFeet == 0) { isLadderTopClimbing = true; State = CharacterState.CLIMB_TOP_OF_LADDER_DOWN; ladderTopClimbState = LadderTopState.CLIMBING_DOWN; } else if (characterInput.y > 0.0f && !(myParent is TopStepPlatform2D)) { isLadderTopClimbing = true; ladderTopClimbState = LadderTopState.CLIMBING_UP; // Force position to be exactly right myTransform.position = new Vector3 (myTransform.position.x, ((LadderCollider2D)myParent).LedgeClimbHeight, myTransform.position.z); } else { myTransform.Translate (0.0f, maxForce, 0.0f, Space.World); } } else { myTransform.Translate (0.0f, maxForce, 0.0f, Space.World); } } if (velocity.y < 0.0f) velocity.y = 0.0f; if (myParent != null && hitGameObject != myParent.gameObject) { // && !(myParent is Rope)) { Unparent (); } grounded = true; fallingTime = 0.0f; } else { if (myParent == null) { ApplyGravity (); } else if (!grounded) { ApplyGravity (); if (!isWallSliding) Unparent (); startedClimbing = false; } } } else { // If we are mving through a passthrough pltform stop gravity for a little while // As long as pass through paltforms are kept thin this works quite well. bool holdOffOnGravity = false; foreach (RaycastCollider2D foot in feetColliders) { if (foot.IsColliding (1 << passThroughLayer)) { holdOffOnGravity = true; } } if (!holdOffOnGravity) ApplyGravity (); } // Force dismount if we dont have enough colliders on the ladder if (climbCount < climbing.collidersRequired && myParent is Ladder2D) { Dismount ((Ladder2D)myParent); } // Stop crouch when climbing if (isClimbing) StopCrouch (); // Apply rotation from slopes if (slopes.allowSlopes) { float actualSlope = (myTransform.localEulerAngles.z % 360.0f) + (slope / (float)slopeCount); if (slopeCount > 0 && !isClimbing && (!(actualSlope > slopes.maxRotation && actualSlope < 360.0f - slopes.maxRotation))) { myTransform.Rotate (0.0f, 0.0f, slopes.rotationSpeed * (slope / (float)slopeCount)); } else if (slopeCount == -1 || isClimbing) { myTransform.localRotation = Quaternion.RotateTowards (myTransform.localRotation, Quaternion.identity, slopes.rotationSpeed * 10.0f); } if ((actualSlope > slopes.maxRotation && actualSlope < 360.0f - slopes.maxRotation)) { myTransform.localRotation = Quaternion.Euler (0, 0, 0); } } // Hitting Head if (velocity.y > 0.0f || isClimbing || (myParent != null && myParent.velocity.y > 0.0f)) { float maxForce = 0.0f; foreach (RaycastCollider2D headCollider in headColliders) { RaycastHit2D hitHead = headCollider.GetCollision (1 << backgroundLayer); float force = (hitHead.normal * (headCollider.distance - (hitHead.fraction * headCollider.distance ))).y; if (hitHead.collider != null) { // Action on headbut Platform2D platform = hitHead.collider.gameObject.GetComponent<Platform2D> (); if (platform != null) { platform.DoAction (headCollider, this); } if (force < -1 * movement.skinSize && force < maxForce) { hasHitHead = true; maxForce = force; } } } if (hasHitHead) { jumpHeldTimer = jump.jumpHeldTime; myTransform.Translate (0.0f, maxForce, 0.0f, Space.World); if (velocity.y > 0.0f) velocity.y = 0.0f; } if (!isClimbing) { ApplyGravity (); } } // Jump if (!hasHitHead || isClimbing) { if (characterInput.jumpButtonDown) { if ((grounded || myParent != null) && jumpCount == 0 && jumpButtonTimer <= 0.0f) { // Special case when launching from a rope /* if (myParent != null && myParent is Rope) { float k = Mathf.Abs (Mathf.Cos (Mathf.Deg2Rad * myTransform.rotation.eulerAngles.z)); k = Mathf.Pow (k, ((Rope)myParent).control.jumpFlattenFactor); velocity = new Vector2 ((myParent.velocity.x + myParent.velocity.y) * ((Rope)myParent).control.ropeVelocityFactor, jump.jumpVelocity * k); jumpCount = 2; } else */ if (jump.inheritParentVelocityFactor != 0 && myParent != null) { velocity.y = jump.jumpVelocity + (myParent.velocity * jump.inheritParentVelocityFactor).y; velocity.x += (myParent.velocity * jump.inheritParentVelocityFactor).x; jumpCount = 1; } else { velocity.y = jump.jumpVelocity * (IsSwimming ? (1 - swimming.waterResistance.y) : 1); jumpCount = 1; } // Inherit parent velocity Unparent (); startedClimbing = false; jumpButtonTimer = jump.jumpTimer; jumpHeldTimer = 0.0f; StopCrouch (); State = CharacterState.JUMPING; } else if (jumpCount == 1 && jump.canDoubleJump && !IsSwimming) { Unparent (); startedClimbing = false; jumpCount++; velocity.y = jump.doubleJumpVelocity; StopCrouch (); State = CharacterState.DOUBLE_JUMPING; } } else if (characterInput.jumpButtonHeld && jumpHeldTimer < jump.jumpHeldTime && jumpCount == 1) { velocity.y += jump.jumpFrameVelocity * frameTime * (jump.jumpHeldTime - jumpHeldTimer); jumpHeldTimer += frameTime; } } // Swimming if (IsSwimming){ if (State != CharacterState.JUMPING && jumpButtonTimer <= 0 && characterInput.swimButtonDown) { // Note this also adds acceleration in X! velocity.y += swimming.swimStrokeAcceleration.y * frameTime; velocity.x += swimming.swimStrokeAcceleration.x * CurrentDirection * frameTime; jumpButtonTimer = swimming.swimStrokeTime; State = CharacterState.SWIMMING; } } if (jumpButtonTimer > 0.0f) jumpButtonTimer -= frameTime; if (jumpButtonTimer <= 0.0f && grounded) { jumpCount = 0; } // Reset held button timer if we release button if (!characterInput.jumpButtonHeld) { jumpHeldTimer = jump.jumpHeldTime; } // Wall jump if (wallJumpTimer > 0) { wallJumpTimer -= frameTime; } if (wall.canWallJump && (wall.wallJumpTag == "" || wall.wallJumpTag == currentWallTag)) { // Easy wall jump if (wall.easyWallJump) { if (characterInput.jumpButtonDown && isWallHolding) { Unparent(); startedClimbing = false; velocity.y = wall.wallJumpSpeed.y; jumpCount = 2; wallJumpTimer = 0.0f; jumpButtonTimer = jump.jumpTimer; jumpHeldTimer = 0.0f; StopCrouch(); State = CharacterState.WALL_JUMPING; if (wall.wallJumpOnlyInOppositeDirection) { oppositeDirectionTimer = wall.oppositeDirectionTime; if (wallJumpDirection == RC_Direction.LEFT) velocity.x = wall.wallJumpSpeed.x; else if (wallJumpDirection == RC_Direction.RIGHT) velocity.x = -1 * wall.wallJumpSpeed.x; } } } // "Hard" wall jump also works for easy wall jump if (wallJumpTimer > 0.0f) { if ((hasPressedJumpForWallJump && ((wallJumpDirection == RC_Direction.LEFT && characterInput.x > 0) || (wallJumpDirection == RC_Direction.RIGHT && characterInput.x < 0))) || (hasPressedDirectionForWallJump && characterInput.jumpButtonDown)) { Unparent(); startedClimbing = false; velocity.y = wall.wallJumpSpeed.y; jumpCount = 2; wallJumpTimer = 0.0f; jumpButtonTimer = jump.jumpTimer; jumpHeldTimer = 0.0f; StopCrouch(); State = CharacterState.WALL_JUMPING; if (wall.wallJumpOnlyInOppositeDirection) { oppositeDirectionTimer = wall.oppositeDirectionTime; if (wallJumpDirection == RC_Direction.LEFT) velocity.x = wall.wallJumpSpeed.x; else if (wallJumpDirection == RC_Direction.RIGHT) velocity.x = -1 * wall.wallJumpSpeed.x; } } else if (!hasPressedJumpForWallJump && characterInput.jumpButtonDown ) { hasPressedJumpForWallJump = true; } else if (!hasPressedDirectionForWallJump && ((wallJumpDirection == RC_Direction.LEFT && characterInput.x > 0) || (wallJumpDirection == RC_Direction.RIGHT && characterInput.x < 0))) { hasPressedDirectionForWallJump = true; } } else { hasPressedJumpForWallJump = false; hasPressedDirectionForWallJump = false; } } if (myParent != null && myParent.overrideAnimation) { State = myParent.GetAnimationState(this); } else { // Animations if ((!IsGrounded (groundedLookAhead, false) && !hasHitFeet) || jumpButtonTimer > 0.0f) { State = CharacterState.AIRBORNE; } if (velocity.y < jump.fallVelocity) { State = CharacterState.FALLING; } if (startedClimbing){ if (isClimbingUpOrDown) { State = CharacterState.CLIMBING; } else { State = CharacterState.HOLDING; } } } }
/// <summary> /// Force the character to unparent from the given object. /// </summary> /// <returns>true if the object was parented to the supplied platform and then successfully unparented.</returns> /// <param name="platform">The platform to unparent from.</param> public bool Unparent (Platform2D platform) { if (myParent == platform) { myParent = null; myTransform.parent = null; return true; } return false; }
protected void MoveInXDirection (bool grounded) { // Create a copy of character input which we can modify; float characterInputX = characterInput.x; // Ignore input if stunned if (stunTimer > 0.0f) characterInputX = 0.0f; // Ignore input if crouching if (isCrouching) characterInputX = 0.0f; // Calculate Velocity float actualDrag = 1 - (currentDrag * frameTime); // Jump Drag if (jumpCount > 0 || !grounded) { actualDrag = 1 - (jump.drag * frameTime); } // Crouch slide drag if (isCrouchSliding) { actualDrag = 1 - (crouchSlideDrag * frameTime); } if (actualDrag < 0) actualDrag = 0; // Timer which ignores character input while jumping away from a wall if (wall.canWallJump && oppositeDirectionTimer > 0.0f) { oppositeDirectionTimer -= frameTime; if (wallJumpDirection == RC_Direction.RIGHT) characterInputX = -0.5f; else if (wallJumpDirection == RC_Direction.LEFT) characterInputX = 0.5f; } if (characterInputX != 0 && (myParent == null || !myParent.overrideX) && (!grounded || !IsSwimming || swimming.canRun)) { bool walking = false; if (jumpCount > 0 || !grounded || (characterInputX > 0 && characterInputX < 1.0f) || (characterInputX < 0 && characterInputX > -1.0f)) walking = true; if (movement.movementStyle != MovementStyle.PHYSICS_LIKE && movement.jumpAtRunSpeed && (jumpCount > 0 || !grounded)) walking = false; // TODO Move these behaviours to different functions (can wait till 2.0 upgrade?) switch (movement.movementStyle) { case MovementStyle.PHYSICS_LIKE: float newVelocity = velocity.x + (frameTime * movement.acceleration * characterInputX) * (IsSwimming ? (1 - swimming.waterResistance.x) : 1); // Climbing sideways if (climbing.allowClimbing && startedClimbing) { velocity.x = newVelocity; if (velocity.x > climbing.horizontalSpeed) velocity.x = climbing.horizontalSpeed; if (velocity.x < -1 * climbing.horizontalSpeed) velocity.x = -1 * climbing.horizontalSpeed; } else if (walking) { // If going too fast just apply drag (don't just limit to walk speed else you may get odd jerks) if (velocity.x > movement.walkSpeed && characterInputX >= 0.0f || velocity.x < movement.walkSpeed * -1 && characterInputX <= 0.0f) { velocity.x = velocity.x * actualDrag; // If we went too far go back to walk speed if (velocity.x < movement.walkSpeed && characterInputX >= 0.0f) { velocity.x = movement.walkSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1); } else if (velocity.x > movement.walkSpeed * -1 && characterInputX <= 0.0f) { velocity.x = movement.walkSpeed * -1 * (IsSwimming ? (1 - swimming.waterResistance.x) : 1); } } else { velocity.x = newVelocity; // Limit to walk speed; if (velocity.x > movement.walkSpeed) velocity.x = movement.walkSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1); if (velocity.x < -1 * movement.walkSpeed) velocity.x = -1 * movement.walkSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1); } } else { velocity.x = newVelocity; // Limit to run speed; if (velocity.x > movement.runSpeed) velocity.x = movement.runSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1); if (velocity.x < -1 * movement.runSpeed) velocity.x = -1 * movement.runSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1); } break; case MovementStyle.DIGITAL: if (climbing.allowClimbing && startedClimbing) { velocity.x = (characterInput.x > 0 ? 1 : -1) * climbing.horizontalSpeed; } else if (walking) { velocity.x = (characterInput.x > 0 ? 1 : -1) * movement.walkSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1); } else { velocity.x = (characterInput.x > 0 ? 1 : -1) * movement.runSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1); } break; case MovementStyle.DIGITAL_WITH_SLIDE: if (climbing.allowClimbing && startedClimbing) { velocity.x = (characterInput.x > 0 ? 1 : -1) * climbing.horizontalSpeed; } else if (walking) { velocity.x = (characterInput.x > 0 ? 1 : -1) * movement.walkSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1); } else { velocity.x = (characterInput.x > 0 ? 1 : -1) * movement.runSpeed * (IsSwimming ? (1 - swimming.waterResistance.x) : 1); } break; } } else { switch (movement.movementStyle) { case MovementStyle.PHYSICS_LIKE: velocity.x = velocity.x * actualDrag; break; case MovementStyle.DIGITAL: velocity.x = 0; break; case MovementStyle.DIGITAL_WITH_SLIDE: velocity.x = velocity.x * actualDrag; break; } } // Apply velocity if ((myParent == null || !myParent.overrideX) && velocity.x > movement.skinSize || velocity.x * -1 > movement.skinSize) { myTransform.Translate (velocity.x * frameTime, 0.0f, 0.0f); } float forceSide = 0.0f; // Ledge Hang variables int ledgeHangHitCount = 0; Collider2D ledgeHangCollider = null; RaycastCollider2D actualLedgeCollider = null; // Wall slide variables int wallSlideCount = 0; RaycastCollider2D actualWallCollider = null; isWallSliding = false; isWallHolding = false; for (int i = 0; i < sides.Length; i++) { RaycastHit2D hitsides2D; float additionalDistance = 0.0f; // If crouching and using autoHeightReduction skip any sides2D higher than provided value if (!isCrouching || !crouch.useHeightReduction || sides[i].offset.y <= crouch.ignoredSideCollidersHigherThan) { if (ledgeHanging.autoGrab && velocity.y <= 0.0f) additionalDistance = ledgeHanging.autoGrabDistance; else if (wall.canWallSlide) additionalDistance = wall.wallSlideAdditionalDistance; hitsides2D = sides [i].GetCollision (1 << backgroundLayer, additionalDistance); // Hit something ... if (hitsides2D.collider != null) { // Update ledge hang if (ledgeHanging.canLedgeHang && !grounded && velocity.y <= 0.0f) { if (sides [i].direction == RC_Direction.RIGHT && (sides [i] == highestSideColliders [1] || sides [i] == highestSideColliders [0])) { ledgeHangHitCount++; ledgeHangDirection = RC_Direction.RIGHT; ledgeHangCollider = hitsides2D.collider; if (sides [i] == highestSideColliders [1]) { actualLedgeCollider = highestSideColliders [1]; } else { actualLedgeCollider = highestSideColliders [0]; } } else if (sides [i].direction == RC_Direction.LEFT && (sides [i] == highestSideColliders [1] || sides [i] == highestSideColliders [0])) { ledgeHangHitCount++; ledgeHangDirection = RC_Direction.LEFT; ledgeHangCollider = hitsides2D.collider; if (sides [i] == highestSideColliders [1]) { actualLedgeCollider = highestSideColliders [1]; } else { actualLedgeCollider = highestSideColliders [0]; } } } /// Update wall slide if ((wall.canWallSlide || wall.canWallJump) && !grounded) { if ((sides [i] == highestSideColliders [1] || sides [i] == highestSideColliders [0])) { if (hitsides2D.fraction * (sides[i].distance + additionalDistance) <= sides [i].distance + wall.wallSlideAdditionalDistance) { wallSlideCount++; wallSlideDirection = sides[i].direction; if (sides [i] == highestSideColliders [1]) { actualWallCollider = highestSideColliders [1]; } else { actualWallCollider = highestSideColliders [0]; } } } } // Check for platforms, but only if we are within collider distance + skinSize if (hitsides2D.fraction * (sides[i].distance + additionalDistance) <= sides [i].distance + movement.skinSize) { Platform2D platform = hitsides2D.collider.gameObject.GetComponent<Platform2D> (); if (platform != null) { platform.DoAction (sides [i], this); } } } // Stop movement, but only if we are within collider distance if (hitsides2D.fraction * (sides[i].distance + additionalDistance) <= sides [i].distance) { float tmpForceSide = (hitsides2D.normal * (sides [i].distance - hitsides2D.fraction * (sides[i].distance + additionalDistance))).x; if (tmpForceSide > Mathf.Abs (forceSide) || tmpForceSide * -1 > Mathf.Abs (forceSide)) { forceSide = tmpForceSide; // TODO Remove this after adequate testing break; } } } } // Check for ledge hang if (ledgeHanging.canLedgeHang && ledgeHangHitCount == 1 && !IsSwimming) { bool stopLedgeHang = false; if (ledgeHangDirection == RC_Direction.LEFT) { if (ledgeHanging.grabOnlyInFacingDirection && CurrentDirection >= 0) { stopLedgeHang = true; } if (actualLedgeCollider.IsColliding (1 << backgroundLayer, ledgeHanging.edgeDetectionOffset.x + ledgeHanging.autoGrabDistance, ledgeHanging.edgeDetectionOffset.y)) { stopLedgeHang = true; } if (!(ledgeHangCollider is BoxCollider2D)) { stopLedgeHang = true; } if (!stopLedgeHang && ledgeHangCollider.Max().y < myTransform.position.y + actualLedgeCollider.offset.y + ledgeHanging.graspPoint + ledgeHanging.graspLeeway && ledgeHangCollider.Max().y > myTransform.position.y + actualLedgeCollider.offset.y + ledgeHanging.graspPoint - ledgeHanging.graspLeeway) { isLedgeHanging = true; jumpCount = 2; ledgeHangState = LedgeHangingState.TRANSITION; ledgeHangTimer = 0.0f; ledgeHangOriginalPosition = myTransform.position; ledgeHangGoalPosition = ledgeHanging.hangOffset + new Vector3 (ledgeHangCollider.Max().x, ledgeHangCollider.Max().y, myTransform.position.z); // Check for parent Platform2D platform = ledgeHangCollider.gameObject.GetComponent<Platform2D> (); if (platform != null) { Transform parentPlatform = platform.ParentOnStand (this); if (parentPlatform != null) { myParent = platform; if (myTransform.parent != parentPlatform) { myTransform.parent = parentPlatform; } ledgeHangGoalPosition += platform.velocity * ledgeHanging.transitionTime; } else { // Force ladder to unparent if we have a "bobble" if (myParent is Ladder2D) { Unparent(); } } } } } else if (ledgeHangDirection == RC_Direction.RIGHT) { if (ledgeHanging.grabOnlyInFacingDirection && CurrentDirection <= 0) { stopLedgeHang = true; } if (actualLedgeCollider.IsColliding (1 << backgroundLayer, ledgeHanging.edgeDetectionOffset.x + ledgeHanging.autoGrabDistance, ledgeHanging.edgeDetectionOffset.y)) { stopLedgeHang = true; } if (!(ledgeHangCollider is BoxCollider2D)) { stopLedgeHang = true; } if (!stopLedgeHang && ledgeHangCollider.Max().y < myTransform.position.y + actualLedgeCollider.offset.y + ledgeHanging.graspPoint + ledgeHanging.graspLeeway && ledgeHangCollider.Max().y > myTransform.position.y + actualLedgeCollider.offset.y + ledgeHanging.graspPoint - ledgeHanging.graspLeeway) { isLedgeHanging = true; jumpCount = 2; ledgeHangState = LedgeHangingState.TRANSITION; ledgeHangTimer = 0.0f; ledgeHangOriginalPosition = myTransform.position; ledgeHangGoalPosition = ledgeHanging.hangOffset + new Vector3 (ledgeHangCollider.Min().x, ledgeHangCollider.Max().y, myTransform.position.z); // Check for parent Platform2D platform = ledgeHangCollider.gameObject.GetComponent<Platform2D> (); if (platform != null) { Transform parentPlatform = platform.ParentOnStand (this); if (parentPlatform != null) { myParent = platform; if (myTransform.parent != parentPlatform) { myTransform.parent = parentPlatform; } ledgeHangGoalPosition += platform.velocity * ledgeHanging.transitionTime; } } } } } // Check for wall slide if (wallSlideCount > 0 && velocity.y <= 0.0f) { isWallHolding = true; bool stopWallSlide = true; RaycastHit2D hit = actualWallCollider.GetCollision(1<<backgroundLayer, wall.edgeDetectionOffset.x); if (hit.collider != null) { currentWallTag = hit.collider.gameObject.tag; } else { currentWallTag = null; } if (actualWallCollider.IsColliding (1 << backgroundLayer, wall.edgeDetectionOffset.x, wall.edgeDetectionOffset.y)) { stopWallSlide = false; } if (currentWallTag != wall.wallJumpTag) stopWallSlide = true; if (!stopWallSlide && wall.canWallSlide && ((wallSlideDirection == RC_Direction.RIGHT && characterInput.x > 0) || (wallSlideDirection == RC_Direction.LEFT && characterInput.x < 0))) { // Support sliding on moving platforms actualWallCollider.GetCollision(1<< backgroundLayer, 0.1f); isWallSliding = true; State = CharacterState.WALL_SLIDING; // Handle moving platforms if (hit.collider != null) { Platform2D platform = hit.collider.gameObject.GetComponent<Platform2D>(); if (platform != null && platform.ParentOnStand(this) != null) { myParent = platform; myTransform.parent = platform.ParentOnStand(this); } } // End cope with moving platforms } } // Move if (forceSide > movement.skinSize) { myTransform.Translate(Mathf.Max(velocity.x * frameTime * -1, forceSide), 0.0f, 0.0f); wallJumpDirection = RC_Direction.LEFT; wallJumpTimer = wall.wallJumpTime; hasPressedJumpForWallJump = false; hasPressedDirectionForWallJump = false; StopCrouch(); } else if (-1 * forceSide > movement.skinSize) { myTransform.Translate(Mathf.Min(velocity.x * frameTime * -1, forceSide), 0.0f, 0.0f); wallJumpDirection = RC_Direction.RIGHT; wallJumpTimer = wall.wallJumpTime; hasPressedJumpForWallJump = false; hasPressedDirectionForWallJump = false; StopCrouch(); } if ((forceSide > 0 && velocity.x < 0) || (forceSide < 0 && velocity.x > 0)) { velocity.x = 0.0f; } // Animation if (grounded) { if ( (velocity.x > movement.walkSpeed && characterInput.x > 0.1f) || (velocity.x < movement.walkSpeed * -1 && characterInput.x < -0.1f)) { State = CharacterState.RUNNING; } else if ( (velocity.x > maxSpeedForIdle && characterInput.x > 0.1f) || (velocity.x < -1 * maxSpeedForIdle && characterInput.x < -0.1f)){ State = CharacterState.WALKING; } else if ( velocity.x > maxSpeedForIdle || velocity.x < -1 * maxSpeedForIdle ){ State = CharacterState.SLIDING; } else { State = CharacterState.IDLE; } } // Reset Drag currentDrag = movement.drag; }
/// <summary> /// Unparent from platform. /// </summary> private void Unparent () { myParent = null; myTransform.parent = null; }