Why can´t I walk while crouching? - unity3d

So, apperently I am trying to make a game using unity.
So far so good.
But there is one problem: Everytime I crouch or slide, I cant move anymore until I stand up again.
I ve tried everything.
I ve even tried removing the sliding completely or writing a whole new code, yet nothing works.
Sorry for the long code, but I dont know anymore ;-;
using System;
using UnityEngine;
public class PlayerMovement : MonoBehaviour {
//Assingables
public Transform playerCam;
public Transform orientation;
//Other
private Rigidbody rb;
//Rotation and look
private float xRotation;
private float sensitivity = 50f;
public float sensMultiplier = 1f;
//Movement
public float moveSpeed = 4500;
public float maxSpeed = 10;
public bool grounded;
public LayerMask whatIsGround;
public float counterMovement = 0.175f;
private float threshold = 0.01f;
public float maxSlopeAngle = 35f;
public float sprintspeed = 20f;
public float speedOrigin = 10f;
//Crouch & Slide
private Vector3 crouchScale = new Vector3(1, 0.5f, 1);
private Vector3 playerScale;
public float slideForce = 0;
public float slideCounterMovement = 0.2f;
//Jumping
private bool readyToJump = true;
private float jumpCooldown = 0.25f;
public float jumpForce = 300f;
//Input
float x, y;
bool jumping, sprinting, crouching;
//Sliding
private Vector3 normalVector = Vector3.up;
private Vector3 wallNormalVector;
void Awake() {
rb = GetComponent<Rigidbody>();
}
void Start() {
playerScale = transform.localScale;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
private void FixedUpdate() {
Movement();
}
private void Update() {
MyInput();
Look();
}
/// <summary>
/// Find user input. Should put this in its own class but im lazy
/// </summary>
private void MyInput() {
x = Input.GetAxisRaw("Horizontal");
y = Input.GetAxisRaw("Vertical");
jumping = Input.GetButton("Jump");
crouching = Input.GetKey(KeyCode.LeftControl);
//Sprinting
if (Input.GetKeyDown(KeyCode.LeftShift) && !crouching)
StartSprint();
if (Input.GetKeyUp(KeyCode.LeftShift))
StopSprint();
//Crouching
if (Input.GetKeyDown(KeyCode.LeftControl))
StartCrouch();
if (Input.GetKeyUp(KeyCode.LeftControl))
StopCrouch();
}
private void StartCrouch() {
transform.localScale = crouchScale;
transform.position = new Vector3(transform.position.x, transform.position.y - 0.5f, transform.position.z);
maxSpeed = 7f;
}
private void StopCrouch() {
transform.localScale = playerScale;
transform.position = new Vector3(transform.position.x, transform.position.y + 0.5f, transform.position.z);
maxSpeed = speedOrigin;
}
//Sprinting
private void StartSprint() {
maxSpeed = sprintspeed;
}
private void StopSprint() {
maxSpeed = speedOrigin;
}
private void Movement() {
//Extra gravity
rb.AddForce(Vector3.down * Time.deltaTime * 10);
//Find actual velocity relative to where player is looking
Vector2 mag = FindVelRelativeToLook();
float xMag = mag.x, yMag = mag.y;
//Counteract sliding and sloppy movement
CounterMovement(x, y, mag);
//If holding jump && ready to jump, then jump
if (readyToJump && jumping) Jump();
//Set max speed
float maxSpeed = this.maxSpeed;
//If sliding down a ramp, add force down so player stays grounded and also builds speed
if (crouching && grounded && readyToJump) {
rb.AddForce(Vector3.down * Time.deltaTime * 3000);
return;
}
//If speed is larger than maxspeed, cancel out the input so you don't go over max speed
if (x > 0 && xMag > maxSpeed) x = 0;
if (x < 0 && xMag < -maxSpeed) x = 0;
if (y > 0 && yMag > maxSpeed) y = 0;
if (y < 0 && yMag < -maxSpeed) y = 0;
//Some multipliers
float multiplier = 1f, multiplierV = 1f;
// Movement in air
if (!grounded) {
maxSpeed = 8f;
}
// Movement while crouching
if (grounded && crouching) maxSpeed = 7f;
//Apply forces to move player
rb.AddForce(orientation.transform.forward * y * moveSpeed * Time.deltaTime * multiplier * multiplierV);
rb.AddForce(orientation.transform.right * x * moveSpeed * Time.deltaTime * multiplier);
}
private void Jump() {
if (grounded && readyToJump) {
readyToJump = false;
//Add jump forces
rb.AddForce(Vector2.up * jumpForce * 1.5f);
rb.AddForce(normalVector * jumpForce * 0.5f);
//If jumping while falling, reset y velocity.
Vector3 vel = rb.velocity;
if (rb.velocity.y < 0.5f)
rb.velocity = new Vector3(vel.x, 0, vel.z);
else if (rb.velocity.y > 0)
rb.velocity = new Vector3(vel.x, vel.y / 2, vel.z);
Invoke(nameof(ResetJump), jumpCooldown);
}
}
private void ResetJump() {
readyToJump = true;
}
private float desiredX;
private void Look() {
float mouseX = Input.GetAxis("Mouse X") * sensitivity * Time.fixedDeltaTime * sensMultiplier;
float mouseY = Input.GetAxis("Mouse Y") * sensitivity * Time.fixedDeltaTime * sensMultiplier;
//Find current look rotation
Vector3 rot = playerCam.transform.localRotation.eulerAngles;
desiredX = rot.y + mouseX;
//Rotate, and also make sure we dont over- or under-rotate.
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, -90f, 90f);
//Perform the rotations
playerCam.transform.localRotation = Quaternion.Euler(xRotation, desiredX, 0);
orientation.transform.localRotation = Quaternion.Euler(0, desiredX, 0);
}
private void CounterMovement(float x, float y, Vector2 mag) {
if (!grounded || jumping) return;
//Slow down sliding
if (crouching) {
rb.AddForce(moveSpeed * Time.deltaTime * -rb.velocity.normalized * slideCounterMovement);
return;
}
//Counter movement
if (Math.Abs(mag.x) > threshold && Math.Abs(x) < 0.05f || (mag.x < -threshold && x > 0) || (mag.x > threshold && x < 0)) {
rb.AddForce(moveSpeed * orientation.transform.right * Time.deltaTime * -mag.x * counterMovement);
}
if (Math.Abs(mag.y) > threshold && Math.Abs(y) < 0.05f || (mag.y < -threshold && y > 0) || (mag.y > threshold && y < 0)) {
rb.AddForce(moveSpeed * orientation.transform.forward * Time.deltaTime * -mag.y * counterMovement);
}
//Limit diagonal running. This will also cause a full stop if sliding fast and un-crouching, so not optimal.
if (Mathf.Sqrt((Mathf.Pow(rb.velocity.x, 2) + Mathf.Pow(rb.velocity.z, 2))) > maxSpeed) {
float fallspeed = rb.velocity.y;
Vector3 n = rb.velocity.normalized * maxSpeed;
rb.velocity = new Vector3(n.x, fallspeed, n.z);
}
}
/// <summary>
/// Find the velocity relative to where the player is looking
/// Useful for vectors calculations regarding movement and limiting movement
/// </summary>
/// <returns></returns>
public Vector2 FindVelRelativeToLook() {
float lookAngle = orientation.transform.eulerAngles.y;
float moveAngle = Mathf.Atan2(rb.velocity.x, rb.velocity.z) * Mathf.Rad2Deg;
float u = Mathf.DeltaAngle(lookAngle, moveAngle);
float v = 90 - u;
float magnitue = rb.velocity.magnitude;
float yMag = magnitue * Mathf.Cos(u * Mathf.Deg2Rad);
float xMag = magnitue * Mathf.Cos(v * Mathf.Deg2Rad);
return new Vector2(xMag, yMag);
}
private bool IsFloor(Vector3 v) {
float angle = Vector3.Angle(Vector3.up, v);
return angle < maxSlopeAngle;
}
private bool cancellingGrounded;
/// <summary>
/// Handle ground detection
/// </summary>
private void OnCollisionStay(Collision other) {
//Make sure we are only checking for walkable layers
int layer = other.gameObject.layer;
if (whatIsGround != (whatIsGround | (1 << layer))) return;
//Iterate through every collision in a physics update
for (int i = 0; i < other.contactCount; i++) {
Vector3 normal = other.contacts[i].normal;
//FLOOR
if (IsFloor(normal)) {
grounded = true;
cancellingGrounded = false;
normalVector = normal;
CancelInvoke(nameof(StopGrounded));
}
}
//Invoke ground/wall cancel, since we can't check normals with CollisionExit
float delay = 3f;
if (!cancellingGrounded) {
cancellingGrounded = true;
Invoke(nameof(StopGrounded), Time.deltaTime * delay);
}
}
private void StopGrounded() {
grounded = false;
}
}

Have you tried to delete the return inside this?
if (crouching && grounded && readyToJump) {
rb.AddForce(Vector3.down * Time.deltaTime * 3000);
return;
}
Because of that, you are not applying force for move your object based on your inputs.

Related

Player jumps a second time by itself after hitting the ground

I'm trying to make a First Person Controller and after I jump, right as the player is about to hit the ground, it jumps a second time by itself. This doesn't seem to be the case when the player lands on ground higher or lower than the ground it originally jumped on.
This is my Player code:
`
using System;
using UnityEngine;
using UnityEngine.InputSystem;
public class Player : MonoBehaviour
{
[SerializeField] float mouseSensitivity = 3f;
[SerializeField] float walkingSpeed = 10f;
[SerializeField] float flyingSpeed = 15;
[SerializeField] float climbingSpeed = 5f;
[SerializeField] float mass = 1f;
[SerializeField] float acceleration = 20f;
[SerializeField] float worldBottomBoundary = -100f;
public Transform cameraTransform;
public bool IsGrounded => controller.isGrounded;
public float Height
{
get => controller.height;
set => controller.height = value;
}
public event Action OnBeforeMove;
public event Action<bool> OnGroundStateChange;
internal float movementSpeedMultiplier;
State _state;
public State CurrentState
{
get => _state;
set
{
_state = value;
velocity = Vector3.zero;
}
}
public enum State
{
Walking,
Flying,
Climbing
}
CharacterController controller;
internal Vector3 velocity;
Vector2 look;
(Vector3, Quaternion) initialPositionAndRotation;
bool wasGrounded;
PlayerInput playerInput;
InputAction moveAction;
InputAction lookAction;
InputAction flyUpDownAction;
void Awake()
{
controller = GetComponent<CharacterController>();
playerInput = GetComponent<PlayerInput>();
moveAction = playerInput.actions["move"];
lookAction = playerInput.actions["look"];
flyUpDownAction = playerInput.actions["flyUpDown"];
}
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
initialPositionAndRotation = (transform.position, transform.rotation);
}
public void Teleport(Vector3 position, Quaternion rotation)
{
transform.position = position;
Physics.SyncTransforms();
look.x = rotation.eulerAngles.y;
look.y = rotation.eulerAngles.z;
velocity = Vector3.zero;
}
void Update()
{
movementSpeedMultiplier = 1f;
switch (CurrentState)
{
case State.Walking:
UpdateGround();
UpdateGravity();
UpdateMovement();
UpdateLook();
CheckBounds();
break;
case State.Flying:
UpdateMovementFlying();
UpdateLook();
break;
case State.Climbing:
UpdateMovementClimbing();
UpdateLook();
break;
}
}
void CheckBounds()
{
if (transform.position.y < worldBottomBoundary)
{
var (position, rotation) = initialPositionAndRotation;
Teleport(position, rotation);
}
}
void UpdateGround()
{
if (wasGrounded != IsGrounded)
{
OnGroundStateChange?.Invoke(IsGrounded);
wasGrounded = IsGrounded;
}
}
void UpdateGravity()
{
var gravity = Physics.gravity * mass * Time.deltaTime;
velocity.y = IsGrounded ? -1f : velocity.y + gravity.y;
}
Vector3 GetMovementInput(float speed, bool horizontal = true)
{
var moveInput = moveAction.ReadValue<Vector2>();
var flyUpDownInput = flyUpDownAction.ReadValue<float>();
var input = new Vector3();
var referenceTransform = horizontal ? transform : cameraTransform;
input += referenceTransform.forward * moveInput.y;
input += referenceTransform.right * moveInput.x;
if (!horizontal)
{
input += transform.up * flyUpDownInput;
}
input = Vector3.ClampMagnitude(input, 1f);
input *= speed * movementSpeedMultiplier;
return input;
}
void UpdateMovement()
{
OnBeforeMove?.Invoke();
var input = GetMovementInput(walkingSpeed);
var factor = acceleration * Time.deltaTime;
velocity.x = Mathf.Lerp(velocity.x, input.x, factor);
velocity.z = Mathf.Lerp(velocity.z, input.z, factor);
controller.Move(velocity * Time.deltaTime);
}
void UpdateMovementFlying()
{
var input = GetMovementInput(flyingSpeed, false);
var factor = acceleration * Time.deltaTime;
velocity = Vector3.Lerp(velocity, input, factor);
controller.Move(velocity * Time.deltaTime);
}
void UpdateMovementClimbing()
{
var input = GetMovementInput(climbingSpeed, false);
var forwardInputFactor = Vector3.Dot(transform.forward, input.normalized);
if (forwardInputFactor > 0)
{
input.x = input.x * .5f;
input.z = input.z * .5f;
if (Mathf.Abs(input.y) > .2f)
{
input.y = Mathf.Sign(input.y) * climbingSpeed;
}
}
else
{
input.y = 0;
input.x = input.x * 3f;
input.z = input.z * 3f;
}
var factor = acceleration * Time.deltaTime;
velocity = Vector3.Lerp(velocity, input, factor);
controller.Move(velocity * Time.deltaTime);
}
void UpdateLook()
{
var lookInput = lookAction.ReadValue<Vector2>();
look.x += lookInput.x * mouseSensitivity;
look.y += lookInput.y * mouseSensitivity;
look.y = Mathf.Clamp(look.y, -90, 90f);
cameraTransform.localRotation = Quaternion.Euler(-look.y, 0, 0);
transform.localRotation = Quaternion.Euler(0, look.x, 0);
}
void OnToggleFlying()
{
CurrentState = CurrentState == State.Flying ? State.Walking : State.Flying;
}
}
`
And this is my PlayerJumping code:
`
using UnityEngine;
[RequireComponent(typeof(Player))]
public class PlayerJumping : MonoBehaviour
{
[SerializeField] float jumpSpeed = 5f;
[SerializeField] float jumpPressBufferTime = .05f;
[SerializeField] float jumpGroundGraceTime = .2f;
[SerializeField] int maxJumps = 1;
Player player;
bool tryingToJump;
float lastJumpPressTime;
float lastGroundedTime;
int jumps;
void Awake()
{
player = GetComponent<Player>();
}
void OnEnable()
{
player.OnBeforeMove += OnBeforeMove;
player.OnGroundStateChange += OnGroundStateChange;
}
void OnDisable()
{
player.OnBeforeMove -= OnBeforeMove;
player.OnGroundStateChange -= OnGroundStateChange;
}
void OnJump()
{
tryingToJump = true;
lastJumpPressTime = Time.time;
}
void OnBeforeMove()
{
if (player.IsGrounded) jumps = 0;
var wasTryingToJump = Time.time - lastJumpPressTime < jumpPressBufferTime;
var wasGrounded = Time.time - lastGroundedTime < jumpGroundGraceTime;
var isOrWasTryingToJump = tryingToJump || (wasTryingToJump && player.IsGrounded);
var isOrWasGrounded = player.IsGrounded || wasGrounded;
var jumpAllowed = jumps < maxJumps;
if (
jumpAllowed && isOrWasTryingToJump && isOrWasGrounded
|| jumpAllowed && tryingToJump
)
{
player.velocity.y += jumpSpeed;
jumps++;
}
tryingToJump = false;
}
void OnGroundStateChange(bool isGrounded)
{
if (!isGrounded) lastGroundedTime = Time.time;
}
}
`
Although to be honest, I've checked a million times and I'm starting to believe the problem isn't in the code but in the inspector, but don't let that cloud your judgement because I can be pretty stupid at times. Do you have any ideas?

how do i stop my character moving to far after slope

after my character goes up a slope or stairs while sprinting it keeps the momentum and usually flies over the platform at the top because hes moving too fast how would i get him to stay on the ground coming out of a slope but still be able to jump
im using a rigid body and heres the script im using to move the character
{
[Header("Movement")]
private float moveSpeed;
public float walkSpeed;
public float sprintSpeed;
public float slideSpeed;
private float desiredMoveSpeed;
private float lastDesiredMoveSpeed;
public float speedIncreaseMultiplier;
public float slopeIncreaseMultiplier;
public float groundDrag;
[Header("Jumping")]
public float jumpForce;
public float jumpCooldown;
public float airMultiplier;
bool readyToJump;
[Header("Crouching")]
public float crouchSpeed;
public float crouchYScale;
private float startYScale;
[Header("Keybinds")]
public KeyCode jumpKey = KeyCode.Space;
public KeyCode sprintKey = KeyCode.LeftShift;
public KeyCode crouchKey = KeyCode.LeftControl;
[Header("Ground Check")]
public float playerHeight;
public LayerMask whatIsGround;
bool grounded;
[Header("Slope Handling")]
public float maxSlopeAngle;
private RaycastHit slopeHit;
private bool exitingSlope;
public Rigidbody playerRb;
public Transform orientation;
float horizontalInput;
float verticalInput;
Vector3 moveDirection;
Rigidbody rb;
public MovementState state;
public enum MovementState
{
walking,
sprinting,
crouching,
sliding,
air
}
public bool sliding;
private void Start()
{
rb = GetComponent<Rigidbody>();
rb.freezeRotation = true;
readyToJump = true;
startYScale = transform.localScale.y;
}
private void Update()
{
// ground check
grounded = Physics.Raycast(transform.position, Vector3.down, playerHeight * 0.5f + 0.2f, whatIsGround);
MyInput();
SpeedControl();
StateHandler();
// handle drag
if (grounded)
rb.drag = groundDrag;
else
rb.drag = 0;
}
private void FixedUpdate()
{
MovePlayer();
}
private void MyInput()
{
horizontalInput = Input.GetAxisRaw("Horizontal");
verticalInput = Input.GetAxisRaw("Vertical");
// when to jump
if (Input.GetKey(jumpKey) && readyToJump && grounded)
{
readyToJump = false;
Jump();
Invoke(nameof(ResetJump), jumpCooldown);
}
// start crouch
if (Input.GetKeyDown(crouchKey))
{
transform.localScale = new Vector3(transform.localScale.x, crouchYScale, transform.localScale.z);
rb.AddForce(Vector3.down * 5f, ForceMode.Impulse);
}
// stop crouch
if (Input.GetKeyUp(crouchKey))
{
transform.localScale = new Vector3(transform.localScale.x, startYScale, transform.localScale.z);
}
}
private void StateHandler()
{
// Mode - Sliding
if (sliding)
{
state = MovementState.sliding;
if (OnSlope() && rb.velocity.y < 0.1f)
desiredMoveSpeed = slideSpeed;
else
desiredMoveSpeed = sprintSpeed;
}
// Mode - Crouching
else if (Input.GetKey(crouchKey))
{
state = MovementState.crouching;
desiredMoveSpeed = crouchSpeed;
}
// Mode - Sprinting
else if (grounded && Input.GetKey(sprintKey))
{
state = MovementState.sprinting;
desiredMoveSpeed = sprintSpeed;
}
// Mode - Walking
else if (grounded)
{
state = MovementState.walking;
desiredMoveSpeed = walkSpeed;
}
// Mode - Air
else
{
state = MovementState.air;
}
// check if desiredMoveSpeed has changed drastically
if (Mathf.Abs(desiredMoveSpeed - lastDesiredMoveSpeed) > 4f && moveSpeed != 0)
{
StopAllCoroutines();
StartCoroutine(SmoothlyLerpMoveSpeed());
}
else
{
moveSpeed = desiredMoveSpeed;
}
lastDesiredMoveSpeed = desiredMoveSpeed;
}
private IEnumerator SmoothlyLerpMoveSpeed()
{
// smoothly lerp movementSpeed to desired value
float time = 0;
float difference = Mathf.Abs(desiredMoveSpeed - moveSpeed);
float startValue = moveSpeed;
while (time < difference)
{
moveSpeed = Mathf.Lerp(startValue, desiredMoveSpeed, time / difference);
if (OnSlope())
{
float slopeAngle = Vector3.Angle(Vector3.up, slopeHit.normal);
float slopeAngleIncrease = 1 + (slopeAngle / 90f);
time += Time.deltaTime * speedIncreaseMultiplier * slopeIncreaseMultiplier * slopeAngleIncrease;
}
else
time += Time.deltaTime * speedIncreaseMultiplier;
yield return null;
}
moveSpeed = desiredMoveSpeed;
}
private void MovePlayer()
{
// calculate movement direction
moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput;
// on slope
if (OnSlope() && !exitingSlope)
{
rb.AddForce(GetSlopeMoveDirection(moveDirection) * moveSpeed * 20f, ForceMode.Force);
if (rb.velocity.y > 0)
rb.AddForce(Vector3.down * 80f, ForceMode.Force);
}
// on ground
else if (grounded)
rb.AddForce(moveDirection.normalized * moveSpeed * 10f, ForceMode.Force);
// in air
else if (!grounded)
rb.AddForce(moveDirection.normalized * moveSpeed * 10f * airMultiplier, ForceMode.Force);
// turn gravity off while on slope
rb.useGravity = !OnSlope();
}
private void SpeedControl()
{
// limiting speed on slope
if (OnSlope() && !exitingSlope)
{
if (rb.velocity.magnitude > moveSpeed)
rb.velocity = rb.velocity.normalized * moveSpeed;
}
// limiting speed on ground or in air
else
{
Vector3 flatVel = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
// limit velocity if needed
if (flatVel.magnitude > moveSpeed)
{
Vector3 limitedVel = flatVel.normalized * moveSpeed;
rb.velocity = new Vector3(limitedVel.x, rb.velocity.y, limitedVel.z);
}
}
}
private void Jump()
{
exitingSlope = true;
// reset y velocity
rb.velocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
rb.AddForce(transform.up * jumpForce, ForceMode.Impulse);
}
private void ResetJump()
{
readyToJump = true;
exitingSlope = false;
}
public bool OnSlope()
{
if (Physics.Raycast(transform.position, Vector3.down, out slopeHit, playerHeight * 0.5f + 0.3f))
{
float angle = Vector3.Angle(Vector3.up, slopeHit.normal);
return angle < maxSlopeAngle && angle != 0;
}
return false;
}
public Vector3 GetSlopeMoveDirection(Vector3 direction)
{
return Vector3.ProjectOnPlane(direction, slopeHit.normal).normalized;
}
}```

Guidance needed to understand quaternion and movetowards of gameobject

Hello I am trying to move a game object in 3d space I have searched the internet and found there are 3 ways to do that using turntoface(euler angles) or quaternion or navmesh agents
My problem is the game object default rotation is changing in using quaternions or move towards.
Can anyone help me understand why it is happening like that.
I want the capsule in slanted position.
//below code is using quaternions
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Guard : MonoBehaviour
{
public float speed = 5;
public float waitTime = .3f;
public float turnSpeed = 90;
public Transform pathHolder;
public Transform target;
void Start()
{
Vector3[] waypoints = new Vector3[pathHolder.childCount];
for (int i = 0; i < waypoints.Length; i++)
{
waypoints = pathHolder.GetChild(i).position;
waypoints = new Vector3(waypoints.x, transform.position.y, waypoints.z);
}
StartCoroutine(FollowPath(waypoints));
}
IEnumerator FollowPath(Vector3[] waypoints)
{
transform.position = waypoints[0];
int targetWaypointIndex = 1;
Vector3 targetWaypoint = waypoints[targetWaypointIndex];
while (true)
{
Quaternion targetRotation = Quaternion.LookRotation(targetWaypoint - transform.position);
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, turnSpeed * Time.deltaTime);
if (transform.rotation == targetRotation)
{
transform.position = Vector3.MoveTowards(transform.position, targetWaypoint, speed * Time.deltaTime);
if (transform.position == targetWaypoint)
{
targetWaypointIndex = (targetWaypointIndex + 1) % waypoints.Length;
targetWaypoint = waypoints[targetWaypointIndex];
yield return new WaitForSeconds(waitTime);
}
}
yield return null;
}
IEnumerator TurnToFace(Vector3 lookTarget)
{
Vector3 dirToLookTarget = (lookTarget - transform.position).normalized;
float targetAngle = 90 - Mathf.Atan2(dirToLookTarget.y, dirToLookTarget.x) * Mathf.Rad2Deg;
while (Mathf.Abs(Mathf.DeltaAngle(transform.eulerAngles.y, targetAngle)) > 0.05f)
{
float angle = Mathf.MoveTowardsAngle(transform.eulerAngles.y, targetAngle, turnSpeed * Time.deltaTime);
transform.eulerAngles = Vector3.up * angle;
yield return null;
}
}
void OnDrawGizmos()
{
Vector3 startPosition = pathHolder.GetChild(0).position;
Vector3 previousPosition = startPosition;
foreach (Transform waypoint in pathHolder)
{
Gizmos.DrawSphere(waypoint.position, .3f);
Gizmos.DrawLine(previousPosition, waypoint.position);
previousPosition = waypoint.position;
}
Gizmos.DrawLine(previousPosition, startPosition);
}
}
}
//below code is using turntoface (euler angles concept)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Guard : MonoBehaviour
{
public float speed = 5;
public float waitTime = .3f;
public float turnSpeed = 90;
public Transform pathHolder;
void Start()
{
Vector3[] waypoints = new Vector3[pathHolder.childCount];
for (int i = 0; i < waypoints.Length; i++)
{
waypoints = pathHolder.GetChild(i).position;
waypoints = new Vector3(waypoints.x, transform.position.y, waypoints.z);
}
StartCoroutine(FollowPath(waypoints));
}
IEnumerator FollowPath(Vector3[] waypoints)
{
transform.position = waypoints[0];
int targetWaypointIndex = 1;
Vector3 targetWaypoint = waypoints[targetWaypointIndex];
transform.LookAt(targetWaypoint);
while (true)
{
transform.position = Vector3.MoveTowards(transform.position, targetWaypoint, speed * Time.deltaTime);
if (transform.position == targetWaypoint)
{
targetWaypointIndex = (targetWaypointIndex + 1) % waypoints.Length;
targetWaypoint = waypoints[targetWaypointIndex];
yield return new WaitForSeconds(waitTime);
yield return StartCoroutine(TurnToFace(targetWaypoint));
}
yield return null;
}
}
IEnumerator TurnToFace(Vector3 lookTarget)
{
Vector3 dirToLookTarget = (lookTarget - transform.position).normalized;
float targetAngle = 90 - Mathf.Atan2(dirToLookTarget.z, dirToLookTarget.x) * Mathf.Rad2Deg;
while (Mathf.DeltaAngle(transform.eulerAngles.y, targetAngle) > 0.05f)
{
float angle = Mathf.MoveTowardsAngle(transform.eulerAngles.y, targetAngle, turnSpeed * Time.deltaTime);
transform.eulerAngles = Vector3.up * angle;
yield return null;
}
}
void OnDrawGizmos()
{
Vector3 startPosition = pathHolder.GetChild(0).position;
Vector3 previousPosition = startPosition;
foreach (Transform waypoint in pathHolder)
{
Gizmos.DrawSphere(waypoint.position, .3f);
Gizmos.DrawLine(previousPosition, waypoint.position);
previousPosition = waypoint.position;
}
Gizmos.DrawLine(previousPosition, startPosition);
}
}
This link has all videos and required output for reference

How to make jump faster when player is running?

I have a character controller movement where the player can walk, run and jump. However, I facing an issue with the jumping. When jumping while walking, the jump speed looks good. But when jumping while running, the jump speed is too slow compared to the run speed. How can I fix this?
Here is my code:
public class PlayerMovement : MonoBehaviour
{
[SerializeField] Transform playerCamera = null;
[SerializeField] float mouseSensitivity = 3.5f;
[SerializeField] float walkSpeed = 10.0f;
[SerializeField] float RunSpeed = 12.0f;
[SerializeField] float gravity = 9.81f;
[SerializeField] bool lockCursor = true;
[SerializeField] [Range(0.0f, 0.5f)] float moveSmoothTime = 0.3f;
public float jumpHeight = 3f;
Vector3 velocity;
public float verticalVelocity;
float cameraPitch = 0.0f;
CharacterController controller = null;
Vector2 currentDir = Vector2.zero;
Vector2 currentDirVelocity = Vector2.zero;
Vector2 currentMouseDelta = Vector2.zero;
Vector2 currentMouseDeltaVelocity = Vector2.zero;
void Start()
{
controller = GetComponent<CharacterController>();
if (lockCursor)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
}
void Update()
{
UpdateMouseLook();
UpdateMovement();
}
void UpdateMouseLook()
{
Vector2 targetMouseDelta = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
currentMouseDelta = Vector2.SmoothDamp(currentMouseDelta, targetMouseDelta, ref currentMouseDeltaVelocity, mouseSmoothTime);
cameraPitch -= currentMouseDelta.y * mouseSensitivity;
cameraPitch = Mathf.Clamp(cameraPitch, -90.0f, 90.0f);
playerCamera.localEulerAngles = Vector3.right * cameraPitch;
transform.Rotate(Vector3.up * currentMouseDelta.x * mouseSensitivity);
}
void UpdateMovement()
{
Vector2 targetDir = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
targetDir.Normalize();
currentDir = Vector2.SmoothDamp(currentDir, targetDir, ref currentDirVelocity, moveSmoothTime);
if (controller.isGrounded)
velocity.y = 0.0f;
velocity += (velocity.y < 0 ? Physics.gravity * 2 : Physics.gravity) * Time.deltaTime;
velocity = (transform.forward * currentDir.y + transform.right * currentDir.x) * walkSpeed + Vector3.up * velocity.y;
if (Input.GetKeyDown(KeyCode.J) && controller.isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
velocity += (velocity.y < 0 ? Physics.gravity * 2 : Physics.gravity) * Time.deltaTime;
}
controller.Move(velocity * Time.deltaTime);
if ((Input.GetKey("left shift") || Input.GetKey("right shift")) && controller.isGrounded && !Input.GetKey(KeyCode.S) && !Input.GetKey(KeyCode.DownArrow))
{
velocity = (transform.forward * currentDir.y + transform.right * currentDir.x) * RunSpeed + Vector3.up * velocity.y;
controller.Move(velocity * Time.deltaTime);
}
}
I optimized the above code and removed some dublicate. I also noticed that the speed problem was due to the presence of isGrounded in the body of the running condition, which made running dependent on being on the ground. This is the player script:
public class Player : MonoBehaviour
{
[SerializeField] Transform playerCamera = null;
[SerializeField] float mouseSensitivity = 3.5f;
[SerializeField] float walkSpeed = 10.0f;
[SerializeField] float runSpeed = 12.0f;
[SerializeField] float gravity = 9.81f;
[SerializeField] bool lockCursor = true;
[SerializeField] [Range(0.0f, 0.5f)] float moveSmoothTime = 0.3f;
public float jumpHeight = 3f;
Vector3 velocity;
private float verticalVelocity;
private Vector3 inputVector;
float cameraPitch = 0.0f;
CharacterController controller = null;
Vector2 currentDir = Vector2.zero;
Vector3 currentDirVelocity = Vector3.zero;
Vector2 currentMouseDelta = Vector2.zero;
Vector2 currentMouseDeltaVelocity = Vector2.zero;
void Start()
{
controller = GetComponent<CharacterController>();
if (lockCursor)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
}
void Update()
{
UpdateMouseLook();
UpdateMovement();
}
void UpdateMouseLook()
{
var targetMouseDelta = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
currentMouseDelta = Vector2.SmoothDamp(currentMouseDelta, targetMouseDelta, ref currentMouseDeltaVelocity, moveSmoothTime);
cameraPitch -= currentMouseDelta.y * mouseSensitivity;
cameraPitch = Mathf.Clamp(cameraPitch, -90.0f, 90.0f);
playerCamera.localEulerAngles = Vector3.right * cameraPitch;
transform.Rotate(Vector3.up * currentMouseDelta.x * mouseSensitivity);
}
void UpdateMovement()
{
// jumping
var isGrounded = Physics.Raycast(transform.position, Vector3.down, 1.1f) && velocity.y <= 0;
if (isGrounded)
{
velocity.y = Input.GetKeyDown(KeyCode.Space) ? Mathf.Sqrt(jumpHeight) : 0f;
}
else
{
velocity += (velocity.y < 0 ? Physics.gravity * 2 : Physics.gravity) * Time.deltaTime;
}
controller.Move(velocity);
// movement
inputVector = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")).normalized;
var smoothDamp = Vector3.SmoothDamp(inputVector, inputVector, ref currentDirVelocity, moveSmoothTime);
var runKey = (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) &&
!Input.GetKey(KeyCode.S) && !Input.GetKey(KeyCode.DownArrow);
controller.Move(smoothDamp * (runKey ? runSpeed : walkSpeed) * Time.deltaTime);
}
}
Also, these settings were suitable for a height 2 capsule:
If your character is greater than 2, adjust the length of the ground detection raycast accordingly because the controller.isGrounded condition does not always work.
When you are using character controller you need to do all the calculations for all the situations.
To get the result you are looking for you can do a calculation beetween jump and walking speed.
Another way is to use Rigid body (lock rotations) and add forces for jump and move.
both examples here: https://www.youtube.com/watch?v=b1uoLBp2I1w

Player Swipe Movement Controller like subway surfer using Character Controller in Unity3D?

I am trying to make a player movement controller like subway surfer using Character Controller, every thing is working fine with keyboard but I am getting an issue in swipe. When I swipe its moving only one frame. And also I want player to go left and right while player in air(Jumping). Please help.
Here is my code:
using UnityEngine;
using System.Collections;
public class PlayerControllerScript : MonoBehaviour
{
public float speed = 8.0F;
public float jumpSpeed = 16.0F;
public float gravity = 80.0F;
private Vector3 moveDirection = Vector3.zero;
public int laneNumber = 1;
public int lanesCount = 3;
bool didChangeLastFrame = false;
public float laneDistance = 2;
public float firstLaneXPos = -2;
public float deadZone = 0.1f;
public float sideSpeed = 12;
private bool Right = false;
private bool Left = false;
void Update()
{
CharacterController controller = GetComponent<CharacterController>();
float input = Input.GetAxis("Horizontal");
if (controller.isGrounded) {
if (Mathf.Abs(input) > deadZone)
{
if (!didChangeLastFrame)
{
didChangeLastFrame = true;
laneNumber += Mathf.RoundToInt(Mathf.Sign(input));
if (laneNumber < 0) laneNumber = 0;
else if (laneNumber >= lanesCount) laneNumber = lanesCount - 1;
}
}
else
{
didChangeLastFrame = false;
moveDirection = new Vector3(0, 0, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
if (Input.GetButton("Jump") || SwipeManager.IsSwipingUp())
moveDirection.y = jumpSpeed;
}
}
if (Left)
moveDirection.x = -jumpSpeed;
if (Right)
moveDirection.x = jumpSpeed;
if (SwipeManager.IsSwipingLeft())
{
Left = true;
Right = false;
}
if (SwipeManager.IsSwipingRight())
{
Right = true;
Left = false;
}
Vector3 pos = transform.position;
pos.x = Mathf.Lerp(pos.x, firstLaneXPos + laneDistance * laneNumber, Time.deltaTime * sideSpeed);
transform.position = pos;
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
}
}
I think,
if (Input.GetButton("Jump") || SwipeManager.IsSwipingUp())
moveDirection.y = jumpSpeed;
must be outside the if(controller.isGrounded) block. So, you jump regardless of gravity.
This is the final code;
using UnityEngine;
using System.Collections;
public class PlayerControllerScript : MonoBehaviour
{
public float speed = 8.0F;
public float jumpSpeed = 16.0F;
public float gravity = 80.0F;
private Vector3 moveDirection = Vector3.zero;
public int laneNumber = 1;
public int lanesCount = 3;
bool didChangeLastFrame = false;
public float laneDistance = 2;
public float firstLaneXPos = -2;
public float deadZone = 0.1f;
public float sideSpeed = 12;
private bool Right = false;
private bool Left = false;
void Update()
{
CharacterController controller = GetComponent<CharacterController>();
float input = Input.GetAxis("Horizontal");
if (controller.isGrounded) {
if (Mathf.Abs(input) > deadZone)
{
if (!didChangeLastFrame)
{
didChangeLastFrame = true;
laneNumber += Mathf.RoundToInt(Mathf.Sign(input));
if (laneNumber < 0) laneNumber = 0;
else if (laneNumber >= lanesCount) laneNumber = lanesCount - 1;
}
}
else
{
didChangeLastFrame = false;
moveDirection = new Vector3(0, 0, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
}
}
if (Input.GetButton("Jump") || SwipeManager.IsSwipingUp())
moveDirection.y = jumpSpeed;
if (Left)
moveDirection.x = -jumpSpeed;
if (Right)
moveDirection.x = jumpSpeed;
if (SwipeManager.IsSwipingLeft())
{
Left = true;
Right = false;
}
if (SwipeManager.IsSwipingRight())
{
Right = true;
Left = false;
}
Vector3 pos = transform.position;
pos.x = Mathf.Lerp(pos.x, firstLaneXPos + laneDistance * laneNumber, Time.deltaTime * sideSpeed);
transform.position = pos;
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
}
}