private void OnCollisionEnter(Collision other) { foreach (ContactPoint c in other.contacts) { if (c.normal.y > 0.5f) { OnHitGround?.Invoke(); airborne = false; } } }
void CheckGrounded(float dt) { bool hitGroundThisFrame = false; if (rb.velocity.y <= 0f) { isJumping = false; } if (characterCollision.OnGround) { if (rb.velocity.y <= 0) { hitGroundThisFrame = true; if (!wasGrounded) { OnHitGround?.Invoke(rb.velocity.y); } } if (!isJumping) { numberOfJumps = jumpProfile.MaxNumberOfJumps; } notGroundedTimer = 0f; } else { notGroundedTimer += dt; if (notGroundedTimer > jumpProfile.CoyoteTime) { if (numberOfJumps == jumpProfile.MaxNumberOfJumps) { numberOfJumps--; } } } wasGrounded = hitGroundThisFrame; }
internal void LateUpdate() { deltaTime = Mathf.Min(deltaTimeCap, Time.deltaTime); if (transform.position.y < minimumYPosition) { SetPosition(characterPosition.worldPosition); return; } if (freeMovementController.IsActive()) { velocity = freeMovementController.CalculateMovement(); } else { velocity.x = 0f; velocity.z = 0f; velocity.y += gravity * deltaTime; bool previouslyGrounded = isGrounded; if (!isJumping || velocity.y <= 0f) { CheckGround(); } if (isGrounded) { isJumping = false; velocity.y = gravity * deltaTime; // to avoid accumulating gravity in velocity.y while grounded } else if (previouslyGrounded && !isJumping) { lastUngroundedTime = Time.time; } if (Utils.isCursorLocked && characterForward.HasValue()) { // Horizontal movement var speed = movementSpeed * (isSprinting ? runningSpeedMultiplier : 1f); transform.forward = characterForward.Get().Value; var xzPlaneForward = Vector3.Scale(cameraForward.Get(), new Vector3(1, 0, 1)); var xzPlaneRight = Vector3.Scale(cameraRight.Get(), new Vector3(1, 0, 1)); Vector3 forwardTarget = Vector3.zero; if (characterYAxis.GetValue() > 0) { forwardTarget += xzPlaneForward; } if (characterYAxis.GetValue() < 0) { forwardTarget -= xzPlaneForward; } if (characterXAxis.GetValue() > 0) { forwardTarget += xzPlaneRight; } if (characterXAxis.GetValue() < 0) { forwardTarget -= xzPlaneRight; } forwardTarget.Normalize(); velocity += forwardTarget * speed; CommonScriptableObjects.playerUnityEulerAngles.Set(transform.eulerAngles); } bool jumpButtonPressedWithGraceTime = jumpButtonPressed && (Time.time - lastJumpButtonPressedTime < 0.15f); if (jumpButtonPressedWithGraceTime) // almost-grounded jump button press allowed time { bool justLeftGround = (Time.time - lastUngroundedTime) < 0.1f; if (isGrounded || justLeftGround) // just-left-ground jump allowed time { Jump(); } } //NOTE(Mordi): Detecting when the character hits the ground (for landing-SFX) if (isGrounded && !previouslyGrounded && (Time.time - lastUngroundedTime) > 0.4f) { OnHitGround?.Invoke(); } } bool movingPlatformMovedTooMuch = Vector3.Distance(lastPosition, transform.position) > movingPlatformAllowedPosDelta; if (isOnMovingPlatform && !characterPosition.RepositionedWorldLastFrame() && movingPlatformMovedTooMuch) { ResetGround(); // As the character has already been moved faster-than-we-want, we reposition it characterController.transform.position = lastPosition; } if (characterController.enabled) { //NOTE(Brian): Transform has to be in sync before the Move call, otherwise this call // will reset the character controller to its previous position. Environment.i.platform.physicsSyncController.Sync(); characterController.Move(velocity * deltaTime); } SetPosition(PositionUtils.UnityToWorldPosition(transform.position)); if ((DCLTime.realtimeSinceStartup - lastMovementReportTime) > PlayerSettings.POSITION_REPORTING_DELAY) { ReportMovement(); } if (isOnMovingPlatform) { lastLocalGroundPosition = groundTransform.InverseTransformPoint(transform.position); } OnUpdateFinish?.Invoke(deltaTime); }
void FixedUpdate() { isOnGround = feetCol.IsTouchingLayers(LayerMask.GetMask("Ground")); isInLadder = col.IsTouchingLayers(LayerMask.GetMask("Ladder")); fuClimbing(); fuRunning(); fuJumping(jumpSpeed); //if the player hit the ground this frame, stop his x- & y-velocity. #region explanation //We need to do this because otherwise the player would keep on sliding, because he has no friction. //Why no friction, you ask? So that he can't wall- jump. Why is he be able to wall-jump with //friction? -> Example: When you jump to the right and hit a wall and keep holding the "go right" //button, the player's and wall's colliders are touching every single frame. Since there's //friction between them, the rigidbody inhibits movement. You could, for example, make the player //slide down walls if you apply just a little friction. //added 13.6.: Why stop the y-vel aswell? It's because while jumping and hugging a wall, once //the player would hit that wall's corner, the feet collider would touch that corner, hence //setting isOnGround to true. Since the player is holding the jump button at this time, //they'd jump again. Jumping is just adding jump-velocity to the current velocity, so the //player would jump really high. #endregion if (!wasOnGroundLastF && isOnGround) { rb.velocity = Vector2.zero; if (hasControl) { OnHitGround?.Invoke(); //the hasControl check is to make respawning silent } } #region start_stop_delegates //if started moving in the ladder this frame if (movingInLadderThisF && !movingInLadderLastF && hasControl) { OnStartedClimbing?.Invoke(); } //if we latched onto the ladder but didn't move if (isInLadder && !wasInLadderLastF) { OnClimbedOnce?.Invoke(); } //if stopped moving in the ladder this frame if (!movingInLadderThisF && movingInLadderLastF) { OnStoppedClimbing?.Invoke(); } //if started holding run this frame while on ground OR hit ground while holding run if (hasControl) { if ((holdingRun && !holdingRunLastF && isOnGround) || (holdingRun && isOnGround && !wasOnGroundLastF)) { OnStartedRunning?.Invoke(); } } //if stopped holding run this frame while on ground OR stopped being on ground this frame if ((!holdingRun && holdingRunLastF && isOnGround) || (!isOnGround && wasOnGroundLastF)) { OnStoppedRunning?.Invoke(); } #endregion start_stop_delegates holdingRunLastF = holdingRun; wasOnGroundLastF = isOnGround; wasInLadderLastF = isInLadder; hadControlLastF = hasControl; movingInLadderLastF = movingInLadderThisF; }