I'm following brackey's fps movement tutorial. I've copied all the code correctly.
but the isGrounded value is always false, even if the player is touching the ground
The Ground is also on the layer "Ground"
and here's my code
// non related varriables
public CharacterController controller;
public float speed = 12f;
//the gravity
public float gravity = -9.81f;
//the transform groundcheck, it's attached to the groundcheck object
public Transform groundCheck;
public float groundDistance = 0.4f;
// layer mask groundmask.
public LayerMask groundMask;
Vector3 velocity;
bool isGrounded;
// Update is called once per frame
void Update()
{
// check if the groundcheck transform is colliding with the ground, which always for //some reason returns false.
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
// make the set y velocity to 0. when groundcheck touches the ground
if (isGrounded && velocity.y < 0)
{
velocity.y = 0;
}
// the movement code (not related)
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
// move the player acording the gravity.
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
Since you're using CharacterController, you can use a build-in function
void Update()
{
if (controller.isGrounded && velocity.y < 0)
{
velocity.y = 0;
}
//the rest of your code
}
CharacterController docs
Two things.
First, you don't need to pass in that layer mask. Layer masks are only for when you are trying to ignore another object not detect it. So get rid of that ground mask in CheckSphere.
Second, make sure your ground has a collider and is set on. Unity physics engine looks for colliders and if it doesn't see one it won't register anything.
Related
Im trying to learn coding and watch youtube tutorials learn to code and I came across this code that I put in my prototype game, Im just asking what should I add to make my character do a double jump?
Code:
public class fpsmovement : MonoBehaviour
{
private float yaw = 0.0f, pitch = 0.0f;
private Rigidbody rb;
[SerializeField] float movementspeed = 5.0f, sensitivity = 2.0f;
// Start is called before the first frame update
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
rb = gameObject.GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.Space) && Physics.Raycast(rb.transform.position, Vector3.down, 1 + 0.001f))
rb.velocity = new Vector3(rb.velocity.x, 5.0f, rb.velocity.z);
Look();
}
void FixedUpdate()
{
Movement();
}
void Look()
{
pitch -= Input.GetAxisRaw("Mouse Y") * sensitivity;
pitch = Mathf.Clamp(pitch, -90.0f, 90.0f);
yaw += Input.GetAxisRaw("Mouse X") * sensitivity;
Camera.main.transform.localRotation = Quaternion.Euler(pitch, yaw, 0);
}
void Movement()
{
Vector2 axis = new Vector2(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal")).normalized * movementspeed;
Vector3 forward = new Vector3(-Camera.main.transform.right.z, 0.0f, Camera.main.transform.right.x);
Vector3 wishDirector = (forward * axis.x + Camera.main.transform.right * axis.y + Vector3.up * rb.velocity.y);
rb.velocity = wishDirector;
}
}
First of all you need to check if your player is grounded to be allowed to jump. You problably have a player which can jump again forever like a rocket right now. Then you need to create a boolean variable to check if the player can double jump. Set the variable to true when you jump and set the variable to false when you do the 2nd jump. Also, to allow jump, you should check if the player is grounded OR if can doublejump. There is a lot of tutorials on youtube about this topic, I hope you find the code needed easily.
You can try two methods, "Jump" and "Jump1", the first "Jump" method first uses if to judge whether it is on the ground, if it is allowed to jump on the ground, the "Jump1" method judges if it is not on the ground. On this basis, the code logic for judging the jump state is implemented, and finally the button is reset.
I have a game that generates a maze at the start of the game. The player is dropped into the maze from a height of about 10 feet or so. The problem is that if I click the player object and change the inspector from normal to debug, I see that the character is still continuously generating falling velocity. I have a sphere at the bottom of the character that is supposed to do a ground check but clearly that isn't working. This is the relevant code for one of the ground tiles and the ground check features of the character.
Ground Tile Code in GameManager.cs in Scripts folder.
var tile = Instantiate(_tilePrefab);
tile.transform.Rotate(90, 0, 0);
tile.transform.localPosition = new Vector3((x * tileWidth) + offsetTile, 0, (y * tileWidth) + offsetTile);
tile.gameObject.layer = LayerMask.NameToLayer("Ground");
tile.transform.parent = _mazePrefab;
PlayerMovement.cs in Scripts folder
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController controller;
public float speed = 15f;
public float gravity = -9.8f;
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
Vector3 velocity;
bool isGrounded;
// Update is called once per frame
void Update()
{
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if (isGrounded && velocity.y > 0)
{
velocity.y = 0f;
}
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
}
I have a ground layer created and everything and I have an empty that projects a sphere at the base of my character.
What am I doing wrong?
The problem must be that your gravity resetting isn’t working. I suppose you are using the tutorial from Brackeys — I have used his tutorial before, so I know it works. The problem must be that your gravity resetting. So, I go through your code. I notice there is an if statement meant to reset the velocity when the player is grounded. So, I check the isGrounded variable. The only thing that could set that incorrectly is that the maze doesn’t have the right layer. Your code does set the layer right, so I rule that one out. I then look back at the if statement. The only thing that could set it off is the second term in it:
if (... && velocity.y > 0)
Notice how later in your code the velocity rapidly decreases.
velocity.y += gravity * Time.deltaTime;
Notice how gravity is a negative variable.
float gravity = -9.8f;
And Time.deltaTime is positive. When multiplying positive and negative values, if the number of negative values in the equation is odd the result is negative, and if it is even the result is positive. Therefore, velocity decreases instead of increases.
In the if statement, you check if velocity.y > 0, in other words: if the velocity is greater than 0, do something. But according to the math, velocity is always decreasing, not increasing. But you are detecting if the velocity is above 0, not under it.
Change the if statement to:
if (isGrounded && velocity.y < 0)
Notice how I change the > to a < to detect if it is less than zero.
That would solve your problem and you could go off here, but there is something else that is less important. Notice how after your if statement, you decrease the velocity.
...
if (isGrounded && velocity.y > 0)// «— if statement.
{
velocity.y = 0f;
}
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
velocity.y += gravity * Time.deltaTime;// «—- change velocity.
...
Since after you call the if statement you change it, you won’t need to detect if the velocity is less than 0. This is because the velocity will always be slightly less than 0 at the end of each frame.
There are two things you could do here.
You could remove the second part of the if statement.
You could add the velocity change to the else of the if statement.
For 1:
if (isGrounded)
{
velocity.y = 0f;
}
For 2:
Add:
if (isGrounded)
{
velocity.y = 0f;
}
else
{
velocity.y += gravity * Time.deltaTime;
}
And remove:
controller.Move(move * speed * Time.deltaTime);
//removed this line «—-
controller.Move(velocity * Time.deltaTime);
I am following an FPS tutorial here. Unfortunately, at the end when Brackeys tests out the code, I cannot jump. Here is my player movement script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController controller;
public float speed = 10f;
public float gravity = -10f;
public float jumpHeight = 5f;
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
Vector3 velocity;
bool isGrounded;
void Update()
{
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
if (Input.GetButton("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
}
Here is the screenshot for the code component in the unity editor:
Please help me!
Also, if you need any clarification, do not hesitate to ask!
I have some suggestions for your problem but I am not 100% sure that they will work.
Check that that the layer Ground is attached to the gameobject that is your platform. If you don't know how to do this, check this doc on layers: https://docs.unity3d.com/Manual/Layers.html
Another idea is that of the groundcheck. Make sure the ground check is just below the player.
My final suggestion is that of the key bindings. Make sure that Jump is assigned to your desired button.
I believe these will work. If there are still any problems, comment down below.
I haven't tried the code myself yet, but if you increase the Jumpheight to something like 300 the player should jump up.
This is because your formula:
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
Ends up being smaller than the gravity , so you don't have enough force to jump up.
No need for ground check from Brackeys's FPS code since the character controller has its public isGrounded property.
I created controls for a 3D Platformer game. Somehow the player is falling down very very slowly.
My player object got 2 components, the default capsule collider and the default Rigidbody. I didnt change anything there.
So my code is this one here:
float movementSpeed = 8;
float currentMovementSpeed;
float speedSmoothTime = 0.1f;
float turnSmoothTime = 0.2f;
float jumpPower = 5;
float airControlPercentage = 0.2f;
float turnSmoothVelocity;
float speedSmoothVelocity;
bool isGrounded;
private void FixedUpdate()
{
isGrounded = GroundCheck(); // Is player grounded?
Vector2 inputDirection = (new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"))).normalized;
if (Input.GetButtonDown("Jump") && isGrounded) // Jump handling
Debug.Log("Player Jump");
if (inputDirection != Vector2.zero)
transform.eulerAngles = Vector3.up * Mathf.SmoothDampAngle(transform.eulerAngles.y, Mathf.Atan2(inputDirection.x, inputDirection.y) * Mathf.Rad2Deg + cameraTransform.eulerAngles.y, ref turnSmoothVelocity, GetModifiedSmoothTime(turnSmoothTime)); // Rotate
currentMovementSpeed = Mathf.SmoothDamp(currentMovementSpeed, movementSpeed * inputDirection.magnitude, ref speedSmoothVelocity, GetModifiedSmoothTime(speedSmoothTime));
playerRigid.velocity = transform.forward * currentMovementSpeed + Vector3.up * playerRigid.velocity.y * Time.deltaTime; // Move
currentMovementSpeed = (new Vector2(playerRigid.velocity.x, playerRigid.velocity.z)).magnitude;
}
private float GetModifiedSmoothTime(float smoothTime) // Limit the control while in air
{
if (isGrounded)
return smoothTime;
if (airControlPercentage == 0)
return float.MaxValue;
return smoothTime / airControlPercentage;
}
private bool GroundCheck() // Player is grounded?
{
if (true)
return true;
return false;
}
Does someone knows what to do here?
It probably has something to do with your current gravity. Check in edit -> project settings -> physics the value of your gravity. In my case is -9,81. Change it to a higher value and see what happens.
I finally got it. How to fix it:
In this line of code
playerRigid.velocity = transform.forward * currentMovementSpeed + Vector3.up * playerRigid.velocity.y * Time.deltaTime;
Take out
* Time.deltaTime
Now the player is falling correctly.
Actually , transform.forward effect the y component of the body thus effects the gravity acting on the body.
Use
rb.velocity = new Vector3(horizontal , -1 , vertical) * speed ; .
It will work, or simply use AddForce to drive the player.
when you want to use gravity calculations, changing the rigidbody in your code can do this.
//rb.velocity = moveInput * moveSpeed;
for example will screw with your movement, even when a button isn't being pressed.
using something like:
if(Input.GetButtonDown("Jump") && Mathf.Abs(rb.velocity.y) < 0.001f)
{
rb.AddForce(new Vector2(0, jumpForce), ForceMode2D.Impulse);
}
will simply add forces on top of the calculations, instead of changing them prior to
In my case, the slow descending of my game character was solved by eliminating unnecessary calls to the physics system in the FixedUpdate() function. For example, when a joystick's X-axis and/or Y-axis are in the zero position.
I call addForce, velocity, rb transforms, etc. only if the absolute joystick value (- and +) exceeds a minimum value, in my case 0.04. Without these tests, these physics calls are done every time FixedUpdate() is called. This seems to overload the physics system, because at the same time, physics is also processing gravity etc.
Note that merely setting the joystick's dead zones in the Unity Input System doesn't solve this problem.
void FixedUpdate()
{
if (Mathf.Abs(stick.x) > 0.04) // prevent unnecessary physics call.
{
rb.transform.eulerAngles = rb.transform.eulerAngles - new Vector3(0, stick.x * Time.deltaTime * RotationSpeed * -1, 0);
}
if (Mathf.Abs(stick.y) > 0.04) // prevent unnecessary physics call.
{
rb.velocity = transform.forward * stick.y * Speed * Time.deltaTime;
}
}
I have a little problem with my player control script (C#) in the unity enigne. I worked out the following script with the basic movement of the player. The problem is that the player can enter the jump statement (the debug log printed it out)
Debug Log
but it will not work. The character is still on the ground.
The jump function will be enabled when the player is on the ground (grounded) and did not a double jump.
So my question is are there any "code mistakes" or maybe some configuration problems which I do not see?
Thank you for your help in advance!
using UnityEngine;
using System.Collections;
public class PlayerControl : MonoBehaviour
{
// public variables
public float speed = 3f;
public float jumpHeight = 5f;
// private variables
Vector3 movement;
Animator anim;
Rigidbody2D playerRigidbody;
// variables for the ground check
public Transform groundCheck;
public float groundCheckRadius;
public LayerMask whatIsGround;
private bool grounded;
private bool doubleJump;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
// Proves if the player is on the ground and activate the double jump function
if (grounded)
{
doubleJump = false;
}
// First line of proving the jump
if (Input.GetMouseButtonDown(0) && grounded)
{
Debug.Log("Jump if entered");
Jump();
}
if (Input.GetMouseButtonDown(0) && !doubleJump && !grounded)
{
Debug.Log("double Jump");
Jump();
doubleJump = true;
}
// Flipping the Player when he runs back
if (Input.GetAxis("Horizontal") < 0)
{
playerRigidbody.transform.localScale = new Vector2(-1.7f, 1.7f);
}
else
{
playerRigidbody.transform.localScale = new Vector2(1.7f, 1.7f);
}
}
void Awake()
{
// References setting up
playerRigidbody = this.GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
}
void FixedUpdate()
{
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
// simple Movement without a speed control
Move(horizontal, vertical);
Animating(horizontal, vertical);
// Section for ground detection
grounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround);
// Set the parameter for the jump animation false or true
anim.SetBool("Grounded", grounded);
}
void Move(float horizontal, float vertical)
{
movement.Set(horizontal, 0f, vertical);
movement = movement.normalized * speed * Time.deltaTime;
playerRigidbody.MovePosition(transform.position + movement);
}
void Jump()
{
playerRigidbody.AddForce(Vector3.up * jumpHeight);
// playerRigidbody.AddForce(new Vector2(0f, jumpHeight), ForceMode2D.Impulse);
Debug.Log("Jump function");
}
void Animating(float h, float v)
{
bool walking = h != 0f || v != 0f;
anim.SetBool("IsWalking", walking);
}
}
Just guessing here, but maybe Vector3.up does not work for 2D physics? I'm not really into 2D, but you could try
playerRigidbody.AddForce(transform.up * jumpHeight);
instead.
Also, have you tried different values for jumpHeight? 5 might be way to small depending on the mass you set for your rigidbody.
And make sure you haven't restricted any axes in the inspector.
// Note: If you want the object to move in a reliable predictable way but still allow physics interactions, use MovePosition (set the object to kinematic if you want it to be unaffected by physics but still be able to affect other things, and uncheck kinematic if you want both objects to be able to be acted on by physics.
If you want to move your object but let physics handle the finer details, add a force.
playerRigidbody.rigidbody2D.AddForce(Vector3.up * 10 * Time.deltaTime);
use Vector.up, Vector.down, vector.right, Vectore.left along with time.deltaTime to have smooth movement along the frame.