I make 3rd person game, where i have script for control model of my character.
Problem is that when i jump and don't push any button he stack in the air, but if i jump with pushing controlling button he worked normally.
Thanks in advance.
Player controller script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(CharacterController))]
public class RelativeMovement : MonoBehaviour
{
[SerializeField] private Transform target;
public float rotSpeed = 5.0f;
public float moveSpeed = 6.0f;
public float jumpSpeed = 15.0f;
public float gravity = -9.8f;
public float terminalVelocity = -20.0f;
public float minFall = -1.5f;
private float _vertSpeed;
private CharacterController _charController;
private ControllerColliderHit _contact;
void Start()
{
_vertSpeed = minFall;
_charController = GetComponent<CharacterController>();
}
void Update()
{
Vector3 movement = Vector3.zero;
float horInput = Input.GetAxis("Horizontal");
float vertInput = Input.GetAxis("Vertical");
if(horInput != 0 || vertInput != 0)
{
movement.x = horInput * moveSpeed;
movement.z = vertInput * moveSpeed;
movement = Vector3.ClampMagnitude(movement, moveSpeed);
Quaternion tmp = target.rotation;
target.eulerAngles = new Vector3(0, target.eulerAngles.y, 0);
movement = target.TransformDirection(movement);
target.rotation = tmp;
Quaternion direction = Quaternion.LookRotation(movement);
transform.rotation = Quaternion.Lerp(transform.rotation,
direction, rotSpeed * Time.deltaTime);
bool hitGround = false;
RaycastHit hit;
if(_vertSpeed < 0 && Physics.Raycast(transform.position, Vector3.down, out hit))
{
float check =
(_charController.height + _charController.radius) / 1.9f;
hitGround = hit.distance <= check;
}
if(hitGround)
{
if (Input.GetButtonDown("Jump"))
{
_vertSpeed = jumpSpeed;
}
else
{
_vertSpeed = minFall;
}
}
else
{
_vertSpeed += gravity * 5 * Time.deltaTime;
if(_vertSpeed < terminalVelocity)
{
_vertSpeed = terminalVelocity;
}
if(_charController.isGrounded)
{
if(Vector3.Dot(movement, _contact.normal) < 0)
{
movement = _contact.normal * moveSpeed;
}
else
{
movement += _contact.normal * moveSpeed;
}
}
}
movement.y = _vertSpeed;
movement *= Time.deltaTime;
_charController.Move(movement);
}
}
void OnControllerColliderHit(ControllerColliderHit hit)
{
_contact = hit;
}
}
Jesus photo:
enter image description here
I didn't go through all of the code but I can immediately see what can cause the problem you describe:
your entire logic happen under this if statement:
if(horInput != 0 || vertInput != 0)
So everything inside this logic block will happen only when you actively press a movement button.
You can remove it (or better yet, close the if block at the right spot.. I think it would be 2 lines down)
The answer of this question is:
if((horInput == 0 || vertInput == 0) || (horInput != 0 && vertInput != 0))
{
movement.x = horInput * moveSpeed;
movement.z = vertInput * moveSpeed;
if(horInput != 0 || vertInput != 0)
{
movement = Vector3.ClampMagnitude(movement, moveSpeed);
Quaternion tmp = target.rotation;
target.eulerAngles = new Vector3(0, target.eulerAngles.y, 0);
movement = target.TransformDirection(movement);
target.rotation = tmp;
Quaternion direction = Quaternion.LookRotation(movement);
transform.rotation = Quaternion.Lerp(transform.rotation,
direction, rotSpeed * Time.deltaTime);
}
Thanks Joe
Related
I wanted to add Guns with recoil to my 3d fps game. It worked but for some reason all the time when i look completely downwards i walk backwards or frontwards. This only happens when the gun is active.
The Gun Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GunScript : MonoBehaviour
{
[SerializeField] float Recoil = 500f;
[SerializeField] float TimeTillNextShoot;
[SerializeField] float Range = 100f;
[SerializeField] Transform GunTipposition;
[SerializeField] float recoilRadius = 100f;
public Camera PlayerCamera;
public Rigidbody rbPlayer;
private void Update()
{
Shoot();
}
public void Shoot()
{
if (Input.GetButtonDown("Fire1"))
{
RaycastHit hit;
if(Physics.Raycast(PlayerCamera.transform.position, PlayerCamera.transform.forward, out hit, Range))
{
Debug.Log(hit.transform.name);
Enemy Enemytarget = hit.transform.GetComponent<Enemy>();
if(Enemytarget != null)
{
Enemytarget.TakeDamage(true);
}
}
if (gameObject.CompareTag("ShotGun"))
{
Transform RecoilPosition = GunTipposition.transform;
rbPlayer.AddExplosionForce(Recoil, RecoilPosition.position, recoilRadius);
}
}
}
}
The player Movement:
// Some stupid rigidbody based movement by Dani
using System;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
[Header("Assignables")]
[Tooltip("this is a reference to the MainCamera object, not the parent of it.")]
public Transform playerCam;
[Tooltip("reference to orientation object, needed for moving forward and not up or something.")]
public Transform orientation;
[Tooltip("LayerMask for ground layer, important because otherwise the collision detection wont know what ground is")]
public LayerMask whatIsGround;
private Rigidbody rb;
[Header("Rotation and look")]
private float xRotation;
[Tooltip("mouse/look sensitivity")]
public float sensitivity = 50f;
private float sensMultiplier = 1.5f;
[Header("Movement")]
[Tooltip("additive force amount. every physics update that forward is pressed, this force (multiplied by 1/tickrate) will be added to the player.")]
public float moveSpeed = 4500;
[Tooltip("maximum local velocity before input is cancelled")]
public float maxSpeed = 20;
[Tooltip("normal countermovement when not crouching.")]
public float counterMovement = 0.175f;
private float threshold = 0.01f;
[Tooltip("the maximum angle the ground can have relative to the players up direction.")]
public float maxSlopeAngle = 35f;
private Vector3 crouchScale = new Vector3(1, 0.5f, 1);
private Vector3 playerScale;
[Tooltip("forward force for when a crouch is started.")]
public float slideForce = 400;
[Tooltip("countermovement when sliding. this doesnt work the same way as normal countermovement.")]
public float slideCounterMovement = 0.2f;
private bool readyToJump = true;
private float jumpCooldown = 0.25f;
[Tooltip("this determines the jump force but is also applied when jumping off of walls, if you decrease it, you may end up being able to walljump and then get back onto the wall leading to infinite height.")]
public float jumpForce = 550f;
float x, y;
bool jumping;
private Vector3 normalVector = Vector3.up;
[Header("Wallrunning")]
private float actualWallRotation;
private float wallRotationVel;
private Vector3 wallNormalVector;
[Tooltip("when wallrunning, an upwards force is constantly applied to negate gravity by about half (at default), increasing this value will lead to more upwards force and decreasing will lead to less upwards force.")]
public float wallRunGravity = 1;
[Tooltip("when a wallrun is started, an upwards force is applied, this describes that force.")]
public float initialForce = 20f;
[Tooltip("float to choose how much force is applied outwards when ending a wallrun. this should always be greater than Jump Force")]
public float escapeForce = 600f;
private float wallRunRotation;
[Tooltip("how much you want to rotate the camera sideways while wallrunning")]
public float wallRunRotateAmount = 10f;
[Tooltip("a bool to check if the player is wallrunning because thats kinda necessary.")]
public bool isWallRunning;
[Tooltip("a bool to determine whether or not to actually allow wallrunning.")]
public bool useWallrunning = true;
[Header("Collisions")]
[Tooltip("a bool to check if the player is on the ground.")]
public bool grounded;
[Tooltip("a bool to check if the player is currently crouching.")]
public bool crouching;
private bool surfing;
private bool cancellingGrounded;
private bool cancellingSurf;
private bool cancellingWall;
private bool onWall;
private bool cancelling;
public static PlayerMovement Instance { get; private set; }
void Awake()
{
Instance = this;
rb = GetComponent<Rigidbody>();
//Create a physic material with no friction to allow for wallrunning and smooth movement not being dependant
//and smooth movement not being dependant on the in-built unity physics engine, apart from collisions.
PhysicMaterial mat = new PhysicMaterial("tempMat");
mat.bounceCombine = PhysicMaterialCombine.Average;
mat.bounciness = 0;
mat.frictionCombine = PhysicMaterialCombine.Minimum;
mat.staticFriction = 0;
mat.dynamicFriction = 0;
gameObject.GetComponent<Collider>().material = mat;
}
void Start()
{
playerScale = transform.localScale;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
readyToJump = true;
wallNormalVector = Vector3.up;
}
private void FixedUpdate()
{
Movement();
}
private void Update()
{
MyInput();
Look();
}
private void LateUpdate()
{
//call the wallrunning Function
WallRunning();
WallRunRotate();
}
private void WallRunRotate()
{
FindWallRunRotation();
float num = 12f;
actualWallRotation = Mathf.SmoothDamp(actualWallRotation, wallRunRotation, ref wallRotationVel, num * Time.deltaTime);
playerCam.localRotation = Quaternion.Euler(playerCam.rotation.eulerAngles.x, playerCam.rotation.eulerAngles.y, actualWallRotation);
}
/// <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);
//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);
if (rb.velocity.magnitude > 0.2f && grounded)
{
if (grounded)
{
rb.AddForce(orientation.transform.forward * slideForce);
}
}
}
private void StopCrouch()
{
transform.localScale = playerScale;
transform.position = new Vector3(transform.position.x, transform.position.y + 0.5f, transform.position.z);
}
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)
{
multiplier = 0.5f;
multiplierV = 0.5f;
}
// Movement while sliding
if (grounded && crouching) multiplierV = 0f;
//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 || isWallRunning || surfing) && readyToJump)
{
MonoBehaviour.print("jumping");
Vector3 velocity = rb.velocity;
readyToJump = false;
rb.AddForce(Vector2.up * jumpForce * 1.5f);
rb.AddForce(normalVector * jumpForce * 0.5f);
if (rb.velocity.y < 0.5f)
{
rb.velocity = new Vector3(velocity.x, 0f, velocity.z);
}
else if (rb.velocity.y > 0f)
{
rb.velocity = new Vector3(velocity.x, velocity.y / 2f, velocity.z);
}
if (isWallRunning)
{
rb.AddForce(wallNormalVector * jumpForce * 3f);
}
Invoke("ResetJump", jumpCooldown);
if (isWallRunning)
{
isWallRunning = false;
}
}
}
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;
float clamp = 89.5f;
xRotation = Mathf.Clamp(xRotation, -clamp, clamp);
//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);
}
//a lot of math (dont touch)
private void FindWallRunRotation()
{
if (!isWallRunning)
{
wallRunRotation = 0f;
return;
}
_ = new Vector3(0f, playerCam.transform.rotation.y, 0f).normalized;
new Vector3(0f, 0f, 1f);
float num = 0f;
float current = playerCam.transform.rotation.eulerAngles.y;
if (Math.Abs(wallNormalVector.x - 1f) < 0.1f)
{
num = 90f;
}
else if (Math.Abs(wallNormalVector.x - -1f) < 0.1f)
{
num = 270f;
}
else if (Math.Abs(wallNormalVector.z - 1f) < 0.1f)
{
num = 0f;
}
else if (Math.Abs(wallNormalVector.z - -1f) < 0.1f)
{
num = 180f;
}
num = Vector3.SignedAngle(new Vector3(0f, 0f, 1f), wallNormalVector, Vector3.up);
float num2 = Mathf.DeltaAngle(current, num);
wallRunRotation = (0f - num2 / 90f) * wallRunRotateAmount;
if (!useWallrunning)
{
return;
}
if ((Mathf.Abs(wallRunRotation) < 4f && y > 0f && Math.Abs(x) < 0.1f) || (Mathf.Abs(wallRunRotation) > 22f && y < 0f && Math.Abs(x) < 0.1f))
{
if (!cancelling)
{
cancelling = true;
CancelInvoke("CancelWallrun");
Invoke("CancelWallrun", 0.2f);
}
}
else
{
cancelling = false;
CancelInvoke("CancelWallrun");
}
}
private bool IsFloor(Vector3 v)
{
return Vector3.Angle(Vector3.up, v) < maxSlopeAngle;
}
private bool IsSurf(Vector3 v)
{
float num = Vector3.Angle(Vector3.up, v);
if (num < 89f)
{
return num > maxSlopeAngle;
}
return false;
}
private bool IsWall(Vector3 v)
{
return Math.Abs(90f - Vector3.Angle(Vector3.up, v)) < 0.05f;
}
private bool IsRoof(Vector3 v)
{
return v.y == -1f;
}
/// <summary>
/// Handle ground detection
/// </summary>
private void OnCollisionStay(Collision other)
{
int layer = other.gameObject.layer;
if ((int)whatIsGround != ((int)whatIsGround | (1 << layer)))
{
return;
}
for (int i = 0; i < other.contactCount; i++)
{
Vector3 normal = other.contacts[i].normal;
if (IsFloor(normal))
{
if (isWallRunning)
{
isWallRunning = false;
}
grounded = true;
normalVector = normal;
cancellingGrounded = false;
CancelInvoke("StopGrounded");
}
if (IsWall(normal) && (layer == (int)whatIsGround || (int)whatIsGround == -1 || layer == LayerMask.NameToLayer("Ground") || layer == LayerMask.NameToLayer("ground"))) //seriously what is this
{
StartWallRun(normal);
onWall = true;
cancellingWall = false;
CancelInvoke("StopWall");
}
if (IsSurf(normal))
{
surfing = true;
cancellingSurf = false;
CancelInvoke("StopSurf");
}
IsRoof(normal);
}
float num = 3f;
if (!cancellingGrounded)
{
cancellingGrounded = true;
Invoke("StopGrounded", Time.deltaTime * num);
}
if (!cancellingWall)
{
cancellingWall = true;
Invoke("StopWall", Time.deltaTime * num);
}
if (!cancellingSurf)
{
cancellingSurf = true;
Invoke("StopSurf", Time.deltaTime * num);
}
}
private void StopGrounded()
{
grounded = false;
}
private void StopWall()
{
onWall = false;
isWallRunning = false;
}
private void StopSurf()
{
surfing = false;
}
//wallrunning functions
private void CancelWallrun()
{
//for when we want to stop wallrunning
MonoBehaviour.print("cancelled wallrun");
Invoke("GetReadyToWallrun", 0.1f);
rb.AddForce(wallNormalVector * escapeForce);
isWallRunning = false;
}
private void StartWallRun(Vector3 normal)
{
MonoBehaviour.print("wallrunning");
//cancels all y momentum and then applies an upwards force.
if (!grounded && useWallrunning)
{
wallNormalVector = normal;
if (!isWallRunning)
{
rb.velocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
rb.AddForce(Vector3.up * initialForce, ForceMode.Impulse);
}
isWallRunning = true;
}
}
private void WallRunning()
{
//checks if the wallrunning bool is set to true and if it is then applies
//a force to counter gravity enough to make it feel like wallrunning
if (isWallRunning)
{
rb.AddForce(-wallNormalVector * Time.deltaTime * moveSpeed);
rb.AddForce(Vector3.up * Time.deltaTime * rb.mass * 40f * wallRunGravity * -Physics.gravity.y);
}
}
}
I used a addForce funktion to add the recoil.Please help me.
This sentence is juist written because i need to add more details
Let me just preface my question by saying I'm quite new to unity and programming as a whole. However I've been experimenting with some movement and after adding my falling function I've run into some trouble. Sometimes if I press play in Unity the character will start jittering quite heavy, every frame it also jumps between isInAir and isGrounded (as well as isInteracting). This causes my player to shake heavily and jitter forward as well.
Sometimes the falling animation will happen but my character falls really slowly, sometimes the animation doesn't work. Does anyone know how I can fix this?
Here is my PlayerLocomotion, the everything falling related is mentioned under HandleFalling.
using System.Collections.Generic;
using UnityEngine;
namespace FS
{
public class PlayerLocomotion : MonoBehaviour
{
PlayerManager playerManager;
Transform cameraObject;
InputHandler inputHandler;
public Vector3 moveDirection;
[HideInInspector]
public Transform myTransform;
[HideInInspector]
public AnimatorHandler animatorHandler;
public new Rigidbody rigidbody;
public GameObject normalCamera;
[Header("Ground & Air Detection Stats")]
[SerializeField]
float groundDetectionRayStartPoint = 0.5f;
[SerializeField]
float minimumDistanceNeededToBeginFall = 1f;
[SerializeField]
float groundDirectionRayDistance = 0.2f;
LayerMask ignoreForGroundCheck;
public float inAirTimer;
[Header("Movement Stats")]
[SerializeField]
float movementSpeed = 5;
[SerializeField]
float sprintSpeed = 7;
[SerializeField]
float rotationSpeed = 10;
[SerializeField]
float fallingSpeed = 45;
void Start()
{
playerManager = GetComponent<PlayerManager>();
rigidbody = GetComponent<Rigidbody>();
inputHandler = GetComponent<InputHandler>();
animatorHandler = GetComponentInChildren<AnimatorHandler>();
cameraObject = Camera.main.transform;
myTransform = transform;
animatorHandler.Initialize();
playerManager.isGrounded = true;
ignoreForGroundCheck = ~(1 << 10);
}
#region Movement
Vector3 normalVector;
Vector3 targetPosition;
private void HandleRotation(float delta)
{
Vector3 targetDir = Vector3.zero;
float moveOverride = inputHandler.moveAmount;
targetDir = cameraObject.forward * inputHandler.vertical;
targetDir += cameraObject.right * inputHandler.horizontal;
targetDir.Normalize();
targetDir.y = 0;
if (targetDir == Vector3.zero) targetDir = myTransform.forward;
float rs = rotationSpeed;
Quaternion tr = Quaternion.LookRotation(targetDir);
Quaternion targetRotation =
Quaternion.Slerp(myTransform.rotation, tr, rs * delta);
myTransform.rotation = targetRotation;
}
public void HandleMovement(float delta)
{
if (inputHandler.rollFlag) return;
if (playerManager.isInteracting) return;
moveDirection = cameraObject.forward * inputHandler.vertical;
moveDirection += cameraObject.right * inputHandler.horizontal;
moveDirection.Normalize();
moveDirection.y = 0;
float speed = movementSpeed;
if (inputHandler.sprintFlag)
{
speed = sprintSpeed;
playerManager.isSprinting = true;
moveDirection *= speed;
}
else
{
moveDirection *= speed;
}
Vector3 projectedVelocity =
Vector3.ProjectOnPlane(moveDirection, normalVector);
rigidbody.velocity = projectedVelocity;
animatorHandler
.UpdateAnimatorValues(inputHandler.moveAmount,
0,
playerManager.isSprinting);
if (animatorHandler.canRotate)
{
HandleRotation (delta);
}
}
public void HandleRollingAndSprinting(float delta)
{
if (animatorHandler.anim.GetBool("isInteracting")) return;
if (inputHandler.rollFlag)
{
moveDirection = cameraObject.forward * inputHandler.vertical;
moveDirection += cameraObject.right * inputHandler.horizontal;
if (inputHandler.moveAmount > 0)
{
animatorHandler.PlayTargetAnimation("Rolling", true);
moveDirection.y = 0;
Quaternion rollRotation =
Quaternion.LookRotation(moveDirection);
myTransform.rotation = rollRotation;
}
else
{
animatorHandler.PlayTargetAnimation("Backstep", true);
}
}
}
public void HandleFalling(float delta, Vector3 moveDirection)
{
playerManager.isGrounded = false;
RaycastHit hit;
Vector3 origin = myTransform.position;
origin.y += groundDetectionRayStartPoint;
if (Physics.Raycast(origin, myTransform.forward, out hit, 0.4f))
{
moveDirection = Vector3.zero;
}
if (playerManager.isInAir)
{
rigidbody.AddForce(-Vector3.up * fallingSpeed);
rigidbody.AddForce(moveDirection * fallingSpeed / 5f);
}
Vector3 dir = -moveDirection;
dir.Normalize();
origin = origin + dir * groundDirectionRayDistance;
targetPosition = myTransform.position;
Debug
.DrawRay(origin,
-Vector3.up * minimumDistanceNeededToBeginFall,
Color.red,
0.1f,
false);
if (Physics.Raycast(origin, -Vector3.up, out hit, minimumDistanceNeededToBeginFall, ignoreForGroundCheck))
{
normalVector = hit.normal;
Vector3 tp = hit.point;
playerManager.isGrounded = true;
targetPosition.y = tp.y;
if (playerManager.isInAir)
{
if (inAirTimer > 0.5f)
{
Debug.Log("You were in the air for " + inAirTimer);
animatorHandler.PlayTargetAnimation("Land", true);
inAirTimer = 0;
}
else
{
animatorHandler
.PlayTargetAnimation("Empty", false);
inAirTimer = 0;
}
playerManager.isInAir = false;
}
else
{
if (playerManager.isGrounded)
{
playerManager.isGrounded = false;
}
if (playerManager.isInAir == false)
{
if (playerManager.isInteracting == false)
{
animatorHandler
.PlayTargetAnimation("Falling", true);
}
Vector3 vel = rigidbody.velocity;
vel.Normalize();
rigidbody.velocity = vel * (movementSpeed / 2);
playerManager.isInAir = true;
}
}
if (playerManager.isInteracting || inputHandler.moveAmount > 0)
{
myTransform.position = Vector3.Lerp(myTransform.position, targetPosition, Time.deltaTime / 0.1f);
}
else
{
myTransform.position = targetPosition;
}
}
}
#endregion
}
}
Did someone know how to make the player not turning when i press left or right button ? I'm using unity script refrence for moving.
this video showing my problem: https://drive.google.com/file/d/1m-_Q3j0kt5bMfxiiqqjGAp0wtW7x8gno/view?usp=sharing
public class Move : MonoBehaviour
{
private CharacterController controller;
private Vector3 playerVelocity;
private bool groundedPlayer;
private float playerSpeed = 2.0f;
private float jumpHeight = 1.0f;
private float gravityValue = -9.81f;
private void Start()
{
controller = gameObject.AddComponent<CharacterController>();
}
void Update()
{
groundedPlayer = controller.isGrounded;
if (groundedPlayer && playerVelocity.y < 0)
{
playerVelocity.y = 0f;
}
Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
controller.Move(move * Time.deltaTime * playerSpeed);
if (move != Vector3.zero)
{
gameObject.transform.forward = move;
}
// Changes the height position of the player..
if (Input.GetButtonDown("Jump") && groundedPlayer)
{
playerVelocity.y += Mathf.Sqrt(jumpHeight * -3.0f * gravityValue);
}
playerVelocity.y += gravityValue * Time.deltaTime;
controller.Move(playerVelocity * Time.deltaTime);
}
}
Remove this line:
if (move != Vector3.zero)
{
gameObject.transform.forward = move;
}
I am a new unity developer that is trying to make a 3d game. So far I have managed to develop a pretty cool first-person character controller. It uses a character controller and it has sliding and jumping mechanics.
And the question is:
How can I make my player lose sliding speed when sliding up a slope and gain sliding speed when sliding down a slope?
Here is my code so far and please keep in mind that my code is messy and that I am a still beginner. If you need any further information please don't hesitate to ask. Thanks for your time! Also, any suggestions are more than welcome!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovementScript : MonoBehaviour
{
//Character controller refrence
private CharacterController controller;
//Camera refrence
[SerializeField] Camera fpsCam;
//IsGrounded variables
private float groundDistance = 1.5f;
public bool isGrounded;
//SomethingAbove variables
private float cellingDistance = 1.5f;
public bool somethingAbove;
//Variables
//Speed that is modified
private float speed = 12f;
//Default speed
private float baseSpeed = 12f;
//Slide speed that is modified
private float slideSpeed = 15f;
//Default slide speed
private float slideSpeedStorage = 15f;
//Crouch speed
private float crouchSpeed = 3f;
//Jump height
private float jumpHeight = 2f;
private bool isJumping = false;
//Gravity
private float gravity = -14.715f;
//Air resistance
private float xAirResistance = 0.5f;
private float zAirResistance = 0.35f;
//Air multipiler
private float airMultiplierJump = 1.1f;
//Fov
private float fovWhenSliding = 100f;
private float defaultFov;
//Crouch variables
float originalHeight;
float reducedHeight = 0.5f;
//Player input
float x;
float z;
bool jump;
bool control;
//Directions
Vector3 velocity;
private Vector3 move = new Vector3();
private Vector3 slideDirection = new Vector3();
private Vector3 jumpDirection = new Vector3();
private void Awake()
{
controller = GetComponent<CharacterController>();
}
private void Start()
{
//Getting the original height
originalHeight = controller.height;
//Getting the default fov
defaultFov = fpsCam.fieldOfView;
}
private void Update()
{
MyInput();
Calculations();
PlayerMovement();
}
private void MyInput()
{
//Getting WASD input
x = Input.GetAxis("Horizontal");
z = Input.GetAxis("Vertical");
//Space bar input
jump = Input.GetButtonDown("Jump");
//Left control input
control = Input.GetKey(KeyCode.LeftControl);
}
private void Calculations()
{
//Checking if player is grounded
Debug.DrawRay(transform.position, Vector3.down * groundDistance, Color.red);
isGrounded = Physics.Raycast(transform.position, Vector3.down, groundDistance);
//Checking if player can get up
Debug.DrawRay(transform.position, Vector3.up * cellingDistance, Color.black);
somethingAbove = Physics.Raycast(transform.position, Vector3.up, cellingDistance);
/*//Getting the player has enough speed and getting jump direction
if (isGrounded && jump && z > 0)
{
//If pressing W the jump direction is forward
jumpDirection = transform.forward;
}*/
//Movement in air
if (isGrounded)
{
//On ground movement
move = transform.right * x + transform.forward * z;
}
else
{
//If pressing W
if (z > 0)
{
//Jump direction multiplied by airMultiplierJump
move = transform.forward * z * airMultiplierJump + transform.right * x * xAirResistance;
}
else
{
//Jump direction = Vector3.zero;
move = transform.forward * z * zAirResistance + transform.right * x * xAirResistance;
}
}
//Checking if the player has enough speed for sliding and getting direction
if (Input.GetKeyDown(KeyCode.LeftControl) && isGrounded)
{
if (z == 1 || x == 1 || x == -1)
{
//If pressing W || A || D slide direction is the direction u are moving towards
slideDirection = transform.forward * z + transform.right * x;
}
else
{
//If pressing S the slide direction is zero
slideDirection = Vector3.zero;
}
}
//Adding extra force so the player stays on ground
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
//Calculating gravity
velocity.y += gravity * Time.deltaTime;
//Normalizing the move vector so the diagonal and normal movement are the same speed
if (move.sqrMagnitude > 1)
{
move.Normalize();
}
//Extra force on slope downwards so the player stays on it
if((x != 0 || z != 0) && OnSlope())
{
controller.Move(Vector3.down * controller.height / 2 * 2f);
}
}
private void PlayerMovement()
{
Jump();
Slide();
//Moving the player with WASD
controller.Move(move * speed * Time.deltaTime);
//Applying gravity
controller.Move(velocity * Time.deltaTime);
}
private void Slide()
{
//Checking for left control input and if the player is grounded
if(control && isGrounded && !OnSlope())
{
StartSlide();
}
//Checking if the player can uncrouch
else if(!somethingAbove && isGrounded)
{
StopSlide();
}
else if (!control)
{
controller.height = originalHeight;
speed = baseSpeed;
}
else if(control && !isGrounded)
{
controller.height = originalHeight;
speed = baseSpeed;
}
else
{
controller.height = reducedHeight;
speed = crouchSpeed;
}
}
//Starting to slide
private void StartSlide()
{
if (z != 1 || x != -1 || x != 1)
{
speed = crouchSpeed;
}
else
{
speed = 0f;
}
controller.height = reducedHeight;
controller.Move(slideDirection * Time.deltaTime * slideSpeed);
slideSpeed -= 10f * Time.deltaTime;
if (slideSpeed <= 0)
{
slideSpeed = 0f;
speed = crouchSpeed;
}
}
//Stopping the slide
private void StopSlide()
{
controller.height = originalHeight;
speed = baseSpeed;
//Slide speed recovery
slideSpeed = Mathf.Lerp(slideSpeed, slideSpeedStorage, Time.deltaTime * 2);
}
//Jumping mechanic
private void Jump()
{
if (jump && isGrounded)
{
isJumping = true;
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
}
private bool OnSlope()
{
if (isJumping)
{
return false;
}
RaycastHit hit;
if(Physics.Raycast(transform.position, Vector3.down, out hit, controller.height / 2 * 5f))
if(hit.normal != Vector3.up)
{
return true;
}
return false;
}
//Stopping the slide if hitting object
private void OnControllerColliderHit(ControllerColliderHit hit)
{
if(hit.transform.tag == "SlideStop")
{
slideSpeed = 0f;
speed = crouchSpeed;
}
}
}```
private bool OnSlope()
{
if (isJumping)
{
return false;
}
RaycastHit hit;
if(Physics.Raycast(transform.position, Vector3.down, out hit, controller.height / 2 * 5f))
if(hit.normal != Vector3.up)
{
return true;
}
return false;
}
One issue is comparing Vector3s which is bad practice, since they are arrays of floats. Even if the plane is completely planar, it might still return true due to what's known as 'floating point errors'. A better practice is to use:
Vector3.distance(hit.normal, Vector3.up) > .1f // or some other small value;
I am currently in the process of developing my first platformer, and I've decided that I want to bake my own acceleration and deceleration for movement instead of using unity's wonky physics.
This has brought up two roadblocks, one being that my character will just clip through objects like walls to jump over or off of, and the other is that if I try to switch directions while decelerating, my character will turn around, but it won't change directions and my acceleration will bypass the limit I set for it (in layman's, it zooms backwards).
I need help fixing this and can describe any of the functions of the variables if asked. There is no physics material on my character, and I am using physics for the jump.
All of the variables are defined in the unity editor for easier tweaking except for currentSpeed, jumpCount, FallTime and canJump, which I have serialized so I can observe them during testing.
I've tried changing
newPos = new Vector2(transform.position.x + currentSpeed, transform.position.y);
transform.position = newPos;
to addForce but it messed with the jumping.
public class PlayerControls : MonoBehaviour {
//walk Vars
[SerializeField] float currentSpeed;
[SerializeField] float maxSpeed;
[SerializeField] float jumpstart;
[SerializeField] float acceleration;
[SerializeField] float deceleraton;
int isFlip = 1;
Vector2 newPos;
Quaternion flip;
//jump Vars
[SerializeField] public int jumpCount;
[SerializeField] public int jumpCountMax;
[SerializeField] public float jumpVel;
[SerializeField] public float fallMulti;
[SerializeField] public float shortMulti;
[SerializeField] public float fallTime;
[SerializeField] public float coyoteTime;
[SerializeField] bool canJump = true;
[SerializeField] bool didJump;
//references
Rigidbody2D rb;
private void Awake() {
rb = GetComponent<Rigidbody2D>();
}
//walk Functions
private void speedCalc() {
currentSpeed += jumpstart * isFlip;
if (currentSpeed * isFlip >= maxSpeed) {
currentSpeed = maxSpeed * isFlip;
}
else {
currentSpeed = (currentSpeed * acceleration);
}
}
private void Start() {
currentSpeed = 0;
}
private void Update() {
//calculate coyote time
if (fallTime == coyoteTime) {
if (didJump == false) {
jumpCount += 1;
}
}
if (jumpCount >= jumpCountMax) {
canJump = false;
} else {
canJump = true;
}
if (rb.velocity.y == 0) {
jumpCount = 0;
didJump = false;
}
//calculate isFlip
if (Input.GetButton("Right")) {
flip = Quaternion.Euler(0, 0, 0);
transform.rotation = flip;
isFlip = 1;
} else if (Input.GetButton("Left")) {
flip = Quaternion.Euler(0, 180, 0);
transform.rotation = flip;
isFlip = -1;
}
//calculate acceleration & deceleration
if (!Input.GetButton("Right") && !Input.GetButton("Left")) {
if (currentSpeed * isFlip <= jumpstart) {
currentSpeed = 0;
} else {
currentSpeed = (currentSpeed / deceleraton);
}
} else {
speedCalc();
}
//implement falling and dyanamic jumping
if (rb.velocity.y < 0) {
fallTime += 1;
rb.velocity += Vector2.up * Physics2D.gravity * (fallMulti - 1) * Time.deltaTime;
} else if (rb.velocity.y == 0) {
fallTime = 0;
} else if (rb.velocity.y > 0 && !Input.GetButton("Jump")) {
rb.velocity += Vector2.up * Physics2D.gravity * (shortMulti - 1) * Time.deltaTime;
}
//execute jump
if (Input.GetButtonDown("Jump") && canJump == true) {
didJump = true;
rb.velocity = Vector2.up * jumpVel;
jumpCount += 1;
}
//move character position
newPos = new Vector2(transform.position.x + currentSpeed, transform.position.y);
transform.position = newPos;
}
}
There where no error messages or anything but I'm 80% sure its my logic and ordering. The acceleration might be overlapping with the deceleration and the isFlip.