I'm currently working on a fps game in which you can travel to asteroids and walk on them, currently I have gravity for those asteroids and I have a fps controller that works for all my other movement systems (swimming, floating) but translating it to the gravity of the asteroid is giving me a lot of trouble. I can get the controller to work perfectly on flat surfaces using Unity's gravity but not on the asteroid.
The current fps controller moves in the direction of the camera which means the character floats up when looking up, all my other fps controllers didn't work at all with the planet and this one is the closet I've gotten to getting it to work.
Is there anyway to fix this? I'm quite new to coding so any explanations would help me heaps!
Here's the code I'm using for the controller:
public Transform targetCamera;
public Rigidbody targetRigidbody;
public Transform targetBody;
public float walkSpeed = 9f;
public float runSpeed = 14f;
public float maxSpeed = 20f;
public float jumpPower = 30f;
public float extraGravity = 0;
float bodyRotationX;
float camRotationY;
Vector3 directionIntentX;
Vector3 directionIntentY;
float speed;
public bool grounded;
public float thrust = 20f;
public float forwardSwimSpeed = 45f;
private float xRotation;
private const float Sensitivity = 50f;
private const float SensitivityMultiplier = 1f;
private float desiredX;
public float dragMult = 2f;
public float rotationSmoothSpeed = 10f;
void Update()
{
Look();
targetRigidbody.drag = dragMult;
}
private void FixedUpdate()
{
if (targetRigidbody.velocity.magnitude > maxSpeed)
{
targetRigidbody.velocity = targetRigidbody.velocity.normalized * maxSpeed;
}
if (Input.GetKey(KeyCode.W))
AddForce(Vector3.forward);
if (Input.GetKey(KeyCode.S))
AddForce(Vector3.back);
if (Input.GetKey(KeyCode.A))
AddForce(Vector3.left);
if (Input.GetKey(KeyCode.D))
AddForce(Vector3.right);
if (Input.GetKey(KeyCode.Space))
AddForce(Vector3.up);
if (Input.GetKey(KeyCode.LeftControl))
AddForce(Vector3.down);
}
private void AddForce(Vector3 direction)
{
float scaledForwardSwimSpeed = Time.deltaTime * forwardSwimSpeed;
targetRigidbody.AddForce(targetCamera.transform.TransformDirection(
direction * thrust) * scaledForwardSwimSpeed,
ForceMode.Acceleration);
}
private void Look()
{
float mouseX = Input.GetAxis("Mouse X") * Sensitivity * Time.fixedDeltaTime * SensitivityMultiplier;
float mouseY = Input.GetAxis("Mouse Y") * Sensitivity * Time.fixedDeltaTime * SensitivityMultiplier;
Vector3 rotation = targetCamera.transform.localRotation.eulerAngles;
desiredX = rotation.y + mouseX;
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, -90f, 90f);
targetCamera.transform.localRotation = Quaternion.Euler(xRotation, desiredX, 0);
}
And here's the first of two bits of code for the asteroid: GravityCtrl
public float gravity = 10f;
private void OnTriggerEnter(Collider other)
{
if (other.GetComponent<GravityCtrl>())
{
other.GetComponent<GravityCtrl>().gravity = this.GetComponent<GravityOrbit>();
}
Here's the second: GravityOrbit
public GravityOrbit gravity;
private Rigidbody rb;
public float rotationSpeed = 20f;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void FixedUpdate()
{
if (gravity)
{
Vector3 gravityUp = Vector3.zero;
gravityUp = (transform.position - gravity.transform.position).normalized;
Vector3 localUp = transform.up;
Quaternion targetrotation = Quaternion.FromToRotation(localUp, gravityUp) * transform.rotation;
transform.up = Vector3.Slerp(transform.up, gravityUp, rotationSpeed * Time.deltaTime);
rb.AddForce((-gravityUp * gravity.gravity) * rb.mass);
}
Related
Good day,
I am making a first-person-view game. That works fine, but whenever I get on a hill/mountain etc. it starts freaking out. The player/camera starts rotating for no reason.
Note: I got some bits of code from external sources, so I don't fully comprehend every bit.
Here is the relevant code:
fpc script:
public float turnSpeed = 4.0f;
public float moveSpeed = 2.0f;
public float minTurnAngle = -90.0f;
public float maxTurnAngle = 90.0f;
private float rotX;
void Update()
{
MouseAiming();
KeyboardMovement();
}
void MouseAiming()
{
// get the mouse inputs
float y = Input.GetAxis("Mouse X") * turnSpeed;
rotX += Input.GetAxis("Mouse Y") * turnSpeed;
// clamp the vertical rotation
rotX = Mathf.Clamp(rotX, minTurnAngle, maxTurnAngle);
// rotate the camera
transform.eulerAngles = new Vector3(-rotX, transform.eulerAngles.y + y, 0);
}
void KeyboardMovement()
{
Vector3 dir = new Vector3(0, 0, 0);
dir.x = Input.GetAxis("Horizontal");
dir.z = Input.GetAxis("Vertical");
transform.Translate(dir * moveSpeed * Time.deltaTime);
}
MouseLookScript:
private PlayerInputActions controls;
[SerializeField] float mouseSensivity = 15f;
private float xRotation = 0f;
private Vector2 mouseLook;
private Transform playerBody;
private void Awake()
{
playerBody = transform.parent;
controls = new PlayerInputActions();
Cursor.lockState = CursorLockMode.Locked;
}
private void Update()
{
Look();
}
private void Look()
{
mouseLook = controls.Player.Look.ReadValue<Vector2>();
float mouseX = mouseLook.x * mouseSensivity * Time.deltaTime;
float mouseY = mouseLook.y * mouseSensivity * Time.deltaTime;
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, -90f, 90f);
transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
playerBody.Rotate(Vector2.up, mouseX);
}
private void OnEnable()
{
controls.Enable();
}
private void OnDisable()
{
controls.Disable();
}
Hopefully someone will be able to help me!
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.
I even set up public variables to see if was getting any input, and it isn't. I even copied and pasted the names directly from the project settings page.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class vehicle : MonoBehaviour
{
private Vector3 thrusterInput;
public float rotationSpeed = 10f;
public float rotSmoothSpeed = 10f;
private Quaternion smoothedRot = Quaternion.identity;
private Quaternion targetRot;
Body[] bodies;
public Rigidbody rigidbody;
public float thrustStrength = 10f;
// Start is called before the first frame update
void Start()
{
bodies = FindObjectsOfType<Body>();
}
// Update is called once per frame
void Update()
{
foreach(Body body in bodies)
{
float sqrDst = (body.transform.position - transform.position).sqrMagnitude;
Vector3 forceDir = (body.transform.position - transform.position).normalized;
Vector3 acceleration = forceDir * Universe.gravitationalConstant * body.rigid.mass / sqrDst;
rigidbody.AddForce(acceleration, ForceMode.Acceleration);
}
Vector3 thrustDir = transform.TransformVector(thrusterInput);
rigidbody.AddForce(thrustDir * thrustStrength, ForceMode.Acceleration);
rigidbody.MoveRotation(smoothedRot);
}
void HandleMovement()
{
float thrustInputX = Input.GetAxis("Horizontal");
float thrustInputY = Input.GetAxis("Ascent");
float thrustInputZ = Input.GetAxis("Vertical");
thrusterInput = new Vector3(thrustInputX, thrustInputY, thrustInputZ);
float yawInput = Input.GetAxis("Mouse X") * rotationSpeed;
float pitchInput = Input.GetAxis("Mouse Y") * rotationSpeed;
float rollInput = Input.GetAxis("Roll") * rotationSpeed;
Quaternion yaw = Quaternion.AngleAxis(yawInput, transform.up);
Quaternion pitch = Quaternion.AngleAxis(pitchInput, transform.right);
Quaternion roll = Quaternion.AngleAxis(rollInput, transform.forward);
targetRot = yaw * pitch * roll * targetRot;
smoothedRot = Quaternion.Slerp(transform.rotation, targetRot, Time.deltaTime * rotSmoothSpeed);
}
}
Sorry if the indents are all messed up, stackoverflow wasn't letting me use tab for some reason.
Your HandleMovement() is not called from anywhere. You need to put it in Update()
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 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);
}
}