// Update is called once per frame void Update() { // update ground state { bool wasOnGround = isOnGround; isOnGround = false; groundNormal = Vector3.up; float maxGroundingDistance = baseController.skinWidth + GROUND_CHECK_DISTANCE; if (Time.time >= jump.ActivatedTime + MIN_JUMP_TIME && Physics.CapsuleCast(ColliderBottom, ColliderTop, baseController.radius, Vector3.down, out RaycastHit hit, maxGroundingDistance, groundCheckLayerMask, QueryTriggerInteraction.Ignore)) { // for use in projecting move direction groundNormal = hit.normal; bool isGroundFacingUp = Vector3.Dot(hit.normal, transform.up) > 0f; bool isSlopeBelowLimit = Vector3.Angle(hit.normal, transform.up) <= baseController.slopeLimit; isOnGround = isGroundFacingUp && isSlopeBelowLimit; // snap to ground if (isOnGround && hit.distance > baseController.skinWidth) { baseController.Move(hit.distance * Vector3.down); } } if (isOnGround && !wasOnGround) { audioSource.PlayOneShot(hitFloorSound, 3); } if (isOnGround) { velocity.y = 0; } } // handle input { // camera control { float rx = playerInput.GetLookInputsHorizontal() * rotationSpeed; float ry = playerInput.GetLookInputsVertical() * rotationSpeed; float ryClamped = Mathf.Clamp(playerCamera.transform.localEulerAngles.x - ry, 20, 60); transform.Rotate(new Vector3(0f, rx, 0f), Space.Self); playerCamera.transform.localEulerAngles = new Vector3(ryClamped, 0f, 0f); } // movement { Vector3 inputVelocity = transform.TransformVector(playerInput.GetMoveInput()) * moveSpeed; Vector3 tangent = Vector3.Cross(inputVelocity.normalized, transform.up); Vector3 targetVelocity = Vector3.Cross(groundNormal, tangent).normalized *inputVelocity.magnitude; float acceleration = isOnGround ? maxAcceleration : maxAcceleration * airControlFactor; float maxSpeedChange = acceleration * Time.deltaTime; float vx = Mathf.MoveTowards(velocity.x, targetVelocity.x, maxSpeedChange); float vy = Mathf.MoveTowards(velocity.y, targetVelocity.y, maxSpeedChange); float vz = Mathf.MoveTowards(velocity.z, targetVelocity.z, maxSpeedChange); velocity = new Vector3(vx, isOnGround ? vy : velocity.y, vz); // add jump jump.Update(playerInput.GetJumpInputDown()); if (isOnGround && jump.Activate()) { velocity.y = jumpSpeed; isOnGround = false; groundNormal = Vector3.up; } // apply gravity if (!isOnGround) { velocity += Vector3.down * gravityAcceleration * Time.deltaTime; } // collide with other geometry Vector3 postVelocity = velocity; if (Physics.CapsuleCast(ColliderBottom, ColliderTop, baseController.radius, velocity.normalized, out RaycastHit hit, velocity.magnitude * Time.deltaTime, 0, QueryTriggerInteraction.Ignore)) { postVelocity = Vector3.ProjectOnPlane(velocity, hit.normal); } baseController.Move(velocity * Time.deltaTime); velocity = postVelocity; } // pickup { pickup1.Update(playerInput.GetFireInputDown()); if (pickup1.Activate()) { Pickup(0); } pickup2.Update(playerInput.GetFire2InputDown()); if (pickup2.Activate()) { Pickup(1); } } } }