Hi ! :) Sooo I kinda have a problem in Unity3d :
I use the following script to make my character move, my character only has a RigidBody, Capsule Collider and this Script (CharacterControllerCode.cs) attached. When i leave the script unchecked, the gravity applies as it should to the character but when I activate the script, the grvity does not apply anymore and the Character stays at the Y position assigned in the editor (Transform Component).
Does anyone have the smallest clue why this is happening ?
(i'm very new to c# and unity so i checked out this video to make the code https://www.youtube.com/watch?v=WIl6ysorTE0&list=PLYQCqA5CcgADEN4gGw7qdsqcN9ERUrHbM∈dex=19)
I'm using the New Input System Package btw
Script below ↓
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerControllerCode : MonoBehaviour
{
private PlayerControlInputs playerControlsAsset;
private InputAction moveAction;
private Rigidbody rigBod;
[SerializeField]
private float movementForce = 1f;
[SerializeField]
private float maxSpeed = 5f;
[SerializeField]
private float jumpForce = 5f;
[SerializeField]
private float dashForce = 5f;
private Vector3 forceDirection = Vector3.zero;
[SerializeField]
private Camera playerCamera;
private void Awake()
{
rigBod = this.GetComponent<Rigidbody>();
playerControlsAsset = new PlayerControlInputs();
}
private void OnEnable()
{
playerControlsAsset.PlayerActions.Jump.started += DoJump;
playerControlsAsset.PlayerActions.Dash.started += DoDash;
moveAction = playerControlsAsset.PlayerActions.Move;
playerControlsAsset.PlayerActions.Enable();
}
private void OnDisable()
{
playerControlsAsset.PlayerActions.Jump.started -= DoJump;
playerControlsAsset.PlayerActions.Dash.started -= DoDash;
playerControlsAsset.PlayerActions.Disable();
}
private void FixedUpdate() {
LookAt();
IsGrounded();
forceDirection += moveAction.ReadValue<Vector2>().x * GetCameraRight(playerCamera) * movementForce;
forceDirection += moveAction.ReadValue<Vector2>().y * GetCameraForward(playerCamera) * movementForce;
rigBod.AddForce(forceDirection, ForceMode.Impulse);
forceDirection = Vector3.zero;
Vector3 horizontalVelocity = rigBod.velocity;
horizontalVelocity.y = 0;
if(rigBod.velocity.y < 0f)
{
rigBod.velocity += Vector3.down * Physics.gravity.y * Time.fixedDeltaTime;
}
if(horizontalVelocity.sqrMagnitude > maxSpeed * maxSpeed)
{
rigBod.velocity = horizontalVelocity.normalized * maxSpeed + Vector3.up * rigBod.velocity.y;
}
}
private void LookAt()
{
Vector3 direction = rigBod.velocity;
direction.y = 0f;
if(moveAction.ReadValue<Vector2>().sqrMagnitude > 0.1f && direction.sqrMagnitude > 0.1f)
{
this.rigBod.rotation = Quaternion.LookRotation(direction, Vector3.up);
}
else
{
rigBod.angularVelocity = Vector3.zero;
}
}
private Vector3 GetCameraRight(Camera playerCamera)
{
Vector3 right = playerCamera.transform.right;
right.y = 0;
return right.normalized;
}
private Vector3 GetCameraForward(Camera playerCamera)
{
Vector3 forward = playerCamera.transform.forward;
forward.y = 0;
return forward.normalized;
}
private void DoJump(InputAction.CallbackContext obj)
{
if(IsGrounded())
{
forceDirection += Vector3.up * jumpForce;
}
}
private void DoDash(InputAction.CallbackContext obj)
{
forceDirection += moveAction.ReadValue<Vector2>().y * GetCameraForward(playerCamera) * dashForce;
}
private bool IsGrounded()
{
Ray ray = new Ray(this.transform.position + Vector3.up * 0.05f, Vector3.down);
if(Physics.Raycast(ray, out RaycastHit hit, 0.1f))
{return true;}
else
{return false;}
}
}
My Hierarchy
My Character's Components
So turns out i was just being blind and there was a simple sign error :
Instead of add (+=) here :
if(rigBod.velocity.y < 0f)
{
rigBod.velocity += Vector3.down * Physics.gravity.y * Time.fixedDeltaTime;
}
It should have been substract (-=)
if(rigBod.velocity.y < 0f)
{
rigBod.velocity -= Vector3.down * Physics.gravity.y * Time.fixedDeltaTime;
}
when you set the rigidbody's velocity from the script, it overrides the velocity calculated by the rigidbody.
You should either use your own physics calculation or only apply forces to unity's rigidbody, but don't do both as it creates this kind of conflict.
Related
I'm developping a 3D game Unity with a squirrel as the player.
I'm struggling with a problem of slopes. I know, there are a bunch of tutorial to go down a slope whithout 'floating in the air while walking' but I didn't find a fine solution. I think it's because of the horizontal animations of the squirrel (maybe). I have tried with addForce, with a modified speed, with gravity... (maybe I implemented it wrong). I know I can check if I'm in the air or not with CharacterController.isGrounded but I can't force the squirrel to stick on the slope while running or walking. I'm sorry by advance if my question is too vague or simple.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System;
public class Squirrel : MonoBehaviour {
Animator squirrel;
public float gravity = 1.0f;
private Vector3 moveDirection = Vector3.zero;
float axisH, axisV;
public static int munitions = 0;
Rigidbody rb;
[SerializeField]
float walkSpeed = 2f, runSpeed = 8f, rotSpeed = 100f, jumpForce = 350;
private bool isJumpKeyDown = false;
[SerializeField] bool isJumping = false;
Animator characterAnimator;
int JumpCount = 0;
public int MaxJumps = 1; //Maximum amount of jumps (i.e. 2 for double jumps)
[SerializeField] GameObject nb_munitions;
CharacterController characterController;
// Use this for initialization
void Start () {
munitions = 0;
squirrel = GetComponent<Animator>();
rb = GetComponentInChildren<Rigidbody>();
characterAnimator = GetComponent<Animator>();
JumpCount = MaxJumps;
characterController = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
GetInput();
nb_munitions.GetComponent<Text>().text = "Glands : " + munitions; //Affichage du score
Move();
}
private void FixedUpdate()
{
if (isJumpKeyDown)
{
squirrel.SetTrigger("jump");
JumpCount -= 1;
isJumpKeyDown = false;
}
}
public void GetInput()
{
axisV = Input.GetAxis("Vertical");
axisH = Input.GetAxis("Horizontal");
}
private void Move()
{
if (characterController.isGrounded)
{
//On the ground
}
else
{
//on the air
}
if (axisV > 0)
{
if (Input.GetKeyDown(KeyCode.LeftControl))
{
transform.position += Vector3.forward * walkSpeed * Time.deltaTime;
squirrel.SetBool("walk", true);
}
else
{
transform.position += Vector3.forward * runSpeed * Time.deltaTime;
squirrel.SetFloat("run", axisV);
squirrel.SetBool("walk", false);
}
}
else
{
squirrel.SetFloat("run", 0);
}
if (axisH != 0 && axisV == 0)
{
squirrel.SetFloat("h", axisH);
}
else
{
squirrel.SetFloat("h", 0);
}
if (axisH != 0)
{
transform.Rotate(Vector3.up * rotSpeed * Time.deltaTime * axisH);
}
if (Input.GetKeyDown(KeyCode.Space))
{
if (JumpCount > 0)
{
isJumpKeyDown = true;
}
}
//Call munitions
if (Input.GetKeyDown(KeyCode.LeftShift))
{
if (Squirrel.munitions > 0)
{
SpawnerScript.Instance.NewSpawnRequest();
munitions--;
}
}
}
}
You can try to get the angle of the slope and make it the pitch for the mesh of the squirrel.
I finally found the problem. My C# script "overwrited" the CharacterController and did not allow the squirrel to go down the slopes. Make sure you follow a move script that "respects" the CharacterController (if you pick one or you'll be fighting windmills).
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);
}
}
}
I have a player in the game, which I can move using the keyboard and rotate only on the horizontal axis using the mouse. That means, I can aim only horizontally and I can not aim it up and down.
I have the Main Camera and another VM Camera from Cinemachine. The current state of the game is like this:
On the horizontal axis, I rotate the player, but on the vertical axis I only want the player's camera/FOV to be moved up and down.
My movement script attached to the player is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController characterController;
public float speed = 35f;
public Animator animator;
// camera and rotation
public Transform cameraHolder;
public float mouseSensitivity = 2f;
public float upLimit = 50;
public float downLimit = -50;
// gravity
private float gravity = 9.87f;
private float verticalSpeed = 0;
void Update()
{
Move();
Rotate();
}
public void Rotate()
{
float horizontalRotation = Input.GetAxis("Mouse X");
float verticalRotation = Input.GetAxis("Mouse Y");
transform.Rotate(0, horizontalRotation * mouseSensitivity, 0);
cameraHolder.Rotate(-verticalRotation * mouseSensitivity, 0, 0);
Vector3 currentRotation = cameraHolder.localEulerAngles;
if (currentRotation.x > 180) currentRotation.x -= 360;
currentRotation.x = Mathf.Clamp(currentRotation.x, upLimit, downLimit);
cameraHolder.localRotation = Quaternion.Euler(currentRotation);
}
private 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);
}
}
This is the code i use, it works for me, it's super easy to implement, and stops moving the camera when you aren't focusing the game, is the script from one of Brackey's tutorials modified for this purpose:
using UnityEngine;
public class CameraController : MonoBehaviour
{
public PlayerController player;
public float sensitivity = 150f;
public float clampAngle = 85f;
public bool look = true;
private float verticalRotation;
private float horizontalRotation;
private void Start()
{
verticalRotation = transform.localEulerAngles.x;
horizontalRotation = player.transform.eulerAngles.y;
// Defines the state of the cursor
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
private void Update()
{
// Looks around if the user is in the window
if (look)
{
Look();
}
Debug.DrawRay(transform.position, transform.forward * 2, Color.red);
// If the player presses ESC while in the game, it unlocks the cursor
if (look && Input.GetKeyDown(KeyCode.Escape))
{
look = false;
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
else if (Input.GetMouseButtonDown(0) && !look)
{
look = true;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
}
private void Look()
{
float _mouseVertical = -Input.GetAxis("Mouse Y");
float _mouseHorizontal = Input.GetAxis("Mouse X");
verticalRotation += _mouseVertical * sensitivity * Time.deltaTime;
horizontalRotation += _mouseHorizontal * sensitivity * Time.deltaTime;
verticalRotation = Mathf.Clamp(verticalRotation, -clampAngle, clampAngle);
transform.localRotation = Quaternion.Euler(verticalRotation, 0f, 0f);
player.transform.rotation = Quaternion.Euler(0f, horizontalRotation, 0f);
}
}
When my player jumps and lands on something it always shakes around like that.
Also, sometimes when I jump a few times in a row (about 10 times) it would go through the ground and just fall down.
I tried using a collider and I don't see anything in the movement script that may cause this. I'm currently using Unity 2018.4.20f1 and Visual Studio c#.
Any solutions?
Player Movement script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public static int movespeed = 6;
public Vector3 userDirection = Vector3.right;
public Rigidbody rb;
public bool isGrounded;
Vector3 jumpMovement;
bool jump = false;
[SerializeField]
float jumpHeight = 1.8f, jumpSpeed = 8f;
void Start()
{
rb = GetComponent<Rigidbody>(); }
void OnCollisionStay()
{
isGrounded = true;
}
public float fallMultiplier = 3.5f;
public float lowJumpMultiplier = 2f;
void Update()
{
//movement
transform.Translate(userDirection * movespeed * Time.deltaTime);
if (Input.GetButton("Jump") && !jump)
StartCoroutine(Jump());
}
IEnumerator Jump()
{
float originalHeight = transform.position.y;
float maxHeight = originalHeight + jumpHeight;
jump = true;
yield return null;
while (transform.position.y < maxHeight)
{
transform.position += transform.up * Time.deltaTime * jumpSpeed;
yield return null;
}
while (transform.position.y > originalHeight)
{
transform.position -= transform.up * Time.deltaTime * jumpSpeed;
yield return null;
}
rb.useGravity = true;
jump = false;
yield return null;
}
}
Edit: I didn't notice the link.
You are forcing it to go down to originalHeight, without checking if there is an object higher than that. You can remove
while (transform.position.y > originalHeight)
{
transform.position -= transform.up * Time.deltaTime * jumpSpeed;
yield return null;
}
and let the rigidbody control gravity (by setting rb.useGravity = true; as you did).
Original answer:
You are probably going below the ground when calling transform.position -= transform.up * Time.deltaTime * jumpSpeed;. Try adding
if (transform.position.y < originalHeight)
transform.position = new Vector3(transform.position.x, originalHeight, transform.position.z)
after it.
I want to be able to jump by pressing on space key inside a place like home or space station and also outside.
This is the player controller script attached to a capsule :
It was working fine until I added the jump part. At the top I added this 3 lines :
public float jumpSpeed = 8.0F;
public float gravity = 20.0F;
private Vector3 moveDirection = Vector3.zero;
Then in the Update added :
if (controller.isGrounded && Input.GetButton("Jump"))
{
moveDirection.y = jumpSpeed;
}
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
But I don't have the variable controller.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float speed = 10.0F;
public float jumpSpeed = 8.0F;
public float gravity = 20.0F;
private Vector3 moveDirection = Vector3.zero;
// Start is called before the first frame update
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
float translation = Input.GetAxis("Vertical") * speed;
float straffe = Input.GetAxis("Horizontal") * speed;
translation *= Time.deltaTime;
straffe *= Time.deltaTime;
transform.Translate(straffe, 0, translation);
if (controller.isGrounded && Input.GetButton("Jump"))
{
moveDirection.y = jumpSpeed;
}
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
if (Input.GetKeyDown("escape"))
{
Cursor.lockState = CursorLockMode.Locked;
}
}
}
And this is the cam mouse look script attached to the main camera that is child of the capsule :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CamMouseLook : MonoBehaviour
{
public float sensitivity = 5.0f;
public float smoothing = 2.0f;
Vector2 mouseLook;
Vector2 smoothV;
GameObject character;
// Start is called before the first frame update
void Start()
{
character = this.transform.parent.gameObject;
}
// Update is called once per frame
void Update()
{
var md = new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
md = Vector2.Scale(md, new Vector2(sensitivity * smoothing, sensitivity * smoothing));
smoothV.x = Mathf.Lerp(smoothV.x, md.x, 1f / smoothing);
smoothV.y = Mathf.Lerp(smoothV.y, md.y, 1f / smoothing);
mouseLook += smoothV;
mouseLook.y = Mathf.Clamp(mouseLook.y, -90f, 90f);
transform.localRotation = Quaternion.AngleAxis(-mouseLook.y, Vector3.right);
character.transform.localRotation = Quaternion.AngleAxis(mouseLook.x, character.transform.up);
}
}
Have you thought about applying a force?
public Rigidbody myphysic;
public float forceofjump = 100f; // or minor or more....
void Awake()
{
myphysic= transform.GetComponent<Rigidbody>();
}
void FixedUpdate()
{
if (controller.isGrounded && Input.GetButton("Jump"))
{
myphysic.AddForce( transform.up * forceofjump, ForceMode.Impulse);
}
}
Vector3.zero is wrong beacouse set all movement vector to zero! so = no actions!
or, exemple:
Vector3 moveDirection = new Vector3(0, 10, 0);
what does it mean:
new Vector3(X=stop, Y=10 of force, Z=stop);