using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; public class swimSystem : externalControllerBehavior { [Header ("Main Settings")] [Space] public bool swimSystemEnabled = true; public LayerMask layerForGroundDetection; public float groundDetectionRaycastDistance = 1; public float groundDetectionRaycastDistanceOnWater = 0.1f; public float maxDistanceToWalkOnWater = 1; [Space] [Header ("Animation Settings")] [Space] public int swimID; public int regularID = 1; public int swimStateID = 0; public int diveStateID = 1; public int movingUpStateID = 1; public int movingDownStateID = 1; public float movingUpForwardStateID = 1.5f; public float movingDownForwardStateID = 2.5f; public int regularIdleID = 0; [Space] [Header ("Physics Settings")] [Space] public bool useForceMode; public ForceMode swimForceMode; public bool moveUpAndDownEnabled; public bool turboEnabled; public float waterFriction; public float maxSwimVelocity; public float swimTurboSpeed; public float swimForce; public float swimMoveUpSpeed; public float swimMoveDownSpeed; public float swimSpeedOnAimMultiplier; public float autoAdjustDistanceToSwimSurfaceSpeed = 2; public float autoAdjustDistanceToSwimSurface = 1.6f; public float firstPersonSpeedMultiplier = 1; [Space] public bool addForceIfDeadOnWater; public Vector3 forceDirectionIfDeadOnWater = -Vector3.up; public float forceAmountIfDeadOnWater = 5; [Space] [Header ("Return To Surface On Enter Water Settings")] [Space] public bool setInitialStateOnSurfaceOnEnterWater = true; public bool useMaxSpeedToMoveToSurfaceOnSwimEnabled; public float maxSpeedToMoveToSurfaceOnSwimEnabled = 20; public float minSpeedToSetSwimOnSurfaceState = 5; public bool cancelReturnToSurfaceIfInputPressed; [Space] [Header ("Other Settings")] [Space] public float minDistanceForSwimSurface = 0.2f; public float delayToResetVelocityWhenReachingSurfaceFromMovingInput = 0.4f; public bool keepSwimStateActiveOnDeath; public bool checkGroundDistanceOnSwimOnSurface = true; public float raycastDistanceToCheckOnSwimOnSurface = 1; public bool checkIfPlayerIsOnWaterInsideVehicles; [Space] [Header ("Jump Settings")] [Space] public bool canJumpWhenSwimmingOnSurface; public float jumpForceOnSurface; public bool onlyClimbOnCloseSurfaces; public float maxAngleDifferenceOnSurfaceToClimb = 90; public float maxClimbSurfaceHeight = 4; public bool allowJumpOnSwimIfNoCloseSurfaceToClimbFound; public Transform climbSurfaceActionSystemTransform; [Space] [Space] public eventParameters.eventToCallWithGameObject eventToActivateClimbSurfaceActionSystem; [Space] [Header ("Swim Settings")] [Space] public float swimVerticalSpeedMultiplier; public float swimHorizontalSpeedMultiplier; [Space] [Header ("Dive Settings")] [Space] public float diveVerticalSpeedMultiplier; public float diveHorizontalSpeedMultiplier; [Space] [Header ("Third Person Camera State Settings")] [Space] public bool setNewCameraStateOnThirdPerson; public string newCameraStateOnThirdPerson; public bool returnToPreviuosViewOnSwimEnd = true; [Space] [Header ("Debug")] [Space] public bool showDebugPrint; public bool swimSystemActive; public bool turboActive; public bool movingUp; public bool movingDown; public bool currentlyOnSurface; public bool currentlyDiving; public bool overridingMovementToSurfaceActive; public Vector3 targetDirection; public float currentHorizontalMovement; public float currentVerticalMovement; public bool checkIfCloseToSurface; public bool playerIsMoving; public float currentDistanceToSurface; public bool checkingToActivateMovementToSurfaceAutomaticallyActive; public float currentStatID; public bool walkingOnWater; public Vector3 totalForce; public Vector3 extraForce; public bool cameraBelowWater; public bool swimForcesPaused; public float currentLookAngle; public float lookDirectionAngle; public bool checkingIfPlayerNotMovingInsideVehicleActive; [Space] public List swimTriggerList = new List (); [Space] [Header ("Events Settings")] [Space] public UnityEvent eventOnStateEnabled; public UnityEvent eventOnStateDisabled; public bool useEventOnWalkingOnWater; public UnityEvent eventOnWalkingOnWater; public bool useEventsOnDiveStateChange; public UnityEvent eventOnStartDive; public UnityEvent eventOnEndDive; public bool useEventOnChangeSwimToDive; public UnityEvent eventOnChangeSwimToDive; public bool useEventOnChangeDiveToSwim; public UnityEvent eventOnChangeDiveToSwim; public UnityEvent eventBeforeActivatingSwimSystem; public UnityEvent eventBeforeDeactivatingSwimSystem; public bool useEventOnCameraUnderwaterEffect; public UnityEvent eventOnCameraUnderWaterStart; public UnityEvent eventOnCameraUnderWaterEnd; public bool useEventUseTurboOnSwim; public UnityEvent eventOnStarTurboOnSwim; public UnityEvent eventOnEndTurboOnSwim; [Space] [Header ("Components")] [Space] public playerController mainPlayerController; public Transform playerTransform; public Transform mainCameraTransform; public Transform playerCameraTransform; public Rigidbody mainRigidbody; public playerInputManager playerInput; public headTrack mainHeadTrack; public Collider mainPlayerCollider; public Collider swimCollider; public playerCamera mainPlayerCamera; public ragdollActivator mainRagdollActivator; float currentAimSpeedMultipler; float velocityMagnitude; Transform currentSwimZoneTransform; float lastTimeSwimActive; bool lookingInCameraDirection; bool turnAndForwardAnimatorValuesPaused; bool checkingDivingDirection; bool enteringOnWaterFromWalking; float lastTimeWalkingOnWaterActive; bool setMovementToSurfaceOnEnterWaterActive; bool canUseTurboPausedState; string previousCameraState = ""; bool reachingSurfaceFromMovingInput; float lastTimeSurfaceReachedFromMovingInput; bool firstPersonChecked; bool thirdPersonChecked; waterSurfaceSystem currentWaterSurfaceSystem; bool updateSurfaceTransformDynamically; Collider currentSwimTrigger; bool currentSwimTriggerLocated; Transform currentLockedCameraTransform; bool isPlayerMovingOn3dWorld; bool isCameraTypeFree; Coroutine checkIfPlayerNotOnVehicleCoroutine; bool ignoreDisableCameraBelowWaterStateActive; void checkSwimStateOnDeath () { if (cameraBelowWater) { ignoreDisableCameraBelowWaterStateActive = true; } setSwimSystemActivestate (false); setExtraCharacterStateOnSwim (true); if (addForceIfDeadOnWater) { mainRagdollActivator.setCustomForceOnMainHipsRigidbody (forceDirectionIfDeadOnWater * forceAmountIfDeadOnWater); } } void setExtraCharacterStateOnSwim (bool state) { if (state) { mainPlayerCamera.setCustomSmoothReturnSpeed (10); } else { mainPlayerCamera.setOriginalSmoothReturnSpeed (); } if (mainRagdollActivator != null) { mainRagdollActivator.setPauseAnimatorStatesToGetUpState (state); mainRagdollActivator.setStateToGetUpOnAirActive (state); } } public override void updateControllerBehavior () { //if the player is swimming if (swimSystemActive) { if (mainPlayerController.isPlayerDead ()) { checkSwimStateOnDeath (); return; } bool getRegularDistanceToSurface = true; if (updateSurfaceTransformDynamically) { float surfacePosition = currentWaterSurfaceSystem.GetWaterLevel (playerTransform.position); currentDistanceToSurface = Mathf.Abs (playerTransform.position.y - surfacePosition); if (surfacePosition != -1) { getRegularDistanceToSurface = false; } } if (getRegularDistanceToSurface) { currentDistanceToSurface = Mathf.Abs (playerTransform.InverseTransformPoint (currentSwimZoneTransform.position).y); } isPlayerMovingOn3dWorld = mainPlayerController.isPlayerMovingOn3dWorld (); isCameraTypeFree = mainPlayerCamera.isCameraTypeFree (); if (walkingOnWater) { if (!mainPlayerController.isPlayerOnGround () && (lastTimeWalkingOnWaterActive == 0 || Time.time > lastTimeWalkingOnWaterActive + 1)) { enableOrDisableSwimState (true); walkingOnWater = false; lastTimeWalkingOnWaterActive = 0; } else { if (currentDistanceToSurface > maxDistanceToWalkOnWater) { enteringOnWaterFromWalking = true; walkingOnWater = false; enableOrDisableSwimState (true); } } } else { updateSwimActiveState (); checkIfGroundDetectedOnSwimActiveState (); if (useEventOnCameraUnderwaterEffect) { if (currentSwimTriggerLocated) { bool cameraInsideBoundTrigger = false; if (isPlayerMovingOn3dWorld && isCameraTypeFree) { cameraInsideBoundTrigger = currentSwimTrigger.bounds.Contains (mainCameraTransform.position); } else { cameraInsideBoundTrigger = currentSwimTrigger.bounds.Contains (playerTransform.position + 1.7f * playerCameraTransform.up); } if (cameraInsideBoundTrigger) { if (!cameraBelowWater) { eventOnCameraUnderWaterStart.Invoke (); cameraBelowWater = true; } } else { if (cameraBelowWater) { eventOnCameraUnderWaterEnd.Invoke (); cameraBelowWater = false; } } } else { if (mainCameraTransform.position.y < currentSwimZoneTransform.position.y) { if (!cameraBelowWater) { eventOnCameraUnderWaterStart.Invoke (); cameraBelowWater = true; } } else { if (cameraBelowWater) { eventOnCameraUnderWaterEnd.Invoke (); cameraBelowWater = false; } } } } } } } void updateSwimActiveState () { targetDirection = Vector3.zero; currentVerticalMovement = mainPlayerController.getVerticalInput (); currentHorizontalMovement = mainPlayerController.getHorizontalInput (); if (overridingMovementToSurfaceActive) { currentVerticalMovement = 0; currentHorizontalMovement = 0; checkIfCloseToSurface = true; playerInput.overrideInputValues (new Vector2 (0, 1), true); if (cancelReturnToSurfaceIfInputPressed) { if (playerInput.getRealMovementAxisInputAnyType () != Vector2.zero) { enableOrDisableVerticalMovementUp (false); overridingMovementToSurfaceActive = false; checkIfCloseToSurface = false; setDivingState (true); if (showDebugPrint) { print ("cancel movement to surface"); } } } } else { if (movingUp) { checkIfCloseToSurface = true; currentVerticalMovement = 0; currentHorizontalMovement = 0; if (lookingInCameraDirection) { playerInput.overrideInputValues (new Vector2 (0, 1), true); } else { playerInput.overrideInputValues (new Vector2 (0, -1), true); } } else { checkIfCloseToSurface = false; } if (movingDown) { currentVerticalMovement = 0; currentHorizontalMovement = 0; if (lookingInCameraDirection) { playerInput.overrideInputValues (new Vector2 (0, 1), true); } else { playerInput.overrideInputValues (new Vector2 (0, -1), true); } } } if (!checkIfCloseToSurface) { if (currentlyDiving) { if (!overridingMovementToSurfaceActive) { if (!movingUp && !movingDown && playerIsMoving) { if (currentStatID != movingUpStateID && currentDistanceToSurface < minDistanceForSwimSurface) { if (currentStatID == diveStateID) { if (showDebugPrint) { print ("returning to surface from up axis input"); } checkIfCloseToSurface = true; } } } } } } if (checkIfCloseToSurface) { bool canCheckDistance = true; if (checkingToActivateMovementToSurfaceAutomaticallyActive) { if (Time.time > lastTimeSwimActive + 1) { checkingToActivateMovementToSurfaceAutomaticallyActive = false; } else { canCheckDistance = false; // if (showDebugPrint) { // print ("waiting to check close to surface"); // } } } if (canCheckDistance && currentDistanceToSurface < minDistanceForSwimSurface) { if (showDebugPrint) { print ("close to surface reached"); } enableOrDisableVerticalMovementUp (false); overridingMovementToSurfaceActive = false; checkIfCloseToSurface = false; setDivingState (false); lastTimeSurfaceReachedFromMovingInput = Time.time; reachingSurfaceFromMovingInput = true; } } if (!isPlayerMovingOn3dWorld || !isCameraTypeFree) { currentLockedCameraTransform = mainPlayerCamera.getLockedCameraTransform (); } if (currentlyDiving) { if (isPlayerMovingOn3dWorld) { if (isCameraTypeFree) { targetDirection = (currentVerticalMovement * diveVerticalSpeedMultiplier) * mainCameraTransform.forward + (currentHorizontalMovement * diveHorizontalSpeedMultiplier) * mainCameraTransform.right; } else { targetDirection = (currentVerticalMovement * diveVerticalSpeedMultiplier) * currentLockedCameraTransform.forward + (currentHorizontalMovement * diveHorizontalSpeedMultiplier) * currentLockedCameraTransform.right; } } else { targetDirection = (currentVerticalMovement * diveVerticalSpeedMultiplier) * currentLockedCameraTransform.up + (currentHorizontalMovement * diveHorizontalSpeedMultiplier) * currentLockedCameraTransform.right; } } if (currentlyOnSurface) { if (isPlayerMovingOn3dWorld) { if (isCameraTypeFree) { targetDirection = (currentVerticalMovement * swimVerticalSpeedMultiplier) * playerCameraTransform.forward + (currentHorizontalMovement * swimHorizontalSpeedMultiplier) * playerCameraTransform.right; } else { targetDirection = (currentVerticalMovement * swimVerticalSpeedMultiplier) * currentLockedCameraTransform.forward + (currentHorizontalMovement * swimHorizontalSpeedMultiplier) * currentLockedCameraTransform.right; } } else { targetDirection = (currentVerticalMovement * swimVerticalSpeedMultiplier) * currentLockedCameraTransform.up + (currentHorizontalMovement * swimHorizontalSpeedMultiplier) * currentLockedCameraTransform.right; } } if (targetDirection.magnitude > 1) { targetDirection.Normalize (); } playerIsMoving = mainPlayerController.isPlayerMoving (0.1f); bool isPlayerOnFirstPerson = mainPlayerController.isPlayerOnFirstPerson (); if (isPlayerOnFirstPerson) { if (!firstPersonChecked) { if (showDebugPrint) { print ("checking swim state on first person"); } if (thirdPersonChecked) { mainPlayerController.resetAnimator (); if (showDebugPrint) { print ("reset animator state for first person"); } } firstPersonChecked = true; thirdPersonChecked = false; } } else { if (!thirdPersonChecked) { if (showDebugPrint) { print ("checking swim state on third person"); } if (firstPersonChecked) { mainPlayerController.resetAnimator (); if (showDebugPrint) { print ("reset animator state for first person"); } mainPlayerController.setOnGroundState (false); mainPlayerController.setOnGroundAnimatorIDValueWithoutCheck (false); mainPlayerController.setFootStepManagerState (true); } thirdPersonChecked = true; firstPersonChecked = false; } } if (!isPlayerOnFirstPerson && !mainPlayerController.isPlayerRotatingToSurface ()) { if (playerIsMoving) { currentLookAngle = 0; if (!mainPlayerController.isPlayerAiming ()) { if (currentlyDiving && !movingDown && !movingUp) { if (isPlayerMovingOn3dWorld) { if (isCameraTypeFree) { currentLookAngle = Vector3.SignedAngle (playerCameraTransform.forward, mainCameraTransform.forward, playerCameraTransform.right); float angleWithCamera = Vector3.SignedAngle (playerCameraTransform.forward, playerTransform.forward, playerCameraTransform.up); bool playerInCameraDirection = Mathf.Abs (angleWithCamera) < 90; if (currentLookAngle > 45) { if (playerInCameraDirection) { currentStatID = movingDownStateID; } else { currentStatID = movingUpStateID; } } else if (currentLookAngle < -45) { if (playerInCameraDirection) { currentStatID = movingUpStateID; } else { currentStatID = movingDownStateID; } } else { currentStatID = diveStateID; } } else { currentStatID = diveStateID; } } else { lookDirectionAngle = Vector3.Angle (playerTransform.forward, currentLockedCameraTransform.right); bool lookingRight = false; if (lookDirectionAngle < 90) { lookingRight = true; } if (lookingRight) { currentLookAngle = Vector3.SignedAngle (targetDirection, currentLockedCameraTransform.right, currentLockedCameraTransform.forward); } else { currentLookAngle = Vector3.SignedAngle (targetDirection, -currentLockedCameraTransform.right, -currentLockedCameraTransform.forward); } if (currentLookAngle > 70) { currentStatID = movingDownStateID; } else if (currentLookAngle < 70 && currentLookAngle > 40) { currentStatID = movingDownForwardStateID; } else if (currentLookAngle > -70 && currentLookAngle < -40) { currentStatID = movingUpForwardStateID; } else if (currentLookAngle < -70) { currentStatID = movingUpStateID; } else { currentStatID = diveStateID; } } mainPlayerController.setCurrentIdleIDValueFloat (currentStatID); checkingDivingDirection = true; if (currentStatID == movingUpStateID && currentDistanceToSurface < minDistanceForSwimSurface) { setDivingState (false); lastTimeSurfaceReachedFromMovingInput = Time.time; reachingSurfaceFromMovingInput = true; } } else { if (currentlyOnSurface && movingUp) { mainPlayerController.setCurrentIdleIDValueFloat (movingUpStateID); checkingDivingDirection = true; } } } } else { if (currentlyDiving) { if (checkingDivingDirection) { updateCurrentStateIDValue (); } } checkingDivingDirection = false; } } currentAimSpeedMultipler = 1; if (!isPlayerOnFirstPerson && mainPlayerController.isPlayerAiming ()) { currentAimSpeedMultipler = swimSpeedOnAimMultiplier; if (!turnAndForwardAnimatorValuesPaused) { mainPlayerController.setTurnAndForwardAnimatorValuesPausedState (true); turnAndForwardAnimatorValuesPaused = true; } } else { if (turnAndForwardAnimatorValuesPaused) { mainPlayerController.setTurnAndForwardAnimatorValuesPausedState (false); turnAndForwardAnimatorValuesPaused = false; } } totalForce = (swimForce * currentAimSpeedMultipler) * targetDirection; if (movingUp) { totalForce += swimMoveUpSpeed * playerTransform.up; playerIsMoving = true; } if (movingDown) { totalForce -= swimMoveDownSpeed * playerTransform.up; playerIsMoving = true; } extraForce = Vector3.zero; if (currentlyOnSurface) { if (setMovementToSurfaceOnEnterWaterActive) { if (Time.time < lastTimeSwimActive + 1) { if (!swimForcesPaused) { mainRigidbody.linearVelocity = Vector3.MoveTowards (mainRigidbody.linearVelocity, Vector3.zero, Time.deltaTime * 10); } } else { setMovementToSurfaceOnEnterWaterActive = false; } } else { if (currentDistanceToSurface < autoAdjustDistanceToSwimSurface) { extraForce = autoAdjustDistanceToSwimSurfaceSpeed * (-playerTransform.up); } else { if (Time.time > lastTimeSwimActive + 3) { if (currentDistanceToSurface > autoAdjustDistanceToSwimSurface + 0.2f) { extraForce = autoAdjustDistanceToSwimSurfaceSpeed * playerTransform.up; } } } } } if (playerIsMoving) { totalForce += extraForce; if (turboActive) { totalForce *= swimTurboSpeed; } velocityMagnitude = totalForce.magnitude; if (velocityMagnitude > maxSwimVelocity) { totalForce = Vector3.ClampMagnitude (totalForce, maxSwimVelocity); } velocityMagnitude = totalForce.magnitude; if (!swimForcesPaused) { if (isPlayerOnFirstPerson) { totalForce *= firstPersonSpeedMultiplier; } if (useForceMode) { mainRigidbody.AddForce (totalForce, swimForceMode); } else { mainRigidbody.AddForce (totalForce); } } // print ("MOVING " + totalForce); } else { velocityMagnitude = mainRigidbody.linearVelocity.magnitude; if (velocityMagnitude > 0) { totalForce = (-1 * waterFriction) * mainRigidbody.linearVelocity; // print ("using water friction"); } totalForce += extraForce; if (!swimForcesPaused) { if (isPlayerOnFirstPerson) { totalForce *= firstPersonSpeedMultiplier; } mainRigidbody.AddForce (totalForce, swimForceMode); } // print ("NOT MOVING " + totalForce); } if (reachingSurfaceFromMovingInput) { if (Time.time > lastTimeSurfaceReachedFromMovingInput + delayToResetVelocityWhenReachingSurfaceFromMovingInput) { mainPlayerController.setPlayerVelocityToZero (); reachingSurfaceFromMovingInput = false; } } } void checkIfGroundDetectedOnSwimActiveState () { if (currentDistanceToSurface < maxDistanceToWalkOnWater) { if (Physics.Raycast (playerTransform.position + (0.05f * playerTransform.up), -playerTransform.up, groundDetectionRaycastDistanceOnWater, layerForGroundDetection)) { lastTimeWalkingOnWaterActive = Time.time; enteringOnWaterFromWalking = true; walkingOnWater = true; if (useEventOnWalkingOnWater) { eventOnWalkingOnWater.Invoke (); } enableOrDisableSwimState (false); } } if (!walkingOnWater && checkGroundDistanceOnSwimOnSurface) { if (currentDistanceToSurface < 2) { if (Physics.Raycast (playerTransform.position + (0.05f * playerTransform.up), -playerTransform.up, raycastDistanceToCheckOnSwimOnSurface, layerForGroundDetection)) { if (swimCollider.enabled) { swimCollider.enabled = false; } } else { if (!swimCollider.enabled) { swimCollider.enabled = true; } } } } } public void stopCheckIfPlayerNotOnVehicleCoroutine () { if (checkIfPlayerNotOnVehicleCoroutine != null) { StopCoroutine (checkIfPlayerNotOnVehicleCoroutine); } } IEnumerator updateCheckIfPlayerNotOnVehicleCoroutine () { var waitTime = new WaitForSecondsRealtime (0.00001f); while (true) { if (!mainPlayerController.isMovingInsideVehicle ()) { if (currentSwimTriggerLocated) { setSwimSystemActivestate (true); } checkingIfPlayerNotMovingInsideVehicleActive = false; stopCheckIfPlayerNotOnVehicleCoroutine (); } yield return waitTime; } } public void setSwimSystemActivestate (bool state) { if (!swimSystemEnabled) { if (showDebugPrint) { print ("swim system not eanbled, cancelling"); } return; } if (checkIfPlayerIsOnWaterInsideVehicles) { if (checkingIfPlayerNotMovingInsideVehicleActive) { stopCheckIfPlayerNotOnVehicleCoroutine (); checkingIfPlayerNotMovingInsideVehicleActive = false; } } if (state && mainPlayerController.isMovingInsideVehicle ()) { if (showDebugPrint) { print ("moving inside vehicle, cancelling"); } if (checkIfPlayerIsOnWaterInsideVehicles) { checkingIfPlayerNotMovingInsideVehicleActive = true; checkIfPlayerNotOnVehicleCoroutine = StartCoroutine (updateCheckIfPlayerNotOnVehicleCoroutine ()); } return; } if (swimSystemActive == state) { if (showDebugPrint) { print ("setting same swim state, cancelling"); } return; } if (state && mainPlayerController.isPlayerDead ()) { if (showDebugPrint) { print ("character is dead, cancelling"); } return; } if (state) { externalControllerBehavior currentExternalControllerBehavior = mainPlayerController.getCurrentExternalControllerBehavior (); if (currentExternalControllerBehavior != null && currentExternalControllerBehavior != this) { if (canBeActivatedIfOthersBehaviorsActive && checkIfCanEnableBehavior (currentExternalControllerBehavior.behaviorName)) { currentExternalControllerBehavior.disableExternalControllerState (); } else { if (showDebugPrint) { print ("can't enable external controller, cancelling"); } return; } } } bool swimModeActivePrevioulsy = swimSystemActive; swimSystemActive = state; mainPlayerController.removeJumpInputState (); setBehaviorCurrentlyActiveState (state); setCurrentPlayerActionSystemCustomActionCategoryID (); if (swimSystemActive) { mainPlayerController.setExternalControllerBehavior (this); } else { if (swimModeActivePrevioulsy) { externalControllerBehavior currentExternalControllerBehavior = mainPlayerController.getCurrentExternalControllerBehavior (); if (currentExternalControllerBehavior == null || currentExternalControllerBehavior == this) { mainPlayerController.setExternalControllerBehavior (null); } } } bool canSetSwimState = true; walkingOnWater = false; setMovementToSurfaceOnEnterWaterActive = false; if (state) { if (Physics.Raycast (playerTransform.position, -playerTransform.up, groundDetectionRaycastDistance, layerForGroundDetection)) { canSetSwimState = false; walkingOnWater = true; if (useEventOnWalkingOnWater) { eventOnWalkingOnWater.Invoke (); } } } else { canSetSwimState = true; } if (canSetSwimState) { enableOrDisableSwimState (state); } if (swimSystemActive) { Physics.IgnoreCollision (mainPlayerCollider, swimCollider, true); mainPlayerController.setIgnoreCollisionOnExternalColliderOnlyWithExtraColliderList (swimCollider, true); } swimCollider.enabled = state; bool isFirstPersonActive = mainPlayerController.isPlayerOnFirstPerson (); if (setNewCameraStateOnThirdPerson && !isFirstPersonActive && mainPlayerCamera != null) { if (state) { previousCameraState = mainPlayerCamera.getCurrentStateName (); mainPlayerCamera.setCameraStateOnlyOnThirdPerson (newCameraStateOnThirdPerson); } else { if (previousCameraState != "") { if (returnToPreviuosViewOnSwimEnd) { if (previousCameraState != newCameraStateOnThirdPerson) { mainPlayerCamera.setCameraStateOnlyOnThirdPerson (previousCameraState); } } previousCameraState = ""; } } } if (state) { firstPersonChecked = isFirstPersonActive; thirdPersonChecked = !isFirstPersonActive; } else { swimForcesPaused = false; firstPersonChecked = false; thirdPersonChecked = false; } if (showDebugPrint) { print ("setSwimSystemActivestate " + state); } } void enableOrDisableSwimState (bool state) { if (state) { eventBeforeActivatingSwimSystem.Invoke (); } else { eventBeforeDeactivatingSwimSystem.Invoke (); } mainPlayerController.enableOrDisableSwimMode (state); if (!state) { mainPlayerController.setLastTimeFalling (); } if (state) { mainPlayerController.setCurrentAirIDValue (swimID); mainPlayerController.setOnGroundAnimatorIDValue (false); mainPlayerController.setPreviousValueOnGroundAnimatorStateValue (false); } else { mainPlayerController.setCurrentAirIDValue (regularID); mainPlayerController.setCurrentAirSpeedValue (1); } if (swimSystemActive) { eventOnStateEnabled.Invoke (); if (mainHeadTrack != null) { mainHeadTrack.setSmoothHeadTrackDisableState (true); } } else { eventOnStateDisabled.Invoke (); if (turboActive) { enableOrDisableTurbo (false); } enableOrDisableVerticalMovementUp (false); enableOrDisableVerticalMovementDown (false); if (mainHeadTrack != null) { mainHeadTrack.setSmoothHeadTrackDisableState (false); } } mainPlayerController.stopShakeCamera (); movingUp = false; movingDown = false; if (currentlyDiving) { setDivingState (false); } if (swimSystemActive) { bool checkIfDivingState = true; float lastTimeResurrect = mainPlayerController.getLastTimeResurrect (); bool ignoreDivingCheck = false; if (lastTimeResurrect > 0 && Time.time < lastTimeResurrect + 3f) { enteringOnWaterFromWalking = false; ignoreDivingCheck = true; } currentDistanceToSurface = Mathf.Abs (playerTransform.InverseTransformPoint (currentSwimZoneTransform.position).y); float verticalSpeed = playerTransform.InverseTransformDirection (mainRigidbody.linearVelocity).y; if (currentDistanceToSurface > 2 && Mathf.Abs (verticalSpeed) < 1) { enteringOnWaterFromWalking = false; ignoreDivingCheck = true; if (showDebugPrint) { print ("entering on deep water on low speed, setting dive state"); } } if (enteringOnWaterFromWalking) { overridingMovementToSurfaceActive = false; checkIfCloseToSurface = false; setDivingState (false); checkIfDivingState = false; if (showDebugPrint) { print ("entering on water while walking"); } } bool checkSurfaceOnEnterWaterResult = false; if (setInitialStateOnSurfaceOnEnterWater) { if (checkIfDivingState && !ignoreDivingCheck) { if (useMaxSpeedToMoveToSurfaceOnSwimEnabled) { verticalSpeed = playerTransform.InverseTransformDirection (mainRigidbody.linearVelocity).y; float distanceToSurfaceWithSign = playerTransform.InverseTransformPoint (currentSwimZoneTransform.position).y; if (showDebugPrint) { print (distanceToSurfaceWithSign); } currentDistanceToSurface = Mathf.Abs (distanceToSurfaceWithSign); if (showDebugPrint) { print ("vertical speed " + verticalSpeed); } checkSurfaceOnEnterWaterResult = true; if (Mathf.Abs (verticalSpeed) < minSpeedToSetSwimOnSurfaceState && currentDistanceToSurface < 5) { overridingMovementToSurfaceActive = false; checkIfCloseToSurface = false; setDivingState (false); checkIfDivingState = false; if (showDebugPrint) { print ("starting on suface " + verticalSpeed); } setMovementToSurfaceOnEnterWaterActive = true; } else { if (Mathf.Abs (verticalSpeed) < maxSpeedToMoveToSurfaceOnSwimEnabled && currentDistanceToSurface < 5) { if (showDebugPrint) { print ("return to surface"); } checkingToActivateMovementToSurfaceAutomaticallyActive = true; overridingMovementToSurfaceActive = true; enableOrDisableVerticalMovementUp (true); checkIfDivingState = false; } } } } } if (checkIfDivingState) { verticalSpeed = playerTransform.InverseTransformDirection (mainRigidbody.linearVelocity).y; if (showDebugPrint) { print ("checkIfDivingState result " + checkIfDivingState + " " + verticalSpeed); } if (Mathf.Abs (verticalSpeed) > maxSpeedToMoveToSurfaceOnSwimEnabled || !checkSurfaceOnEnterWaterResult) { setDivingState (true); if (showDebugPrint) { print ("setting diving state"); } } else { currentDistanceToSurface = Mathf.Abs (playerTransform.InverseTransformPoint (currentSwimZoneTransform.position).y); if (currentDistanceToSurface > 3) { setDivingState (true); if (showDebugPrint) { print ("setting diving state"); } } } } lastTimeSwimActive = Time.time; } else { if (overridingMovementToSurfaceActive) { playerInput.overrideInputValues (Vector3.zero, false); } overridingMovementToSurfaceActive = false; currentlyOnSurface = false; } if (turnAndForwardAnimatorValuesPaused) { mainPlayerController.setTurnAndForwardAnimatorValuesPausedState (false); turnAndForwardAnimatorValuesPaused = false; } updateCurrentStateIDValue (); enteringOnWaterFromWalking = false; if (!swimSystemActive) { if (useEventOnCameraUnderwaterEffect) { if (cameraBelowWater) { if (!ignoreDisableCameraBelowWaterStateActive) { eventOnCameraUnderWaterEnd.Invoke (); cameraBelowWater = false; } } } } ignoreDisableCameraBelowWaterStateActive = false; mainPlayerController.setFootStepManagerState (state); setExtraCharacterStateOnSwim (state); } public void enableOrDisableTurbo (bool state) { if (turboActive == state) { return; } if (state && canUseTurboPausedState) { return; } turboActive = state; mainPlayerController.enableOrDisableFlyModeTurbo (turboActive); if (turboActive) { mainPlayerController.setCurrentAirSpeedValue (2); } else { mainPlayerController.setCurrentAirSpeedValue (1); } if (useEventUseTurboOnSwim) { if (state) { eventOnStarTurboOnSwim.Invoke (); } else { eventOnEndTurboOnSwim.Invoke (); } } } public void setCanUseTurboPausedState (bool state) { if (!state && turboActive) { enableOrDisableTurbo (false); } canUseTurboPausedState = state; } public override void disableExternalControllerState () { bool disableSwimStateResult = true; if (keepSwimStateActiveOnDeath) { // print (mainPlayerController.checkIfPlayerDeadFromHealthComponent ()); if (mainPlayerController.checkIfPlayerDeadFromHealthComponent ()) { disableSwimStateResult = false; } } if (disableSwimStateResult) { setSwimSystemActivestate (false); } } public void inputChangeTurboState (bool state) { if (overridingMovementToSurfaceActive) { return; } if (swimSystemActive && turboEnabled) { enableOrDisableTurbo (state); } } public void inputMoveUp (bool state) { if (overridingMovementToSurfaceActive) { return; } if (swimSystemActive && moveUpAndDownEnabled) { if (currentlyOnSurface && state) { if (canJumpWhenSwimmingOnSurface) { bool activateRegularJump = true; bool surfaceToLedgeDetected = false; if (onlyClimbOnCloseSurfaces) { Vector3 raycastPosition = playerTransform.position + (1.5f * playerTransform.up); Vector3 raycastDirection = playerTransform.forward; Vector3 climbSurfaceTargetPosition = Vector3.zero; RaycastHit hit = new RaycastHit (); if (Physics.Raycast (raycastPosition, raycastDirection, out hit, 0.5f, layerForGroundDetection)) { float angleWithSurface = Vector3.SignedAngle (playerTransform.up, hit.normal, playerTransform.right); bool surfaceAngleNotValid = false; float angleWithSurfaceAux = Mathf.Abs (Mathf.Abs (angleWithSurface) - 90); if (showDebugPrint) { print ("angle with surface " + angleWithSurface + " " + angleWithSurfaceAux); } if (angleWithSurfaceAux > maxAngleDifferenceOnSurfaceToClimb) { surfaceAngleNotValid = true; } if (!surfaceAngleNotValid) { //if not surface is found, then Debug.DrawRay (raycastPosition, raycastDirection, Color.green); //search for the closest point surface of that ledge, by lowering the raycast position until a surface is found surfaceToLedgeDetected = false; RaycastHit newHit = new RaycastHit (); int numberOfLoops = 0; Vector3 newRaycastPosition = raycastPosition; while (!surfaceToLedgeDetected && numberOfLoops < 100) { Debug.DrawRay (newRaycastPosition, raycastDirection, Color.blue, 4); if (Physics.Raycast (newRaycastPosition, raycastDirection, out newHit, 2, layerForGroundDetection)) { hit = newHit; newRaycastPosition += 0.04f * playerTransform.up; } else { climbSurfaceTargetPosition = hit.point + 0.04f * playerTransform.up; surfaceToLedgeDetected = true; } numberOfLoops++; } if (GKC_Utils.distance (raycastPosition, climbSurfaceTargetPosition) > maxClimbSurfaceHeight) { surfaceToLedgeDetected = false; if (showDebugPrint) { print ("surface to climb detected too far away"); } } if (surfaceToLedgeDetected) { climbSurfaceActionSystemTransform.position = climbSurfaceTargetPosition; climbSurfaceActionSystemTransform.rotation = Quaternion.LookRotation (-hit.normal); climbSurfaceActionSystemTransform.gameObject.SetActive (true); eventToActivateClimbSurfaceActionSystem.Invoke (playerTransform.gameObject); if (showDebugPrint) { print ("surface to climb detected"); } } else { if (showDebugPrint) { print ("surface to climb not detected"); } } } } else { if (showDebugPrint) { print ("surface to climb not detected"); } } if (surfaceToLedgeDetected) { activateRegularJump = false; } else { if (!allowJumpOnSwimIfNoCloseSurfaceToClimbFound) { activateRegularJump = false; } } } if (activateRegularJump) { mainPlayerController.useJumpPlatform (jumpForceOnSurface * playerTransform.up, ForceMode.Impulse); return; } } } enableOrDisableVerticalMovementUp (state); } } public void inputMoveDown (bool state) { if (overridingMovementToSurfaceActive) { return; } if (swimSystemActive && moveUpAndDownEnabled) { enableOrDisableVerticalMovementDown (state); if (!currentlyDiving) { setDivingState (true); } } } void enableOrDisableVerticalMovementUp (bool state) { if (movingUp && !state) { playerInput.overrideInputValues (Vector3.zero, false); } movingUp = state; if (movingUp) { checkIfLookingInCameraDirection (); movingDown = false; } updateCurrentStateIDValue (); } void enableOrDisableVerticalMovementDown (bool state) { if (movingDown && !state) { playerInput.overrideInputValues (Vector3.zero, false); } movingDown = state; if (movingDown) { checkIfLookingInCameraDirection (); movingUp = false; } updateCurrentStateIDValue (); } void checkIfLookingInCameraDirection () { float angleWithCamera = Vector3.Angle (playerTransform.forward, playerCameraTransform.forward); if (angleWithCamera < 90) { lookingInCameraDirection = true; } else { lookingInCameraDirection = false; } if (showDebugPrint) { print (angleWithCamera + " " + lookingInCameraDirection); } } public void setSwimZoneTransform (Transform newSwimZoneTransform) { currentSwimZoneTransform = newSwimZoneTransform; } public void setSwimTrigger (Collider newSwimTrigger) { currentSwimTrigger = newSwimTrigger; currentSwimTriggerLocated = currentSwimTrigger != null; } public bool isSwimTriggerListEmpty () { if (swimTriggerList.Count > 0) { return false; } return true; } public void addSwimTrigger (Collider newTrigger) { if (newTrigger == null) { return; } if (!swimTriggerList.Contains (newTrigger)) { swimTriggerList.Add (newTrigger); } } public void removeSwimTrigger (Collider newTrigger) { if (newTrigger == null) { return; } if (swimTriggerList.Contains (newTrigger)) { swimTriggerList.Remove (newTrigger); } } public void clearSwimTriggerList () { if (swimTriggerList.Count > 0) { swimTriggerList.Clear (); } } public void setCurrentWaterSurfaceSystem (waterSurfaceSystem newWaterSurfaceSystem) { currentWaterSurfaceSystem = newWaterSurfaceSystem; updateSurfaceTransformDynamically = currentWaterSurfaceSystem != null; } public void setDivingState (bool state) { bool previouslyDiving = currentlyDiving; currentlyDiving = state; currentlyOnSurface = !currentlyDiving; if (useEventsOnDiveStateChange) { if (currentlyDiving) { eventOnStartDive.Invoke (); } else { eventOnEndDive.Invoke (); } } updateCurrentStateIDValue (); if (showDebugPrint) { print ("setting diving state as " + currentlyDiving + " is character on surface " + currentlyOnSurface); } reachingSurfaceFromMovingInput = false; if (swimSystemActive) { if (previouslyDiving) { if (currentlyOnSurface) { if (useEventOnChangeDiveToSwim) { eventOnChangeDiveToSwim.Invoke (); } } } else { if (currentlyDiving) { if (useEventOnChangeSwimToDive) { eventOnChangeSwimToDive.Invoke (); } } } } } void updateCurrentStateIDValue () { currentStatID = -1; if (swimSystemActive) { if (currentlyDiving) { if (movingUp) { currentStatID = movingUpStateID; } else if (movingDown) { currentStatID = movingDownStateID; } else { currentStatID = diveStateID; } } if (currentlyOnSurface) { currentStatID = swimStateID; } if (walkingOnWater) { currentStatID = regularIdleID; } } else { currentStatID = regularIdleID; } mainPlayerController.setCurrentIdleIDValueFloat (currentStatID); } public void setEnableExternalForceOnSwimModeState (bool state) { if (swimSystemActive) { mainPlayerController.setEnableExternalForceOnSwimModeState (state); } } public override void checkPauseStateDuringExternalForceOrBehavior () { swimForcesPaused = true; } public override void checkResumeStateAfterExternalForceOrBehavior () { if (swimSystemActive) { setCurrentPlayerActionSystemCustomActionCategoryID (); swimForcesPaused = false; } } public override void setCurrentPlayerActionSystemCustomActionCategoryID () { if (behaviorCurrentlyActive) { if (customActionCategoryID > -1) { mainPlayerController.setCurrentCustomActionCategoryID (customActionCategoryID); } } else { if (regularActionCategoryID > -1) { mainPlayerController.setCurrentCustomActionCategoryID (regularActionCategoryID); } } } }