void FixedUpdate() { // Check if on a solid surface grounded = (collisionFlags & CollisionFlags.Below) != 0; // Clear movement if (cancelMovement) { moveDirection = Vector3.zero; cancelMovement = false; groundMotor.ClearActivePlatform(); acrobatMotor.ClearFallingDamage(); return; } // Handle freeze movement if (freezeMotor > 0) { freezeMotor -= Time.deltaTime; if (freezeMotor <= 0) { freezeMotor = 0; CancelMovement = true; } return; } playerScanner.FindHeadHit(new Ray(controller.transform.position, Vector3.up)); playerScanner.SetHitSomethingInFront(); // Check if should hang hangingMotor.HangingChecks(); // Handle Rappeling rappelMotor.RappelChecks(); // Handle climbing climbingMotor.ClimbingCheck(); // Do nothing if player levitating/swimming or climbing - replacement motor will take over movement for levitating/swimming if (levitateMotor && (levitateMotor.IsLevitating || levitateMotor.IsSwimming) || climbingMotor.IsClimbing || hangingMotor.IsHanging) { moveDirection = Vector3.zero; return; } if (climbingMotor.WallEject) { // True in terms of the player having their feet on solid surface. grounded = true; } if (grounded) { acrobatMotor.Jumping = false; acrobatMotor.CheckFallingDamage(); // checks if sliding and applies movement to moveDirection if true frictionMotor.GroundedMovement(ref moveDirection); acrobatMotor.HandleJumpInput(ref moveDirection); } else { acrobatMotor.CheckInitFall(ref moveDirection); acrobatMotor.CheckAirControl(ref moveDirection, speed); } playerScanner.FindStep(moveDirection); acrobatMotor.ApplyGravity(ref moveDirection); acrobatMotor.HitHead(ref moveDirection); groundMotor.MoveWithMovingPlatform(moveDirection); }
/// <summary> /// Perform Climbing Movement /// </summary> private void ClimbMovement() { // Try to move along wall and forwards at same time // This helps player maintain collision checks with the wall and step onto the ledge once it's found // if strafing to either side, this will be set so we can check for wrap-around corners. Vector3 checkDirection = Vector3.zero; if (!isSlipping) { float climbScalar = speedChanger.GetClimbingSpeed(playerMotor.Speed); moveDirection = Vector3.zero; bool movedForward = InputManager.Instance.HasAction(InputManager.Actions.MoveForwards); bool movedBackward = InputManager.Instance.HasAction(InputManager.Actions.MoveBackwards); bool movedLeft = InputManager.Instance.HasAction(InputManager.Actions.MoveLeft); bool movedRight = InputManager.Instance.HasAction(InputManager.Actions.MoveRight); if (DaggerfallUnity.Settings.AdvancedClimbing) { bool hitSomethingInFront = moveScanner.HitSomethingInFront; #region Vertical Climbing // TODO: Disallow rappel when pressing back if auto climbing if (!movedBackward && !atOutsideCorner && (movedForward || !hitSomethingInFront)) { // TODO: devise horizontal distance-based solution to terminate forward movement // It may fix the problem of climbing to the top of gabled roofs. if (!overrideSkillCheck) { overrideSkillCheck = !hitSomethingInFront; } moveDirection.y = Vector3.up.y * climbScalar; } else if (movedBackward) { moveDirection.y = Vector3.down.y * climbScalar; } #endregion #region Horizontal Climbing if (movedRight || movedLeft) { float checkScalar = controller.radius + 0.5f; if (movedRight) { checkDirection = Vector3.Cross(Vector3.up, myLedgeDirection).normalized; } else if (movedLeft) { checkDirection = Vector3.Cross(myLedgeDirection, Vector3.up).normalized; } // adjust direction so it can intersect with adjacentWallRay myStrafeRay.direction = checkDirection; Debug.DrawRay(myStrafeRay.origin, myStrafeRay.direction, Color.red); // perform check for adjacent wall GetAdjacentWallInfo(controller.transform.position, checkDirection * checkScalar, movedLeft ? PlayerMoveScanner.RotationDirection.XZClockwise : PlayerMoveScanner.RotationDirection.XZCounterClockwise); Vector3 intersection; Vector3 intersectionOrthogonal; Vector3 wrapDirection = Vector3.zero; // direction to move while wrapping around corner // did we find the wall corner intersection? if (LineLineIntersection(out intersection, myStrafeRay.origin, myStrafeRay.direction, adjacentWallRay.origin, adjacentWallRay.direction)) { intersectionOrthogonal = (-myLedgeDirection - adjacentLedgeDirection).normalized; Debug.DrawRay(intersection, intersectionOrthogonal, Color.yellow); atOutsideCorner = ((myStrafeRay.origin - intersection).magnitude < 0.01f); if (atOutsideCorner) { // perform outside corner wrap if (movedRight) { wrapDirection = Vector3.Cross(intersectionOrthogonal, Vector3.up).normalized; } else if (movedLeft) { wrapDirection = Vector3.Cross(Vector3.up, intersectionOrthogonal).normalized; } } cornerNormalRay = new Ray(intersection, intersectionOrthogonal); } // exiting outside wall corner? if (atInsideCorner || (atOutsideCorner && IsAlmostParallel(wrapDirection, adjacentWallRay.direction))) { myLedgeDirection = adjacentLedgeDirection; wrapDirection = -adjacentWallRay.direction; checkDirection = wrapDirection; atOutsideCorner = false; atInsideCorner = false; } // if at outside corner, use corner-updated directions to wrap around it if (atOutsideCorner) { Debug.DrawRay(intersection, wrapDirection, Color.magenta); moveDirection += wrapDirection * climbScalar; } else // move in wasd direction { moveDirection += checkDirection * climbScalar; } } #endregion // need to add horizontal movement towards wall for collision moveDirection.x += wallDirection.x * playerMotor.Speed; moveDirection.z += wallDirection.z * playerMotor.Speed; } else // do normal climbing { moveDirection = wallDirection * playerMotor.Speed; moveDirection.y = Vector3.up.y * climbScalar; } } else // do slipping down wall { acrobatMotor.CheckInitFall(ref moveDirection); acrobatMotor.ApplyGravity(ref moveDirection); } // finalize climbing movement controller.Move(moveDirection * Time.deltaTime); playerMotor.CollisionFlags = controller.collisionFlags; }
void FixedUpdate() { // Clear movement if (cancelMovement) { moveDirection = Vector3.zero; cancelMovement = false; groundMotor.ClearActivePlatform(); acrobatMotor.ClearFallingDamage(); return; } // Handle freeze movement if (freezeMotor > 0) { freezeMotor -= Time.deltaTime; if (freezeMotor <= 0) { freezeMotor = 0; CancelMovement = true; } return; } // Handle climbing climbingMotor.ClimbingCheck(ref collisionFlags); if (climbingMotor.IsClimbing) { acrobatMotor.Falling = false; } // Do nothing if player levitating/swimming or climbing - replacement motor will take over movement for levitating/swimming if (levitateMotor && (levitateMotor.IsLevitating || levitateMotor.IsSwimming) || climbingMotor.IsClimbing) { return; } // Player assumed to be in movement for now standingStill = false; if (grounded) { // Set standing still while grounded flag // Casting moveDirection to a Vector2 so constant downward force of gravity not included in magnitude standingStill = (new Vector2(moveDirection.x, moveDirection.z).magnitude == 0); acrobatMotor.Jumping = false; acrobatMotor.CheckFallingDamage(); // checks if sliding and applies movement to moveDirection if true frictionMotor.MoveIfSliding(ref moveDirection); acrobatMotor.HandleJumpInput(ref moveDirection); } else { acrobatMotor.CheckInitFall(); acrobatMotor.CheckAirControl(ref moveDirection, speed); } acrobatMotor.ApplyGravity(ref moveDirection); // If we hit something above us AND we are moving up, reverse vertical movement if ((controller.collisionFlags & CollisionFlags.Above) != 0) { if (moveDirection.y > 0) { moveDirection.y = -moveDirection.y; } } groundMotor.MoveOnGround(moveDirection, ref collisionFlags, ref grounded); }
/// <summary> /// Perform Climbing Movement and call Skill Checks /// </summary> private void ClimbMovement() { // Try to move up and forwards at same time // This helps player smoothly mantle the top of whatever they are climbing // Horizontal distance check in ClimbingCheck() will cancel climb once player mantles // This has the happy side effect of fixing issue where player climbs endlessly into sky or starting to climb when not facing wall // Climbing effect states "target can climb twice as well" - doubling climbing speed float climbingBoost = player.IsEnhancedClimbing ? 2f : 1f; if (!isSlipping) { float climbScalar = (playerMotor.Speed / 3) * climbingBoost; moveDirection = ledgeDirection * playerMotor.Speed; if (DaggerfallUnity.Settings.AdvancedClimbing) { if (InputManager.Instance.HasAction(InputManager.Actions.MoveForwards)) { moveDirection.y = Vector3.up.y * climbScalar; } else if (InputManager.Instance.HasAction(InputManager.Actions.MoveBackwards)) { moveDirection.y = Vector3.down.y * climbScalar; } if (InputManager.Instance.HasAction(InputManager.Actions.MoveRight)) { moveDirection += Vector3.Cross(Vector3.up, ledgeDirection).normalized *climbScalar; } else if (InputManager.Instance.HasAction(InputManager.Actions.MoveLeft)) { moveDirection += Vector3.Cross(ledgeDirection, Vector3.up).normalized *climbScalar; } } else { moveDirection.y = Vector3.up.y * climbScalar; } } else { acrobatMotor.CheckInitFall(); acrobatMotor.ApplyGravity(ref moveDirection); } // HACK: Overwrite moveDirection to prevent error where player is shot into air and transformed to tile origin // @MeteoricDragon - This cancels advanced climbing and slipping for now, but I just wanted bug removed from next round of builds // This clears bug without directly changing your logic above, then you can then fix properly when possible :) // This code block can just be removed later once problem is resolved if (InputManager.Instance.HasAction(InputManager.Actions.MoveForwards)) { // Climb upwards float climbScalar = (playerMotor.Speed / 3) * climbingBoost; moveDirection.y = Vector3.up.y * climbScalar; } else { // Stop climbing isSlipping = false; isClimbing = false; return; } controller.Move(moveDirection * Time.deltaTime); playerMotor.CollisionFlags = controller.collisionFlags; }