I'm trying to implement a variable jump height system in my game. I stop the jump early by multiplying the velocity by .5f whenever the player releases the jump button (space).
This sometimes works, however sometimes it launches me up randomly when I lightly press space and let go as quickly as I can. It even jumps higher than the maximum jump height I get when I hold space.
This has happened in a project of mine so I thought the project had something wrong with it, I ended up making a new empty project just to test this out. I have no idea whats wrong. I can also confirm it's not an issue with onGround because I tried multiple ground sensing methods, and I substituted Input.GetKeyDown(KeyCode.Space) with Input.GetKey(KeyCode.Space) and nothing changed.
Here's the code :
Rigidbody2D rb;
[SerializeField] float force;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
bool jump;
[SerializeField] bool onGround;
void Update()
{
if(Input.GetKeyDown(KeyCode.Space) && onGround)
{
jump = true;
}
}
private void FixedUpdate()
{
if(jump)
{
//onGround = false;
jump = false;
rb.AddForce(Vector2.up * force, ForceMode2D.Impulse);
}
if(Input.GetKeyUp(KeyCode.Space) && rb.velocity.y > 0)
{
rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * .5f);
}
}
private void OnCollisionEnter2D(Collision2D other)
{
if(other.gameObject.CompareTag("Ground"))
onGround = true;
}
private void OnCollisionExit2D(Collision2D other)
{
if(other.gameObject.CompareTag("Ground"))
onGround = false;
}
I have no other scripts attached. Thanks
Related
I have a character, he can move and jump. I need to check if it is grounded, so I made a trigger box collider as a characters component, and I use OnTriggerEnter and OnTriggerExit to check if it is grounded, but the exit of collision with object that the character is standing on is detected one physics update late, and when it is detected, the upward velocity appears to become 0, and the character starts falling. Here is my code:
using System.Collections;
using UnityEngine;
public class Player : MonoBehaviour
{
public float speed = 4.0f;
public float jumpSpeed = 8.0f;
private bool doJump = false;
private Rigidbody rb;
bool isGrounded = false;
private float x, z;
private void Awake()
{
rb = GetComponent<Rigidbody>();
}
private void Update()
{
x = Input.GetAxis("Horizontal");
z = Input.GetAxis("Vertical");
if (Input.GetKeyDown(KeyCode.Space))
{
StartCoroutine(Jump());
}
}
void FixedUpdate()
{
if (isGrounded)
{
//this is movement
rb.velocity = (transform.right * x) * speed * Time.fixedDeltaTime + (transform.forward * z) * speed * Time.fixedDeltaTime;
}
if (isGrounded && doJump)
{
doJump = false;
rb.AddForce(0, jumpSpeed, 0, ForceMode.VelocityChange);
}
}
IEnumerator Jump()
{
//need the coroutine to make the player jump even if space pressed a bit earlier than
//the character landed
doJump = true;
yield return new WaitForSeconds(0.15f);
doJump = false;
}
private void OnTriggerStay(Collider other)
{
if (other != this.gameObject)
{
isGrounded = true;
}
}
private void OnTriggerExit(Collider other)
{
if (other != this.gameObject)
{
isGrounded = false;
}
}
}
I tried to not use coroutine for jumping but it doesn't help. What helps is deleting the movement line.
I think you are trying to implement "Pre_Update" function, I have found this solution maybe you can use it:
https://answers.unity.com/questions/614343/how-to-implement-preupdate-function.html
I am not sure but I think if you initialize your physics component in the Start function instead of the Awake function then it might work.
So I just started working with unity and wanted that my player can only jump when he's touching the ground. I gave a "Ground" tag to my ground and checked, If the player is touching the gameObject with the "Ground" tag, so the grounded bool would be set to true. Somehow my collision doesnt work.
public class PlayerMovement : MonoBehaviour
{
[SerializeField] float speed = 10;
private Rigidbody2D body;
private Animator animate;
private bool grounded;
private void Awake()
{
body = GetComponent<Rigidbody2D>();
animate = GetComponent<Animator>();
}
private void Update()
{
float horizontalInput = Input.GetAxis("Horizontal");
body.velocity = new Vector2(horizontalInput * speed, body.velocity.y);
if (horizontalInput > 0.01f)
transform.localScale = new Vector3(7, 7, 7);
else if (horizontalInput < -0.01f)
transform.localScale = new Vector3(-7, 7, 7);
if (Input.GetKeyDown(KeyCode.Space) && grounded == true)
Jump();
animate.SetBool("Run", horizontalInput != 0);
animate.SetBool("grounded", grounded);
}
private void Jump()
{
body.velocity = new Vector2(body.velocity.x, speed);
animate.SetTrigger("Jump");
grounded = false;
}
private void OncollisionEnter2D(Collision2D collision)
{
Debug.Log("Collision detected");
if (collision.gameObject.tag == "Ground")
grounded = true;
Debug.Log("ground is being touched");
}
}
I thought it would be a good idea to let certain steps of this process output a log message, but my log stayed empty after testing.
OnCollisionEnter2D would be the right spelling of what you intented to write. So, change OncollisionEnter2D to OnCollisionEnter2D, because capitalization matters.
As we're already here and it won't harm, I'd also suggest you to use CompareTag instead of tag == string as it performs slightly better due to less memory allocation (as you can read here: https://learn.unity.com/tutorial/fixing-performance-problems#5c7f8528edbc2a002053b595), so it's a good habit to get used to CompareTag:
if(collision.gameObject.CompareTag("MyTag"))
To finish up this answer, I'd like to point out that you might want to consider fixing your auto-completion suggestions (in Visual Studio and Visual Studio Code: IntelliSense) in case it doesn't work. With the help of this tool, you'll never misspell something like this again, because the correct name will be suggested as soon as you start writing.
I have Googled Everything but cannot get the right results. I want the GameObject to only jump once in the air, come back to the ground and then the player can jump. My current results are that the GameObject flies in the air if you press the spacebar. I wanna limit the GameObject to jump only once, come back and then jump if the player desires to. I have Shown some code down`
public class SphereController : MonoBehaviour
{
private bool IsOnGround = true;
Rigidbody rb;
public float BallSpeed = 10f;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
float Hmove = Input.GetAxis("Horizontal");
float Vmove = Input.GetAxis("Vertical");
Vector3 MoveBall = new Vector3(Hmove, 0f, Vmove);
rb.AddForce(MoveBall * BallSpeed);
if ((Input.GetKey(KeyCode.Space)) && IsOnGround == true)
{
rb.AddForce(0, 20, 0);
}
}
private void OnCollisionStay()
{
IsOnGround = true;
}
Change the IsOnGround to false.
if ((Input.GetKey(KeyCode.Space)) && IsOnGround)
{
rb.AddForce(0, 20, 0);
IsOnGround = false
}
You have the OnCollision method that changes it back to true so this should work fairly well.
So, the way I do it is the following.
STEPS:
1- Tag the floor object as whatever you like. I always tag it as ground. You tag objects in the Inspector window, at the top left. I says Untagged by default
2- This is the Code I write:
bool isGrounded;
void OnCollisionEnter(Collision other)
{
if(other.gameObject.tag == "ground")
{
isGrounded = true; // if its colliding with "ground", isGrounded is true
}
else
{
isGrounded = false;
}
if(Input.GetKeyDown(KeyCode.space) && isGrounded) // change space to whatever key to jump
{
Jump(); // your jump code goes here EG. Rigidbody.AddForce(0, 15, 0);
}
}
I hope this is helpful.
When the runner is touching the ground the bool value does not stay true all the period he is on the ground
I made two boxcolliders2D for the runner : One to collide with the ground and the other set as a trigger to check if he is grounded
Here the runner is colliding with the ground but the bool value isn't set as true
I did the same thing for the ground sprite
But when the speed is equals to 0 it works fine ...and of course it's usless then
Oh and another thing , wile the ground prefab keeps generating the runner getenter code here stucked at some point....and when he does it's marked that he is grounded .. any idea how to fix the stucking lag? P.S: I tried to change to boxcollider2D size of the ground but it didn't work :(((
Here is the part of code related to ground check(it's supposed to play a nice footstep soundeffect too)
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.tag == "Ground")
{
isGrounded = true;
footSteps.Play();
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.tag == "Ground")
{
isGrounded = false;
footSteps.Stop();
}
}
Maybe if i just show you the whole code you will be able to help me better(I hope my code isn't so messy)
public float speed;
public float jumpForce = 10f;
public float speedMultiplier;
public float speedIncreasedMilestone;
private float speedMilestoneCount;
private Rigidbody2D rb;
private Collider2D myCollider;
public Animator anim;
public AudioSource footSteps;
public bool isGrounded = false;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
if(transform.position.x < speedMilestoneCount)
{
speedMilestoneCount += speedIncreasedMilestone;
speedIncreasedMilestone = speedIncreasedMilestone * speedMultiplier;
speed = speed * speedMultiplier;
}
if(isGrounded == true)
{
rb.velocity = new Vector2(-speed * Time.deltaTime, rb.velocity.y);
anim.SetBool("Condition",true);
}
if(Input.GetKeyDown(KeyCode.Space) && isGrounded == true)
{
anim.SetBool("Condition", false);
rb.velocity = new Vector2(rb.velocity.x,jumpForce);
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.tag == "Ground")
{
isGrounded = true;
footSteps.Play();
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.tag == "Ground")
{
isGrounded = false;
footSteps.Stop();
}
}
}
Whenever you encounter this problem (i.e. an action takes more time than desired), there are two strategies you can choose:
Check if you can perform the action less frequently
Check if you can perform the action more quickly
In this case, it seems like you only need to know if the player is grounded when the player tries to perform a jump. So that's when you'd want to perform a check.
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.