So, I made a basic movement script with wallrunning and wanted to add dashing to it, at first I made parameters for the character to dash and testing it with debug.log worked as intended, but the actual dash command, which was transform.translate(Vector3.forward), didn't work for some reason.
This is the code:
public class PlayerMovement : MonoBehaviour
{
public Transform player;
public CharacterController controller;
public float speed = 12f;
public float baseSpeed;
Vector3 velocity;
public float gravity = -9.81f;
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
public Transform wallCheckL;
public Transform wallCheckR;
public float wallDistanceL = -0.4f;
public float wallDistanceR = 0.4f;
public LayerMask wallMask;
public bool touchWallL;
public bool touchWallR;
public float SlideTime = 10f;
public float Ynormal;
public bool isGrounded;
public bool Sprinting;
public bool Crouching;
public bool Sliding;
public bool canDash;
// Start is called before the first frame update
void Start()
{
baseSpeed = speed;
canDash = true;
}
// Update is called once per frame
void Update()
{
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
touchWallL = Physics.CheckSphere(wallCheckL.position, wallDistanceL, wallMask);
touchWallR = Physics.CheckSphere(wallCheckR.position, wallDistanceR, wallMask);
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
if ((isGrounded == true) && Input.GetKeyDown("space"))
{
velocity.y = 10f;
}
if (Input.GetKeyDown(KeyCode.LeftShift))
{
speed = baseSpeed * 1.5f;
Sprinting = true;
}
if (Input.GetKeyUp(KeyCode.LeftShift))
{
speed = baseSpeed;
Sprinting = false;
}
if (Input.GetKeyDown(KeyCode.LeftControl))
{
Crouching = true;
}
if (Input.GetKeyUp(KeyCode.LeftControl))
{
Crouching = false;
}
if (Crouching)
{
transform.localScale = new Vector3(1f, 0.5f, 1f);
} else if (Crouching == false)
{
transform.localScale = new Vector3(1f, 1f, 1f);
}
if (Sprinting && Crouching)
{
Sliding = true;
} else if (Sprinting == false && Crouching == false)
{
Sliding = false;
}
if (Sliding)
{
speed = baseSpeed * 2;
transform.localScale = new Vector3(1f, 0.25f, 1f);
}
Ynormal = transform.localEulerAngles.y;
if (touchWallL)
{
gravity = -4.4f;
transform.localRotation = Quaternion.Euler(0, Ynormal, -20f);
isGrounded = true;
} else if (touchWallR)
{
gravity = -4.4f;
transform.localRotation = Quaternion.Euler(0f, Ynormal, 20f);
isGrounded = true;
}
else
{
gravity = -9.81f;
transform.localRotation = Quaternion.Euler(0f, Ynormal, 0f);
}
if (touchWallR && Input.GetKeyDown(KeyCode.Space))
{
velocity.y = 10f;
transform.position += Vector3.left * Time.deltaTime * 100;
}
if (Input.GetKeyDown(KeyCode.E) && canDash)
{
Dash();
}
}
void Dash()
{
StartCoroutine(dashTimer());
player.transform.Translate(Vector3.forward * Time.deltaTime * speed);
}
IEnumerator dashTimer()
{
canDash = false;
yield return new WaitForSeconds(2f);
canDash = true;
}
}
The requirements themselves work, I did some testing, but the dash itself didn't. I tried controller.move, transform.position += transform.position, even making a game object empty called dash distance and trying to teleport my character there, but none of it worked, all of it resulted in my character just not doing anything when I tried to dash.
This is due that Transform.Translate actually needs to be updated each frame.
Try refactoring a bit like this:
// add another control flag
private bool isDashing = false;
void Update()
{
//...
if (Input.GetKeyDown(KeyCode.E) && canDash)
{
StartCoroutine(dashTimer());
}
if (isDashing)
{
Dash();
}
}
void Dash()
{
player.transform.Translate(Vector3.forward * Time.deltaTime * speed);
}
IEnumerator dashTimer()
{
canDash = false;
isDashing = true;
yield return new WaitForSeconds(2f);
canDash = true;
isDashing = false;
}
Related
I'm currently working on a FPS "Speedrun" game & I want to add "Sliding" to the players movement. I already added "Crouching", but currently I'm stuck at getting the sliding done. (I'm using the Character Controller) I've tried many things, but nothing really worked. Heres the current PlayerMovement script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UIElements;
public class PlayerMovement : MonoBehaviour
{
public CharacterController controller;
private Rigidbody rb;
public Transform cameraTransform;
public HeadBobController headBobController;
[Header("Movement")]
private float speedMultiplier = 1f;
public float speed = 12f;
public float sprintSpeed = 20f;
public float slopeSpeed = 0.01f;
public float gravity = -9.81f;
public float jumpHeight = 3f;
public float sensitivity = 2f;
public float cameraRotationLimit = 85f;
[Header("Countermovement")]
public float counterMovement = 0.175f;
private float threshold = 0.01f;
public float maxSlopeAngle = 35f;
[Header("Sliding / Crouch")]
public float slideSpeed;
float originalHeight;
public float reducedHeight;
float targetHeight = 2f;
public float timeToCrouch = 0.25f;
float timeElapsed = 0;
bool canStopCrouching;
bool wantStopCrouch;
bool isRunning = false;
public bool isCrouching = false;
bool canUseHeadbob = true;
bool WillSlideOnSlopes = true;
bool IsSliding
{
get
{
if (controller.isGrounded && Physics.Raycast(transform.position, Vector3.down, out RaycastHit slopeHit, 3f))
{
hitPointNormal = slopeHit.normal;
return Vector3.Angle(hitPointNormal, Vector3.up) > controller.slopeLimit;
} else
{
return false;
}
}
}
[Header("Headbob")]
[SerializeField] private float walkBobSpeed = 14f;
[SerializeField] private float walkBobAmount = 0.05f;
[SerializeField] private float sprintBobSpeed = 18f;
[SerializeField] private float sprintBobAmount = 0.11f;
[SerializeField] private float crouchBobSpeed = 8f;
[SerializeField] private float crouchBobAmount = 0.025f;
private float defaultYPos = 0;
private float timer;
private Vector3 hitPointNormal;
[Header("Ground Check")]
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
Vector3 velocity;
public bool isGrounded;
[Header("Camera")]
float cameraRotationX = 0f;
float cameraRotationY = 0f;
public Camera camera;
public Transform orientation;
[Header("Other")]
public GameObject speedlines;
public ParticleSystem jumpParticle;
void Start()
{
rb = GetComponent<Rigidbody>();
controller = GetComponent<CharacterController>();
originalHeight = controller.height;
defaultYPos = camera.transform.localPosition.y;
//Cursor.lockState = CursorLockMode.Locked;
//Cursor.visible = false;
}
public void Update()
{
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
move = Vector3.ClampMagnitude(move, 1f);
if (Input.GetKey(KeyCode.LeftShift) && !isCrouching)
{
controller.Move(move * sprintSpeed * Time.deltaTime);
isRunning = true;
headBobController.amplitude = 0.1f;
headBobController.frequency = 30f;
} else
{
controller.Move(move * speed * speedMultiplier * Time.deltaTime);
isRunning = false;
headBobController.amplitude = 0.0426f;
headBobController.frequency = 19.1f;
}
if (Physics.Raycast(camera.transform.position, Vector3.up, 1f))
{
canStopCrouching = false;
} else
{
canStopCrouching = true;
}
if (canStopCrouching && wantStopCrouch && !Physics.Raycast(camera.transform.position, Vector3.up, 1f))
{
wantStopCrouch = false;
StopCrouch();
}
if (Input.GetKeyDown(KeyCode.LeftControl) && isGrounded)
{
//controller.height = Mathf.Lerp(reducedHeight, originalHeight, timeElapsed);
StartCrouch();
} else if(Input.GetKeyUp(KeyCode.LeftControl) && isGrounded && !Physics.Raycast(camera.transform.position, Vector3.up, 1f))
{
//controller.height = Mathf.Lerp(originalHeight, targetHeight, timeElapsed);
StopCrouch();
} else if(Input.GetKeyUp(KeyCode.LeftControl) && isGrounded && Physics.Raycast(camera.transform.position, Vector3.up, 1f))
{
wantStopCrouch = true;
}
if (Input.GetKey(KeyCode.LeftControl) && isRunning && isGrounded)
{
//Sliding
}
if (canUseHeadbob && isGrounded)
{
if (Mathf.Abs(move.x) > 0.1f || Mathf.Abs(move.z) > 0.1f)
{
timer += Time.deltaTime * (isCrouching ? crouchBobSpeed : isRunning ? sprintBobSpeed : walkBobSpeed);
camera.transform.localPosition = new Vector3(camera.transform.localPosition.x, defaultYPos + Mathf.Sin(timer) * (isRunning ? sprintBobAmount : walkBobAmount), camera.transform.localPosition.z);
}
}
if(WillSlideOnSlopes && IsSliding)
{
move += new Vector3(hitPointNormal.x, -hitPointNormal.y, hitPointNormal.z) * slopeSpeed;
}
if (isRunning)
{
speedlines.active = true;
} else {
speedlines.active = false;
}
controller.Move(move * speed * speedMultiplier * Time.deltaTime);
if (Input.GetButtonDown("Jump") && isGrounded)
{
controller.Move(-transform.forward * 0.1f);
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
jumpParticle.Play();
}
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
// Rotate the player based on mouse input
float mouseX = Input.GetAxis("Mouse X") * sensitivity;
float mouseY = Input.GetAxis("Mouse Y") * sensitivity;
cameraRotationY += mouseX;
cameraRotationX -= mouseY;
cameraRotationX = Mathf.Clamp(cameraRotationX, -cameraRotationLimit, cameraRotationLimit);
cameraTransform.localEulerAngles = new Vector3(cameraRotationX, cameraRotationY, 0f);
transform.eulerAngles = new Vector3(0f, cameraRotationY, 0f);
}
private void StartCrouch()
{
controller.height = reducedHeight;
speedMultiplier = 0.5f;
isCrouching = true;
}
private void StopCrouch()
{
controller.height = originalHeight;
speedMultiplier = 1f;
isCrouching = false;
}
}
It would be very nice if anyone could try to explain me how to implement it into this code using the Character Controller! :)
I've tried multiple Youtube Tutorial solutions & a lot in Online Forums, nothing really worked for me for some reason. Often the system wouldn't even work (nothing happened). I want the player to have the crouching ability (which is implemented) & to slide when isRunning & when the player isGrounded
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
[Header("Movement")]
private float moveSpeed;
public float walkSpeed;
public float sprintSpeed;
public bool sliding;
public bool sprinting;
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;
[Header("Sliding")]
public float maxSlideTime;
public float slideForce;
private float slideTimer;
public float slideSpeed;
public float slideYScale;
[Header("References")]
public Transform orientation;
private Rigidbody rb;
[Header("Input")]
private float horizontalInput;
private float verticalInput;
Vector3 moveDirection;
public MovementState state;
public enum MovementState
{
walking,
sprinting,
crouching,
sliding,
air
}
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();
if (Input.GetKeyUp(sprintKey) || Input.GetKeyUp(KeyCode.W))
sprinting = false;
// handle drag
if (grounded)
rb.drag = groundDrag;
else
rb.drag = 0;
horizontalInput = Input.GetAxisRaw("Horizontal");
verticalInput = Input.GetAxisRaw("Vertical");
if (Input.GetKeyDown(crouchKey) && sprinting)
StartSlide();
if (Input.GetKeyUp(crouchKey) && sliding)
StopSlide();
}
private void FixedUpdate()
{
MovePlayer();
if (sliding)
SlidingMovement();
}
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);
}
if (Input.GetKeyDown(crouchKey) && sprinting)
{
transform.localScale = new Vector3(transform.localScale.x, slideYScale, transform.localScale.z);
rb.AddForce(Vector3.down * 5f, ForceMode.Impulse);
sliding = true;
moveSpeed = slideSpeed;
}
// stop crouch
if (Input.GetKeyUp(crouchKey))
{
transform.localScale = new Vector3(transform.localScale.x, startYScale, transform.localScale.z);
sliding = false;
}
}
private void StateHandler()
{
// Mode - Crouching
if (Input.GetKey(crouchKey))
{
state = MovementState.crouching;
moveSpeed = crouchSpeed;
}
// Mode - Sliding
if(Input.GetKey(crouchKey) && sprinting)
{
state = MovementState.sliding;
moveSpeed = slideSpeed;
}
// Mode - Sprinting
else if (grounded && Input.GetKey(sprintKey) && Input.GetKey(KeyCode.W))
{
state = MovementState.sprinting;
moveSpeed = sprintSpeed;
sprinting = true;
}
// Mode - Walking
else if (grounded)
{
state = MovementState.walking;
moveSpeed = walkSpeed;
}
// Mode - Air
else
{
state = MovementState.air;
}
}
private void MovePlayer()
{
// calculate movement direction
moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput;
// on slope
if (OnSlope() && !exitingSlope)
{
rb.AddForce(GetSlopeMoveDirection() * 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;
}
private 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;
}
private Vector3 GetSlopeMoveDirection()
{
return Vector3.ProjectOnPlane(moveDirection, slopeHit.normal).normalized;
}
private void StartSlide()
{
sliding = true;
transform.localScale = new Vector3(transform.localScale.x, slideYScale, transform.localScale.z);
rb.AddForce(Vector3.down * 5f, ForceMode.Impulse);
slideTimer = maxSlideTime;
}
private void SlidingMovement()
{
Vector3 inputDirection = orientation.forward;
rb.AddForce(inputDirection.normalized * slideForce, ForceMode.Force);
slideTimer -= Time.deltaTime;
if (slideTimer <= 0)
StopSlide();
}
private void StopSlide()
{
sliding = false;
transform.localScale = new Vector3(transform.localScale.x, startYScale, transform.localScale.z);
}
}
I have been trying for a very long time to fix this, although I'm not the best at coding. I decided to come onto stack overflow for some help. Thank you to everyone who tries to solves this problem :D. As the titles states everything here works, excluding the crouching, when I press ctrl my moveSpeed does not change to my crouchSpeed...
I have coded the unity movement for my character. I made it so they can wall run bit it seems that wall running is somehow making my character walk weird. After wall running (if I wall run with the wall on my right) it will apply a force 90 degrees when I'm walking on the ground. The unknown force changes when each button is pressed (is W then apply both the W force and a force pushing it to the right). And the same happens with running on the left wall but it is at a -90 degree angle. Please help I've been stuck on this for a whole week. Thanks
This is the wall running code
using System.Collections.Generic;
using UnityEngine;
public class MoveChar : MonoBehaviour
{
[Header("Movement")]
float moveSpeed;
[SerializeField] float walkSpeed;
[SerializeField] float sprintSpeed;
[SerializeField] float slideSpeed;
[SerializeField] float wallRunSpeed;
float desiredMoveSpeed;
float lastDesiredMoveSpeed;
[SerializeField] float groundDrag;
[Header("Jumping")]
[SerializeField] float jumpForce;
[SerializeField] float jumpCoolDown;
[SerializeField] float airMultiplier;
bool readyToJump;
[HideInInspector] public bool doubleJump;
[Header("Crouching")]
[SerializeField] float crouchSpeed;
[SerializeField] float crouchYScale;
float crouchYStart;
bool exitingJump;
[Header("Slope Check")]
[SerializeField] float maxSlope;
RaycastHit slopeHit;
[Header("Ground Check")]
[SerializeField] float playerHeight;
[SerializeField] LayerMask whatIsGround;
bool grounded;
[Header("Keybinds")]
KeyCode jumpKey = KeyCode.Space;
KeyCode walkKey = KeyCode.LeftShift;
KeyCode crouchKey = KeyCode.C;
[SerializeField] Transform orientation;
[SerializeField] Transform camRotate;
float horizontalInput;
float verticalInput;
Vector3 moveDirection;
Rigidbody rb;
MovementState state;
enum MovementState
{
walking,
sprinting,
crouching,
sliding,
wallRunning,
air
}
[HideInInspector] public bool sliding;
[HideInInspector] public bool wallRunning;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
ResetJump();
crouchYStart = transform.localScale.y;
}
// Update is called once per frame
void Update()
{
grounded = Physics.Raycast(transform.position, Vector3.down, playerHeight * 0.5f + 0.2f, whatIsGround);
MyInput();
SpeedControl();
StateHandler();
if (grounded)
{
rb.drag = groundDrag;
}
else
{
rb.drag = 0;
}
}
private void FixedUpdate()
{
MovePlayer();
}
void MyInput()
{
horizontalInput = Input.GetAxisRaw("Horizontal");
verticalInput = Input.GetAxisRaw("Vertical");
if (Input.GetKeyDown(jumpKey) && readyToJump && (grounded || doubleJump))
{
readyToJump = false;
Jump();
Invoke(nameof(ResetJump), jumpCoolDown);
}
if (grounded && !Input.GetKey(jumpKey))
{
doubleJump = false;
}
if (Input.GetKeyDown(crouchKey))
{
transform.localScale = new Vector3(transform.localScale.x, crouchYScale, transform.localScale.z);
rb.AddForce(Vector3.down * 5f, ForceMode.Impulse);
}
if (Input.GetKeyUp(crouchKey))
{
transform.localScale = new Vector3(transform.localScale.x, crouchYStart, transform.localScale.z);
}
}
void StateHandler()
{
if (wallRunning)
{
state = MovementState.wallRunning;
desiredMoveSpeed = wallRunSpeed;
doubleJump = false;
}
if (sliding)
{
state = MovementState.sliding;
if (OnSlope() && rb.velocity.y < 0.1f)
{
desiredMoveSpeed = slideSpeed;
}
else
{
desiredMoveSpeed = sprintSpeed;
}
}
else if (Input.GetKey(crouchKey))
{
state = MovementState.crouching;
desiredMoveSpeed = crouchSpeed;
}
else if (grounded && Input.GetKey(walkKey))
{
state = MovementState.walking;
desiredMoveSpeed = walkSpeed;
}
else if (grounded)
{
state = MovementState.sprinting;
desiredMoveSpeed = sprintSpeed;
}
else
{
state = MovementState.air;
}
if (Mathf.Abs(desiredMoveSpeed - lastDesiredMoveSpeed) > 4f && moveSpeed != 0)
{
StopAllCoroutines();
StartCoroutine(SmoothlyLerpMoveSpeed());
}
else
{
moveSpeed = desiredMoveSpeed;
}
lastDesiredMoveSpeed = desiredMoveSpeed;
}
IEnumerator SmoothlyLerpMoveSpeed()
{
float time = 0;
float difference = Mathf.Abs(desiredMoveSpeed - moveSpeed);
float startValue = moveSpeed;
while (time < difference)
{
moveSpeed = Mathf.Lerp(startValue, desiredMoveSpeed, time / difference);
time += Time.deltaTime;
yield return null;
}
moveSpeed = desiredMoveSpeed;
}
void MovePlayer()
{
moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput;
if (OnSlope() && !exitingJump)
{
rb.AddForce(GetSlopeMoveDirection(moveDirection) * moveSpeed * 20f, ForceMode.Force);
if (rb.velocity.y > 0)
{
rb.AddForce(Vector3.down * 80f, ForceMode.Force);
}
}
else if (grounded)
{
rb.AddForce(moveDirection.normalized * moveSpeed * 10f, ForceMode.Force);
}
else if (!grounded)
{
rb.AddForce(moveDirection.normalized * moveSpeed * 10f * airMultiplier, ForceMode.Force);
}
if (!wallRunning)
{
rb.useGravity = !OnSlope();
}
}
void SpeedControl()
{
if (OnSlope() && !exitingJump)
{
if (rb.velocity.magnitude > moveSpeed)
{
rb.velocity = rb.velocity.normalized * moveSpeed;
}
}
else
{
Vector3 flatVel = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
if (flatVel.magnitude > moveSpeed)
{
Vector3 limitVel = flatVel.normalized * moveSpeed;
rb.velocity = new Vector3(limitVel.x, rb.velocity.y, limitVel.z);
}
}
}
void Jump()
{
exitingJump = true;
rb.velocity = new Vector3(rb.velocity.x, 0, rb.velocity.z);
rb.AddForce(transform.up * jumpForce, ForceMode.Impulse);
doubleJump = !doubleJump;
}
void ResetJump()
{
readyToJump = true;
exitingJump = 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 < maxSlope && angle != 0;
}
return false;
}
public Vector3 GetSlopeMoveDirection(Vector3 direction)
{
return Vector3.ProjectOnPlane(direction, slopeHit.normal).normalized;
}
}
This is the wall running code
using System.Collections.Generic;
using UnityEngine;
public class WallRunning : MonoBehaviour
{
[Header("Wallrunning")]
[SerializeField] LayerMask whatIsRunAble;
[SerializeField] LayerMask whatIsGround;
[SerializeField] float wallRunForce;
[SerializeField] float wallRunUpForce;
[SerializeField] float wallRunSideForce;
[SerializeField] float wallClimbSpeed;
[Header("Input")]
KeyCode jumpKey = KeyCode.Space;
float horizontalInput;
float verticalInput;
[Header("Detection")]
[SerializeField] float wallCheckDistance;
[SerializeField] float minJumpHeight;
RaycastHit leftWallHit;
RaycastHit rightWallHit;
bool wallLeft;
bool wallRight;
[Header("Exiting")]
[SerializeField] float exitWallTime;
bool exitingWall;
float exitWallTimer;
[Header("Gravity")]
[SerializeField] bool useGravity;
[SerializeField] float gravityCounterForce;
[Header("References")]
[SerializeField] Transform orientation;
MoveChar mc;
Rigidbody rb;
[SerializeField] Transform cam;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
mc = GetComponent<MoveChar>();
}
// Update is called once per frame
void Update()
{
CheckForWall();
StateMachine();
}
private void FixedUpdate()
{
if (mc.wallRunning)
{
WallRunMove();
}
}
void CheckForWall()
{
wallRight = Physics.Raycast(transform.position, orientation.right, out rightWallHit, wallCheckDistance, whatIsRunAble);
wallLeft = Physics.Raycast(transform.position, -orientation.right, out leftWallHit, wallCheckDistance, whatIsRunAble);
}
bool AboveGround()
{
return !Physics.Raycast(transform.position, Vector3.down, minJumpHeight, whatIsGround);
}
void StateMachine()
{
horizontalInput = Input.GetAxisRaw("Horizontal");
verticalInput = Input.GetAxisRaw("Vertical");
if ((wallLeft || wallRight) && verticalInput > 0 && AboveGround() && !exitingWall)
{
if (Input.GetKeyDown(jumpKey))
{
WallJump();
}
}
if ((wallLeft || wallRight) && verticalInput > 0 && AboveGround() && !exitingWall)
{
if (!mc.wallRunning)
{
StartWallRun();
}
}
else if (exitingWall)
{
if (mc.wallRunning)
{
StopWallRun();
}
if (exitWallTimer > 0)
{
exitWallTimer -= Time.deltaTime;
}
if (exitWallTimer <= 0)
{
exitingWall = false;
}
}
else
{
if (mc.wallRunning)
{
StopWallRun();
}
}
}
void StartWallRun()
{
mc.wallRunning = true;
rb.velocity = new Vector3(rb.velocity.x, 0, rb.velocity.z);
if (wallRight)
{
cam.localRotation = Quaternion.Euler(0, 0, 10f);
}
if (wallLeft)
{
cam.localRotation = Quaternion.Euler(0, 0, -10f);
}
}
void WallRunMove()
{
rb.useGravity = useGravity;
Vector3 wallNormal = wallRight ? rightWallHit.normal : leftWallHit.normal;
Vector3 wallForward = Vector3.Cross(wallNormal, transform.up.normalized);
if ((orientation.forward - wallForward).magnitude > (orientation.forward - -wallForward).magnitude)
{
wallForward = -wallForward;
}
rb.AddForce(wallForward * wallRunForce, ForceMode.Force);
/*if (!(wallLeft && horizontalInput > 0) && !(wallRight && horizontalInput < 0))
{
rb.AddForce(-wallNormal * 100, ForceMode.Force);
}
if (useGravity)
{
rb.AddForce(transform.up * gravityCounterForce, ForceMode.Force);
}*/
}
void StopWallRun()
{
mc.wallRunning = false;
cam.localRotation = Quaternion.Euler(0, 0, 0);
}
void WallJump()
{
exitingWall = true;
exitWallTimer = exitWallTime;
Vector3 wallNormal = wallRight ? rightWallHit.normal : leftWallHit.normal;
Vector3 forceToApply = transform.up * wallRunUpForce + wallNormal * wallRunSideForce;
rb.velocity = new Vector3(rb.velocity.x, 0, rb.velocity.z);
rb.AddForce(forceToApply, ForceMode.Impulse);
mc.doubleJump = !mc.doubleJump;
}
}
Thank you soooooooo much for any help
I am trying to scale and rotate an object. The rotation is on X-Axis. I am able to implement the scale perfectly, it is the rotation that is causing the problem. How do I rotate the object to a target rotation and then back to initial rotation with this script? When I am executing this script, the rotation sometimes work and sometimes does not execute, however there is no problem with the scaling.
EDIT: The basic thing I found was that I cannot set Quaternion to negative value, that is -90 becomes 270 automatically and due to this I cannot move 270 to 0.
using UnityEngine;
using System.Collections;
public class ScaleAndRotate : MonoBehaviour {
public int startSize = 3;
public int minSize = 1;
public int maxSize = 6;
public float speed = 2.0f;
private Vector3 targetScale;
private Vector3 baseScale;
private int currScale;
//ROT
public Quaternion targetRotation;
public bool startRotation = false;
void Start() {
baseScale = transform.localScale;
transform.localScale = baseScale * startSize;
currScale = startSize;
targetScale = baseScale * startSize;
}
void Update() {
transform.localScale = Vector3.Lerp (transform.localScale, targetScale, speed * Time.deltaTime);
if(startRotation == true)
{
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * speed);
}
else
if(startRotation == false)
{
//Go Back To Initial Rotation
}
if (Input.GetKeyDown (KeyCode.UpArrow))
{
ChangeSize (true);
startRotation = true;
}
if (Input.GetKeyDown (KeyCode.DownArrow))
{
ChangeSize (false);
startRotation = false;
}
}
public void ChangeSize(bool bigger) {
if (bigger)
{
currScale++;
}
else
{
currScale--;
}
currScale = Mathf.Clamp (currScale, minSize, maxSize+1);
targetScale = baseScale * currScale;
}
}
The problem was with the transform.rotation that was not able to change the rotation from -90/270 to new rotation. I instead had to use transform.localRotation and it worked perfectly.
using UnityEngine;
using System.Collections;
public class ScaleAndRotate : MonoBehaviour {
public int startSize = 3;
public int minSize = 1;
public int maxSize = 6;
public float speed = 2.0f;
private Vector3 targetScale;
private Vector3 baseScale;
private int currScale;
//ROT
public Quaternion targetRotation;
public Quaternion initialRotation;
public bool startRotation = false;
void Start() {
baseScale = transform.localScale;
transform.localScale = baseScale * startSize;
currScale = startSize;
targetScale = baseScale * startSize;
initialRotation = transform.localRotation;
}
void Update() {
transform.localScale = Vector3.Lerp (transform.localScale, targetScale, speed * Time.deltaTime);
if(startRotation == true)
{
transform.localRotation = Quaternion.Slerp(transform.localRotation, targetRotation, Time.deltaTime * speed);
}
else
if(startRotation == false)
{
//Go Back To Initial Rotation
transform.localRotation = Quaternion.Slerp(transform.localRotation, initialRotation, Time.deltaTime * speed);
}
if (Input.GetKeyDown (KeyCode.UpArrow))
{
ChangeSize (true);
startRotation = false;
}
if (Input.GetKeyDown (KeyCode.DownArrow))
{
ChangeSize (false);
startRotation = true;
}
}
public void ChangeSize(bool bigger) {
if (bigger)
{
currScale++;
}
else
{
currScale--;
}
currScale = Mathf.Clamp (currScale, minSize, maxSize+1);
targetScale = baseScale * currScale;
}
}
I think the problem is that you miss brackets when you use if statements:
if (Input.GetKeyDown (KeyCode.UpArrow))
ChangeSize (true);
startRotation = true;
if (Input.GetKeyDown (KeyCode.DownArrow))
ChangeSize (false);
startRotation = false;
When you use something like that code above the if is used only to the first following line of code. Thus, add brackets to that code:
if (Input.GetKeyDown (KeyCode.UpArrow))
{
ChangeSize (true);
startRotation = true;
}
if (Input.GetKeyDown (KeyCode.DownArrow))
{
ChangeSize (false);
startRotation = false;
}
Solved - I ended up removing playerController.SimpleMove and having playerController.Move control all the player's movement.
So I have been trying to make my character wall jump between to walls. I've been able to make it work however, after each successful wall jump the height of the next jump decreases. This gets to the point where it starts wall jumping downwards. I have no idea why it does this. Before each time pressing the space bar, I am resetting the movement Vector3's to zero and then reapplying the correct values to the jump. I have even gone through the console to look at the vertical changes and neither moveDirection and moveAmount get a large enough value change to make this happen.
Because I am just trying this out, below is all the code that is affecting the player.
public float rotateSpeed = 3.0f;
public float walkSpeed = 5.0f;
public float runSpeed = 15.0f;
public float jumpSpeed = 10.0f;
public float acceleration = .05f;
public bool running = false;
public bool jumping = false;
public bool falling = false;
public bool onWall = false;
public bool wallJumping = false;
public bool stay = false;
private CharacterController playerController;
private Animator playerAnimator;
private float speed;
private Vector3 moveAmount;
private float animationSpeed;
private float currentSpeed;
private float targetSpeed;
private float moveSpeed;
float gravity = 10f;
private Vector3 moveDirection = Vector3.zero;
// Use this for initialization
void Start () {
playerController = GetComponent<CharacterController>();
playerAnimator = GetComponent<Animator>();
}
// Update is called once per frame
void Update () {
transform.Rotate(0, Input.GetAxis("Horizontal") * rotateSpeed, 0);
if (onWall)
{
playerAnimator.SetBool("Wall Holding", true);
jumping = false;
}
else
{
playerAnimator.SetBool("Wall Holding", false);
}
if (stay)
{
moveDirection = Vector3.zero;
moveAmount = Vector3.zero;
}
#region Player Controls
if (Input.GetButton("Vertical") && !wallJumping)
{
moveSpeed = (Input.GetKey(KeyCode.LeftShift)) ? runSpeed : walkSpeed;
moveAmount = transform.TransformDirection(Vector3.forward);
}
else
{
moveSpeed = 0;
moveAmount = Vector3.zero;
}
if (playerController.isGrounded){
moveDirection = Vector3.zero;
jumping = false;
wallJumping = false;
onWall = false;
stay = false;
}
else
{
if (!stay)
onWall = false;
}
if (Input.GetKeyDown(KeyCode.Space))
{
if (playerController.isGrounded)
{
moveDirection.y = jumpSpeed;
jumping = true;
}
else if (onWall)
{
moveDirection = Vector3.zero;
moveAmount = Vector3.zero;
wallJumping = true;
moveDirection += transform.forward * jumpSpeed * 2f;
moveDirection += transform.up * jumpSpeed * 2f;
stay = false;
}
}
if (Input.GetKeyDown(KeyCode.F))
{
if (playerAnimator.GetBool("fight"))
{
playerAnimator.SetBool("fight", false);
}
else
{
playerAnimator.SetBool("fight", true);
}
}
#endregion Player Controls
moveDirection.y -= gravity * Time.deltaTime;
Debug.Log(moveDirection.x);
targetSpeed = Input.GetAxis("Vertical") * moveSpeed;
currentSpeed = SpeedFactor(targetSpeed, currentSpeed, acceleration);
if (currentSpeed > walkSpeed)
running = true;
else
running = false;
playerAnimator.SetFloat("movespeed", currentSpeed);
if (!stay)
{
playerController.SimpleMove(currentSpeed * moveAmount);
playerController.Move(moveDirection * Time.deltaTime);
}
}
private float SpeedFactor (float targetSpeed, float currentSpeed, float dilation) {
if ( currentSpeed < targetSpeed) {
currentSpeed += dilation;
if ( currentSpeed > targetSpeed) {
currentSpeed = targetSpeed;
}
}
else if ( currentSpeed > targetSpeed) {
currentSpeed -= dilation;
if ( currentSpeed < targetSpeed) {
currentSpeed = targetSpeed;
}
}
return currentSpeed;
}
void OnControllerColliderHit (ControllerColliderHit hit) {
if (hit.gameObject.tag == "JumpingWall" && !playerController.isGrounded && !onWall && (jumping || wallJumping))
{
onWall = true;
transform.Rotate(0,180,0);
stay = true;
}
}
The simplest explanation is that transform.forward and/or transform.up vectors begin to diverge from your expectations over time. This would explain how it even seems to be jumping "backwards" eventually when you apply the lines below. Are you sure these vectors are oriented as you expect after the jumper collides with a wall (prior to the next jump)?
moveDirection += transform.forward * jumpSpeed * 2f;
moveDirection += transform.up * jumpSpeed * 2f;