I have began developing an fps script and followed a tutorial to help with the script. Everything works great now but the only issue is any objects in the view seem to stutter whenever the player is moving and rotating at the same time.
The script for the player's movement and camera rotation is below.
Can anybody point me in the right direction?
Thank you.
{
public Transform cam;
public Rigidbody rb;
public float camRotationSpeed = 5f;
public float camMinimumY = -60f;
public float camMaximumY = 75f;
public float rotationSmoothSpeed = 10f;
public float walkSpeed = 9f;
public float runSpeed = 14f;
public float maxSpeed = 20f;
public float jumpPower = 30f;
public float extraGravity = 45;
float bodyRotationX;
float camRotationY;
Vector3 directionIntentX;
Vector3 directionIntentY;
float speed;
public bool grounded;
void Update()
{
LookRotation();
Movement();
ExtraGravity();
GroundCheck();
if(grounded && Input.GetButtonDown("Jump"))
{
Jump();
}
}
void LookRotation()
{
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
bodyRotationX += Input.GetAxis("Mouse X") * camRotationSpeed;
camRotationY += Input.GetAxis("Mouse Y") * camRotationSpeed;
camRotationY = Mathf.Clamp(camRotationY, camMinimumY, camMaximumY);
Quaternion camTargetRotation = Quaternion.Euler(-camRotationY, 0, 0);
Quaternion bodyTargetRotation = Quaternion.Euler(0, bodyRotationX, 0);
transform.rotation = Quaternion.Lerp(transform.rotation, bodyTargetRotation, Time.deltaTime * rotationSmoothSpeed);
cam.localRotation = Quaternion.Lerp(cam.localRotation, camTargetRotation, Time.deltaTime * rotationSmoothSpeed);
}
void Movement()
{
directionIntentX = cam.right;
directionIntentX.y = 0;
directionIntentX.Normalize();
directionIntentY = cam.forward;
directionIntentY.y = 0;
directionIntentY.Normalize();
rb.velocity = directionIntentY * Input.GetAxis("Vertical") * speed + directionIntentX * Input.GetAxis("Horizontal") * speed + Vector3.up * rb.velocity.y;
rb.velocity = Vector3.ClampMagnitude(rb.velocity, maxSpeed);
if (Input.GetKey(KeyCode.LeftShift))
{
speed = runSpeed;
}
if (!Input.GetKey(KeyCode.LeftShift))
{
speed = walkSpeed;
}
}
void ExtraGravity()
{
rb.AddForce(Vector3.down * extraGravity);
}
void GroundCheck()
{
RaycastHit groundHit;
grounded = Physics.Raycast(transform.position, -transform.up, out groundHit, 1.25f);
}
void Jump()
{
rb.AddForce(Vector3.up * jumpPower, ForceMode.Impulse);
}
}
This probably happens because the frame needs to update the camera rotation and the player position at the same time. i would suggest doing the rotation of the camera in fixed update. because this will run at the end of each frame.
like this:
void FixedUpdate()
{
LookRotation();
}
another thing i would suggest is to move the player while the groundcheck is being ran, because if you do it seperately i can see a bug coming up when the player moves faster then the code can run or something. so a tip would be or to run it inside the movement method, or call the method while you are calling the movement method.
this:
void Movement()
{
directionIntentX = cam.right;
directionIntentX.y = 0;
directionIntentX.Normalize();
directionIntentY = cam.forward;
directionIntentY.y = 0;
directionIntentY.Normalize();
rb.velocity = directionIntentY * Input.GetAxis("Vertical") * speed + directionIntentX * Input.GetAxis("Horizontal") * speed + Vector3.up * rb.velocity.y;
rb.velocity = Vector3.ClampMagnitude(rb.velocity, maxSpeed);
if (Input.GetKey(KeyCode.LeftShift))
{
speed = runSpeed;
}
if (!Input.GetKey(KeyCode.LeftShift))
{
speed = walkSpeed;
}
GroundCheck();
}
or litteraly copy and paste the code within your movement method.
Related
Im making a 3d game in unity, and so I made a cs script for movement of my charecter, walking and moveing the camera works fine, however when i added the jump function, it had a delay. You could press the jump button 5 times, with no result. Then you press it again, and it jumps. I cant figure out why this does this.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController characterController;
public int speed = 6;
public float gravity = 9.87f;
private float verticalspeed = 0;
private Vector3 moveDirection = Vector3.zero;
public Transform Camera;
public float Sensitivity = 2f;
public float uplimit = -50;
public float downlimit = -50;
public float jumpspeed = 5.0f;
void Update()
{
move();
cameramove();
void cameramove()
{
float horizontal = Input.GetAxis("Mouse X");
float vertical = Input.GetAxis("Mouse Y");
transform.Rotate(0, horizontal * Sensitivity, 0);
Camera.Rotate(-vertical * Sensitivity, 0, 0);
Vector3 currentRotation = Camera.localEulerAngles;
if (currentRotation.x > 180) currentRotation.x -= 360;
currentRotation.x = Mathf.Clamp(currentRotation.x, uplimit, downlimit);
Camera.localRotation = Quaternion.Euler(currentRotation);
}
void move()
{
float horizontalMove = Input.GetAxis("Horizontal");
float verticalMove = Input.GetAxis("Vertical");
if (characterController.isGrounded) verticalspeed = 0;
else verticalspeed -= gravity * Time.deltaTime;
Vector3 gravityMove = new Vector3(0, verticalspeed, 0);
Vector3 move = transform.forward * verticalMove + transform.right * horizontalMove;
characterController.Move(speed * Time.deltaTime * move + gravityMove * Time.deltaTime);
if (characterController.isGrounded && Input.GetButton("Jump"))
{
moveDirection.y = jumpspeed;
}
moveDirection.y -= gravity * Time.deltaTime;
characterController.Move(moveDirection * Time.deltaTime);
}
}
}
Assuming your character has a RigidBody assigned to it, you can refer it on your script as,
public class PlayerMovement : MonoBehaviour
{
private Rigidbody myrigidbody;
void Start () {
myrigidbody = GetComponent<Rigidbody>();
}
}
Then you can pass the jumpspeed as a Vector3, and probably you might have to trigger your animation here as well.
if (characterController.isGrounded && Input.GetButton("Jump"))
{
characterController.isGrounded = false;
myrigidbody.AddForce(new Vector3(0, jumpspeed, 0));
// Trigger your animation, myanimator.SetTrigger("jump");
}
Unity character controller move documentation also contains jump function.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Example : 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);
}
}
Below is the code that I am using to move an object in Unity. The rb.Velocity line makes my object float in in Gameplay mode. If I comment out the line then the object falls just fine.
Could someone explain whats happening here?
public class PlayerController : MonoBehaviour
{
public float forwardVelocity = 0F;
public float maxSpeed = 180;
public float acceleratePerSecond = 8.0F;
public float rotateSpeed = 3.0F;
private float yaw = 0.0f;
private float pitch = 0.0f;
protected Rigidbody rb;
float timeZeroToMax = 2.5F;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
acceleratePerSecond = maxSpeed / timeZeroToMax;
forwardVelocity = 0F;
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.UpArrow)) //Accelerate The Vehicle
{
if (forwardVelocity< maxSpeed)
{
forwardVelocity += acceleratePerSecond * Time.deltaTime;
}
}
forwardVelocity = Mathf.Min(forwardVelocity, maxSpeed);
rb.velocity = transform.forward * forwardVelocity;
transform.Rotate(0, Input.GetAxis("Mouse X") * rotateSpeed, 0);
yaw += rotateSpeed * Input.GetAxis("Mouse X");
transform.eulerAngles = new Vector3(pitch, yaw, 0.0f);
}
}
The transform.forward is a Vector3(0,0,1), that's the problem.
You are setting your y velocity to 0.
I just started my adventure with unity and I got stuck.
I need to make my character turn on animation walk when I press "W" and when there is no any key pressed stop and do Idle animation for being not moved (Sorry for my english I'm not a native speaker) and then when I press space char should jump and use jump anim my char actually move and jump but repeat only one animation even when I don't press any key.
Further, I want to make Climbing, Ledge Climb, character falling from the edge, etc smth like in Assassin's Creed. I want to animation play on keypress.I just start to figure it out using transition but still luck of results
I'm not sure what should I change, need a help.
using UnityEngine;
using System.Collections;
public class PlayerController2 : MonoBehaviour
{
public float walkSpeed = 20;
public float runSpeed = 40;
public float gravity = -80;
public float jumpHeight = 15;
[Range(0, 1)]
public float airControlPercent;
public float turnSmoothTime = 0.2f;
float turnSmoothVelocity;
public float speedSmoothTime = 0.1f;
float speedSmoothVelocity;
float currentSpeed;
float velocityY;
Animator animator;
Transform cameraT;
CharacterController controller;
void Start()
{
animator = GetComponent<Animator>();
cameraT = Camera.main.transform;
controller = GetComponent<CharacterController>();
}
void Update()
{
// input
Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
Vector2 inputDir = input.normalized;
bool running = Input.GetKey(KeyCode.LeftShift);
Move(inputDir, running);
if (Input.GetKeyDown(KeyCode.Space))
{
Jump();
}
// animator
float animationSpeedPercent = ((running) ? currentSpeed / runSpeed : currentSpeed / walkSpeed * .5f);
animator.SetFloat("speedPercent", animationSpeedPercent, speedSmoothTime, Time.deltaTime);
}
void Move(Vector2 inputDir, bool running)
{
if (inputDir != Vector2.zero)
{
float targetRotation = Mathf.Atan2(inputDir.x, inputDir.y) * Mathf.Rad2Deg + cameraT.eulerAngles.y;
transform.eulerAngles = Vector3.up * Mathf.SmoothDampAngle(transform.eulerAngles.y, targetRotation, ref turnSmoothVelocity, GetModifiedSmoothTime(turnSmoothTime));
}
float targetSpeed = ((running) ? runSpeed : walkSpeed) * inputDir.magnitude;
currentSpeed = Mathf.SmoothDamp(currentSpeed, targetSpeed, ref speedSmoothVelocity, GetModifiedSmoothTime(speedSmoothTime));
velocityY += Time.deltaTime * gravity;
Vector3 velocity = transform.forward * currentSpeed + Vector3.up * velocityY;
controller.Move(velocity * Time.deltaTime);
currentSpeed = new Vector2(controller.velocity.x, controller.velocity.z).magnitude;
if (controller.isGrounded)
{
velocityY = 0;
}
}
void Jump()
{
if (controller.isGrounded)
{
float jumpVelocity = Mathf.Sqrt(-2 * gravity * jumpHeight);
velocityY = jumpVelocity;
}
}
float GetModifiedSmoothTime(float smoothTime)
{
if (controller.isGrounded)
{
return smoothTime;
}
if (airControlPercent == 0)
{
return float.MaxValue;
}
return smoothTime / airControlPercent;
}
}
I have the basic movement and rotation working however I can not work out a way to limit the rotation up and down. I want to make it so that you cant look more than 90° up and down.
Ive tried multiple ways such as using if statments and using clamp.
using UnityEngine;
public class FPSController : MonoBehaviour {
public float speed = 5f;
public float sensitivity = 2f;
public GameObject Camera;
CharacterController controller;
float moveFB;
float moveLR;
public float rotX;
public float rotY;
void Start()
{
controller = GetComponent<CharacterController>();
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void FixedUpdate ()
{
moveFB = Input.GetAxis("Vertical");
moveLR = Input.GetAxis("Horizontal");
rotX = Input.GetAxis("Mouse X") * sensitivity;
rotY = Input.GetAxis("Mouse Y") * sensitivity;
transform.Rotate(0, rotX, 0);
Vector3 movement = new Vector3(moveLR * speed * Time.deltaTime, 0, moveFB * speed * Time.deltaTime);
controller.Move(transform.rotation * movement);
Camera.transform.Rotate(-rotY, 0, 0);
}
}
With this code you will be able to rotate the camera beyond 90 degrees causing it to be upside down etc
"Camera" is a built-in unity class, I would recommend renaming it to "camera".
Try this to clamp the camera's rotation:
(with your other public floats)
public float minAngle = -90;
public float maxAngle = 90;
(at the end of FixedUpdate)
Vector3 temp = camera.transform.localEulerAngles;
camera.transform.localEulerAngles = new Vector3(Mathf.Clamp(Mathf.DeltaAngle(0, temp.x), minAngle, maxAngle), temp.y, temp.z);
Edit: changed eulerAngles to localEulerAngles
Edit 2: changed the order of the arguements of Mathf.DeltaAngle
I fixed it here. Not to sure on how it works but it works. Credit to video:https://www.youtube.com/watch?v=F5eE1YL1ZJY
using UnityEngine;
public class FPSController : MonoBehaviour {
public float speed = 5f;
public float sensitivity = 2f;
public GameObject Camera;
CharacterController controller;
float moveFB;
float moveLR;
public float rotX;
public float rotY;
public float minAngle = -90f;
public float maxAngle = 90f;
void Start()
{
controller = GetComponent<CharacterController>();
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void FixedUpdate ()
{
moveFB = Input.GetAxis("Vertical");
moveLR = Input.GetAxis("Horizontal");
rotX = Input.GetAxis("Mouse X") * sensitivity;
rotY -= Input.GetAxis("Mouse Y") * sensitivity;
rotY = Mathf.Clamp(rotY, minAngle, maxAngle);
transform.Rotate(0, rotX, 0);
Vector3 movement = new Vector3(moveLR * speed * Time.deltaTime, 0, moveFB * speed * Time.deltaTime);
controller.Move(transform.rotation * movement);
Camera.transform.localRotation = Quaternion.Euler(rotY, 0, 0);
}
}
I have figured out how to get fbx animations working in Unity for my character in my adventure game, but now I wish to have my character's running animation move with its speed of motion being in relation to the input of the control stick on an xbox controller.
In addition, when I add a walking animation in the future I wish to make a threshold for the control stick input so that the character walks when there is minimal input from the control stick and running when there is more input from the control stick. Any advice?
Here is my code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCharacterController : MonoBehaviour {
static Animator anim;
public bool walking;
public GameObject playerModel, Hero;
//Transforms
public Transform playerCam, character, centerPoint;
private Vector3 moveDirection;
//character controller declaration
CharacterController player;
//Mouse Rotation
private float rotX, rotY;
//Mouse Y Position
public float mouseYPosition = 1f;
//Mouse Sensitivity
public float Sensitivity = 10f;
//Mouse Zoom
private float zoom;
public float zoomSpeed = 2;
//Clamping Zoom
public float zoomMin = -2f;
public float zoomMax = -10f;
public float rotationSpeed = 5f;
//Move Front Back left & Right
private float moveFB, moveLR;
//Movement Speed
public float Speed = 2f;
//Velocity of Gravity
public float verticalVelocity;
//Jump Distance
public float jumpDist = 5f;
//Multiple Jumps
int jumpTimes;
//To use with Dialogue Manager
public DialogueManager DiagM;
public AudioClip jumpSound;
public AudioClip HurtSound;
AudioSource audioSource;
//knockback
public float knockBackForce;
public float knockBackTime;
private float knockBackCounter;
// Use this for initialization
void Start ()
{
//character controller
player = GameObject.Find("Player").GetComponent<CharacterController> ();
anim = GetComponent<Animator>();
//mouse zoom
zoom = -3;
centerPoint.transform.position = playerCam.transform.position;
centerPoint.transform.parent = null;
audioSource = GetComponent<AudioSource>();
}
// Update is called once per frame
void Update ()
{
//if (DiagM.StartDialogue)
//{ return; }
//Mouse Zoom Input
zoom += Input.GetAxis ("Mouse ScrollWheel") * zoomSpeed;
if (zoom > zoomMin)
zoom = zoomMin;
if (zoom < zoomMax)
zoom = zoomMax;
//Mouse Camera Input
playerCam.transform.localPosition = new Vector3 (0, 0, zoom);
//Mouse Rotation
rotX += Input.GetAxis ("Mouse X") * Sensitivity;
rotY -= Input.GetAxis ("Mouse Y") * Sensitivity;
//Clamp Camera
rotY = Mathf.Clamp (rotY, -60f, 60f);
playerCam.LookAt (centerPoint);
centerPoint.localRotation = Quaternion.Euler (rotY, rotX, 0);
//Movement Speed
if (knockBackCounter <= 0)
{
moveDirection = (transform.forward * Input.GetAxis("Vertical")) + (transform.right * Input.GetAxis("Horizontal"));
moveDirection = moveDirection * Speed;
moveDirection.y = verticalVelocity;
player.Move(moveDirection * Time.deltaTime);
//Movement Rotation
centerPoint.position = new Vector3 (character.position.x, character.position.y + mouseYPosition, character.position.z);
//knockback disable
//Movement Input
if (Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0)
{
transform.rotation = Quaternion.Euler(0f, centerPoint.rotation.eulerAngles.y, 0f);
Quaternion turnAngle = Quaternion.LookRotation(new Vector3(moveDirection.x, 0f, moveDirection.z));
playerModel.transform.rotation = Quaternion.Slerp(playerModel.transform.rotation, turnAngle, Time.deltaTime * rotationSpeed);
if (player.isGrounded == true)
{
anim.Play("Running");
}
}
else
{
if (player.isGrounded == true)
{ anim.Play("Idle"); }
}
if (player.isGrounded == true)
{
jumpTimes = 0;
verticalVelocity = -Physics.gravity.y * Time.deltaTime;
}
else
{
verticalVelocity += Physics.gravity.y * Time.deltaTime;
}
if (Input.GetButtonDown("Submit"))
{
anim.Play("Hello");
}
if (jumpTimes < 1)
{
if (Input.GetButtonDown("Jump"))
{
verticalVelocity += jumpDist;
anim.Play("Jump");
audioSource.PlayOneShot(jumpSound, 1F);
jumpTimes += 1;
}
}
}
else
{
knockBackCounter -= Time.deltaTime;
}
}
public void Knockback(Vector3 direction)
{
knockBackCounter = knockBackTime;
anim.SetTrigger("isJumping");
audioSource.PlayOneShot(HurtSound, 50F);
moveDirection = direction * knockBackForce;
moveDirection.y = knockBackForce;
}
}