Player gravity turns off while i move in Unity - c#

I am quite new to unity and I have two scripts, one for gravity and one for player movement as the names suggest. The reason I am using a gravity script is that the third person movement doesn't support using a rigidbody with position and rotation enabled, so I have frozen the position and the rotation inside the rigidbody (which turns off gravity in the rigidbody). I made the Gravity script myself but I followed a tutorial on the player movement script because I have no idea how to make third person movement so I don't really know what is going on in the movement script.
Movement script:
public class ThirdPersonMovement : MonoBehaviour
{
public CharacterController controller;
public Transform cam;
public float speed = 6f;
public float turnSmoothTime = 0.1f;
float turnSmoothVelocity;
void Update()
{
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
UnityEngine.Vector3 direction = new UnityEngine.Vector3(horizontal, 0f, vertical).normalized;
if (direction.magnitude >= 0.1f)
{
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + cam.eulerAngles.y;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
transform.rotation = UnityEngine.Quaternion.Euler(0f, angle, 0f);
UnityEngine.Vector3 moveDir = UnityEngine.Quaternion.Euler(0f, targetAngle, 0f) * UnityEngine.Vector3.forward;
controller.Move(moveDir.normalized * speed * Time.deltaTime);
}
}
}
Gravity script:
public class gravityScript : MonoBehaviour
{
public float GravitySpeed = -0.03f;
public bool GravityCheck = false;
void OnCollisionEnter(Collision col)
{
if (col.gameObject.name == "Terrain0_0")
{
GravityCheck = true;
}
}
void OnCollisionExit(Collision col)
{
GravityCheck = false;
}
void Update()
{
if (GravityCheck == false)
{
transform.Translate(0, GravitySpeed, 0);
}
}
}
Thank you in advance :)

I don't know what happened but when I opened it today (the day after posting) it was working fine. It was likely just a bug that got fixed after a restart.

Related

Unity need character to rotate to face movement direction on planetoid

we are working on a student project and we chose to do a Mario Galaxy style platformer with planetoids and gravity (kind of a big mistake for my first coding project but I cannot back out of it now) but I am having a hard time to get the character to face it's movement direction without absolutely spazzing out.
I have only been coding for around 2 months so please excuse me being useless at trying to figure this out.
This is the code I use for movement for the character
using System.Collections.Generic;
using UnityEngine;
public class SC_RigidbodyWalker : MonoBehaviour
{
public float speed = 5.0f;
public bool canJump = true;
public float jumpHeight = 2.0f;
public Camera playerCamera;
public float lookSpeed = 2.0f;
public float lookXLimit = 60.0f;
bool grounded = false;
Rigidbody r;
Vector2 rotation = Vector2.zero;
float maxVelocityChange = 10.0f;
void Awake()
{
r = GetComponent<Rigidbody>();
r.freezeRotation = true;
r.useGravity = false;
r.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
rotation.y = transform.eulerAngles.y;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
void Update()
{
}
void FixedUpdate()
{
if (grounded)
{
// Calculate how fast we should be moving
Vector3 forwardDir = Vector3.Cross(transform.up, -playerCamera.transform.right).normalized;
Vector3 rightDir = Vector3.Cross(transform.up, playerCamera.transform.forward).normalized;
Vector3 targetVelocity = (forwardDir * Input.GetAxis("Vertical") + rightDir * Input.GetAxis("Horizontal")) * speed;
Vector3 velocity = transform.InverseTransformDirection(r.velocity);
velocity.y = 0;
velocity = transform.TransformDirection(velocity);
Vector3 velocityChange = transform.InverseTransformDirection(targetVelocity - velocity);
velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
velocityChange.y = 0;
velocityChange = transform.TransformDirection(velocityChange);
r.AddForce(velocityChange, ForceMode.VelocityChange);
if (Input.GetButton("Jump") && canJump)
{
r.AddForce(transform.up * jumpHeight, ForceMode.VelocityChange);
}
}
grounded = false;
}
void OnCollisionStay()
{
grounded = true;
}
}
And here are the code for the gravity functions
using System.Collections.Generic;
using UnityEngine;
public class SC_PlanetGravity : MonoBehaviour
{
public Transform planet;
public bool alignToPlanet = true;
float gravityConstant = 9.8f;
Rigidbody r;
void Start()
{
r = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
Vector3 toCenter = planet.position - transform.position;
toCenter.Normalize();
r.AddForce(toCenter * gravityConstant, ForceMode.Acceleration);
if (alignToPlanet)
{
Quaternion q = Quaternion.FromToRotation(transform.up, -toCenter);
q = q * transform.rotation;
transform.rotation = Quaternion.Slerp(transform.rotation, q, 1);
}
}
}
I can propose an alternative approach which I believe will simplify the problem, should you choose. If the root of your character is positioned at the center of the planetoid, then all movement can be handled as a rotation on root and you won't be fighting the inertia of the character or needing to orient it to the planetoid. Jumping could be handled by adding another child below the root that can slide up and down. Hope this helps!
I managed to get it working by having a new script added to the player avatar.
Here is the code, it's basically a copy paste of a part of the RigidBodyWalker script with some more added parts. It's not perfect but it works like I wanted it to.
using System.Collections.Generic;
using UnityEngine;
public class InputRotation : MonoBehaviour
{
public Camera playerCamera;
public float speed;
public float rotationSpeed;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//float horizontalInput = Input.GetAxis("Horizontal");
//float verticalInput = Input.GetAxis("Vertical");
}
private void FixedUpdate()
{
Vector3 forwardDir = Vector3.Cross(transform.up, -playerCamera.transform.right).normalized;
Vector3 rightDir = Vector3.Cross(transform.up, playerCamera.transform.forward).normalized;
Vector3 targetVelocity = (forwardDir * Input.GetAxis("Vertical") + rightDir * Input.GetAxis("Horizontal")) * speed;
if(targetVelocity != Vector3.zero)
{
Quaternion toRotation = Quaternion.LookRotation(targetVelocity, transform.up);
transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation, rotationSpeed * Time.deltaTime);
}
}
}

Character rotation relative with camera forward?

I spent some time already and still cant figure it out by myself.
The problem is i can"t rotate character forward to move the way i pointing my camera.
To move camera i use cinemachine with Orbital Transposer and normal Composer.
My Movement script to let you know with what I work :
public class PlayerMovement : MonoBehaviour
{
public float m_Impulse = 1f;
public bool grounded = false;
public float groundCheckDistance;
private float bufferCheckDistance = 0.02f;
public float airMultiplier = 0.2f;
float horizontalInput;
float verticalInput;
public float groundDrag;
Rigidbody m_Rigidbody;
Vector3 moveDirection;
public float m_Speed = 5f;
public float m_runSpeed = 7f;
void Start()
{
m_Rigidbody = GetComponent<Rigidbody>();
m_Rigidbody.freezeRotation = true;
}
void FixedUpdate()
{
horizontalInput = Input.GetAxis("Horizontal");
verticalInput = Input.GetAxis("Vertical");
// calculate movement direction
moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput;
if (Input.GetKey(KeyCode.Space) & grounded)
{
m_Rigidbody.AddForce(Vector3.up * m_Impulse * 2);
}
if (Input.GetKey(KeyCode.LeftShift))
{
m_Rigidbody.AddForce(moveDirection * m_runSpeed, ForceMode.Force);
}
else
{
m_Rigidbody.AddForce(moveDirection * m_Speed, ForceMode.Force);
}
}
void Update()
{
groundCheckDistance = (GetComponent<CapsuleCollider>().height / 2) + bufferCheckDistance;
RaycastHit hit;
if (Physics.Raycast(transform.position, -transform.up, out hit, groundCheckDistance))
{
grounded = true;
}
else
{
grounded = false;
}
if (grounded)
{
m_Rigidbody.drag = groundDrag;
}
else if (!grounded)
{
moveDirection *= airMultiplier;
m_Rigidbody.drag = 2;
}
}
Hope you know how to make it works, Thank You in advance.
P.S. My camera script was left with Cursor.LockMode only cuz i messed something up rly bad and my camera was bugged.

Unity 2D Character Vibrates When Touching Wall

Like the title says when i walk into a wall i start to vibrate. It doesn't affect gameplay just graphics i believe. The game is a 2D platformer using rigidbody 2D. I am new to game dev so what you fixed could you please tell me how you fix it. Thank you.
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float MovementSpeed = 1;
public float JumpForce = 1;
private Rigidbody2D _rigidbody;
private float coyoteTime = 0.2f;
private float coyoteTimeCounter;
private float jumpBufferTime = 0.05f;
private float jumpBufferCounter;
[SerializeField] private Rigidbody2D rigidbody2D;
[SerializeField] private Transform groundCheck;
[SerializeField] private LayerMask groundLayer;
private bool isGrounded()
{
return Physics2D.OverlapCircle(groundCheck.position, 0.2f, groundLayer);
}
private void Start()
{
_rigidbody = GetComponent<Rigidbody2D>();
}
private void Update()
{
if (isGrounded())
{
coyoteTimeCounter = coyoteTime;
}
else
{
coyoteTimeCounter -= Time.deltaTime;
}
if (Input.GetButtonDown("Jump"))
{
jumpBufferCounter = jumpBufferTime;
}
else
{
jumpBufferCounter -= Time.deltaTime;
}
var movement = Input.GetAxis("Horizontal");
transform.position += new Vector3(movement, 0, 0) * Time.deltaTime * MovementSpeed;
if (coyoteTimeCounter > 0f && jumpBufferCounter > 0f)
{
_rigidbody.velocity = new Vector2(_rigidbody.velocity.x, JumpForce);
jumpBufferCounter = 0f;
}
if (Input.GetButtonUp("Jump") && _rigidbody.velocity.y > 0f)
{
_rigidbody.velocity = new Vector2(_rigidbody.velocity.x, _rigidbody.velocity.y * 0.5f);
coyoteTimeCounter = 0f;
}
}
}
Sorry if the code is sort of sloppy. I am using multiple tutorials to make the movement perfect for me.
Ah! I have had this problem before.
The reason the vibration is happening, is because you are adding a force manually through rigidbody.velocity. The better (And more efficient) way to do it is through rigidbody.AddForce(). This should allow for the rigidbody to calculate physics much smoother.
The only issue that may arise is if you plan for the player to have a constant speed. If you AddForce(1000) with no other arguments, the character will start accelerating, instead of moving at a constant speed.
If you need the player to move at a constant speed, you can append a ForceMode to! I am not sure what one you would use, but that my idea. One example would be rigidbody.AddForce(1000, ForceMode.VelocityChange),

Unity player movement on moving planet

I am making a game involving orbital physics. I was successfully able to implement this with a slightly modified version of Brackeys gravity tutorial https://youtu.be/Ouu3D_VHx9o, this is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class gravity : MonoBehaviour
{
public GameObject self;
public Rigidbody rb;
public Vector3 initialVelocity;
const float G = 66.74f;
public static List<gravity> Attractors;
public bool isAttractable;
private void Awake()
{
rb.AddForce(initialVelocity);
}
private void FixedUpdate()
{
//planets
if (isAttractable == false)
{
foreach (gravity attractor in Attractors)
{
if (attractor != this)
Attract(attractor);
}
}
//players, spaceships, astroids, ect
if (isAttractable == true)
{
foreach (gravity attractor in Attractors)
{
if (attractor != this)
Attract(attractor);
}
}
}
void OnEnable()
{
if( isAttractable == false)
{
if (Attractors == null)
Attractors = new List<gravity>();
Attractors.Add(this);
}
}
void OnDisable()
{
if (isAttractable == false)
{
Attractors.Remove(this);
}
}
void Attract(gravity objToAttract)
{
Rigidbody rbToAttract = objToAttract.rb;
Vector3 direction = -1 * (rb.position - rbToAttract.position);
Vector3 Force = direction.normalized * (G * ((rb.mass * rbToAttract.mass) / direction.sqrMagnitude));
rb.AddForce(Force);
}
public GameObject GetClosestPlanet()
{
GameObject close = null;
float minDist = Mathf.Infinity;
foreach (gravity attracor in Attractors)
{
float dist = Vector3.Distance(attracor.transform.position, transform.position);
if (dist < minDist)
{
close = attracor.transform.gameObject;
minDist = dist;
}
}
return close;
}
}
Then for player movement I used (and modified) Sebastian Lagues tutorial https://youtu.be/TicipSVT-T8,
this resulted in this code for the player controller:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playerController : MonoBehaviour
{
public float mouseSensitivityX = 250f;
public float mouseSensitivityY = 250f;
Transform cameraT;
float verticalLookRot;
private Rigidbody rb;
Vector3 moveAmount;
Vector3 smootgMoveVelocity;
public float moveSpeed = 15;
public float jumpForce = 220;
public LayerMask groundedMask;
public bool grounded;
public GameObject currentPlanet;
private gravity playerGravity;
private void Awake()
{
rb = GetComponent<Rigidbody>();
playerGravity = GetComponent<gravity>();
Cursor.lockState = CursorLockMode.Locked;
cameraT = Camera.main.transform;
}
void Update()
{
currentPlanet = playerGravity.GetClosestPlanet();
//camera
transform.Rotate(Vector3.up * Input.GetAxis("Mouse X") * Time.deltaTime * mouseSensitivityX);
verticalLookRot += Input.GetAxis("Mouse Y") * Time.deltaTime * mouseSensitivityY;
verticalLookRot = Mathf.Clamp(verticalLookRot, -60, 60);
cameraT.localEulerAngles = Vector3.left * verticalLookRot;
//move input
Vector3 moveDir = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")).normalized;
Vector3 targetMoveAmount = moveDir * moveSpeed;
moveAmount = Vector3.SmoothDamp(targetMoveAmount, targetMoveAmount, ref smootgMoveVelocity, .15f);
//level on planet
if(currentPlanet != null)
{
transform.rotation = Quaternion.FromToRotation(transform.up, (transform.position - currentPlanet.transform.position).normalized) * transform.rotation;
}
//jump
if (Input.GetButtonDown("Jump"))
{ if(grounded)
{
rb.AddForce(transform.up * jumpForce);
print("u jumped");
}
}
}
private void FixedUpdate()
{
//move
rb.MovePosition(rb.position + transform.TransformDirection(moveAmount) * Time.fixedDeltaTime);
//check if on ground
Ray ray = new Ray(transform.position, -transform.up);
RaycastHit hit;
grounded = Physics.Raycast(ray, out hit, transform.localScale.y + 1.1f, groundedMask);
}
}
Now for the issue, this systems works fine when the planet the player is walking on is stationary. As in there are no other attracting bodys in the system and the planet has no initial velocity. However if the planet is moving the player will bounce up and down uncontrollably and will not be able to walk a certain distance away from the planets farthest point from its direction of movement. Here is a recording of this: https://youtu.be/noMekosb7CU
Does anyone know what is causing the bouncing and walking restrictions and how I can fix it?
Some notes on suggested solutions that haven't worked:
-set the planet as the players parent object, same results
-increase players mass, same results
-set the players velocity to += the planets velocity, same results or player goes into infinity
For me it seems to be working "correctly".
Looking like your player is attracted correctly and when the planet moves, your player is quickly moving towards the planet.
I think you could temporarily assign the player as a child gameobject to the planet he's walking on and he should probably move correctly along the planet coordinates and not on global coordinates. (If it works, you could just always assign the player as a child gameObject to every new planet that he visits)

Rigidbody GameObject is restricted in movement while moving

So I'm pretty new to Unity, but I managed to put together a script that moves the player around a plane. Problem is, after moving a certain distance, it won't move any further. I want the movement to be unrestricted.
using UnityEngine;
public class Movement_Player : MonoBehaviour
{
public Rigidbody rb;
public float default_speed;
public float sprint_multiplier;
private float speed;
private void Update()
{
speed = default_speed;
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(horizontal, 0.0f, vertical);
if (Input.GetKey(KeyCode.LeftShift))
speed = speed * sprint_multiplier;
else
speed = default_speed;
rb.MovePosition(movement * speed);
}
}
You need to move your MovePosition outside of Update to FixedUpdated.
FixedUpdate is the right place to put physic code.
You need too to reset your movement vector on each update if you like to get the new displacement vector to skip a drag movement and need to add timefactor * Time.fixedDeltaTime
using UnityEngine;
public class Movement_Player : MonoBehaviour
{
public Rigidbody rb;
public float default_speed;
public float sprint_multiplier;
private float speed;
private void Update()
{
Vector3 movement = Vector3.zero
speed = default_speed;
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(horizontal, 0.0f, vertical);
if (Input.GetKey(KeyCode.LeftShift))
speed = speed * sprint_multiplier;
else
speed = default_speed;
}
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * speed * Time.fixedDeltaTime);
}
}

Categories