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.
Related
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
I am going back into game devloppment after a few months and, while I was making a respawn trigger (that doesn't work), my jump stopped working for no reasons. I didn't modified the code (I think). I followed a tutorial for the code. Please not that I am using the unity new input system and that my game is a 2D GAME Also, there is no errors shown in the logs, the problem is that when I press my jump key, it does nothing. I tried putting Debug.Log("Should Jump"); in the jump code to see if the Rigidbody2D was the problem but it still didn't worked (nothing showed up in the logs). I also verified that my floor was in the Ground layer and it was. I don't see the problem.
My code is the following:
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerMovement : MonoBehaviour
{
[SerializeField] float speed;
[SerializeField] Transform groundCheck;
[SerializeField] LayerMask groundLayer;
bool facingRight = true;
PlayerInput playerInput;
bool isGrounded;
float groundTimer = 1f;
float airTimer;
void Start()
{
playerInput = GetComponent<PlayerInput>();
}
void Update()
{
Movement();
isGround();
}
void isGround()
{
if (Physics2D.OverlapCircle(groundCheck.position, 0.05f, groundLayer) && airTimer <- 0)
{
groundTimer = 0.15f;
isGrounded = true;
}
if (airTimer > 0)
{
airTimer -= Time.deltaTime;
}
else
{
if (groundTimer < 0)
isGrounded = false;
else
groundTimer -= Time.deltaTime;
}
}
void Movement()
{
transform.Translate(Mathf.Abs(playerInput.actions["Horizontal"].ReadValue<float>()) * speed * Time.deltaTime, 0, 0);
//if (playerInput.actions["Jump"].triggered)
if (playerInput.actions["Jump"].triggered && isGrounded && airTimer <- 0)
{
GetComponent<Rigidbody2D>().velocity = Vector2.zero;
GetComponent<Rigidbody2D>().AddForce(new Vector2(0, 10), ForceMode2D.Impulse);
Debug.Log("Should Jump");
isGrounded = false;
airTimer = 0.06f;
}
//Just flipping
}
//More flipping
}
Help...
(It's late for me so, if you ask a question, I will probably not anwser (22:52 EST 19 June 2022))
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 am trying to prevent the player to double jump, for that I am using Raycast to check if the player is in the layer Floor. My solution works sometimes, but sometimes it allows the player to double jump.
This is my code:
void Movement()
{
float movement = Input.GetAxis("Horizontal");
Vector3 playerVelocity = new Vector3(movement*speed, myRigidbody.velocity.y, speed);
myRigidbody.velocity = playerVelocity;
if (Input.GetKeyDown("space") && isGrounded)
{
Vector3 jumpVelocity = new Vector3(0f, jumpSpeed, 0f);
myRigidbody.velocity += jumpVelocity;
isGrounded = false;
Debug.Log("floor:"+isGrounded);
anim.SetInteger("AnimationPar", 3);
myAudioSource.Stop();
AudioSource.PlayClipAtPoint(jumpSound,transform.position, volumeSoundEffects);
}
else if (isGrounded && !myAudioSource.isPlaying && !levelFinished)
{
myAudioSource.Play();
}
if (!isGrounded)
{
IsGrounded();
}
}
void IsGrounded()
{
RaycastHit hit;
int mask = 1 << LayerMask.NameToLayer("Floor");
if (Physics.Raycast(transform.position, Vector3.down, out hit, 0.01f, mask))
{
//Debug.Log("Is touching floor");
isGrounded = true;
Debug.Log("floot:" + isGrounded);
anim.SetInteger("AnimationPar", 1);
if (!myAudioSource.isPlaying)
{
myAudioSource.Play();
}
}
}
The Movement method is called in Update. I think that maybe the IsGrounded method is called to fast and the player is still to close to the floor.
An easy way to prevent double jump is using a counter instead of raycast, it really makes everything easy. put a counter in this portion of the code:
if (Input.GetKeyDown("space") && isGrounded && counter <2)
{
Vector3 jumpVelocity = new Vector3(0f, jumpSpeed, 0f);
counter++;
Im unable to debug your code at this time, but another way you could do it is using OnCollisionEnter and OnCollisionExit
You can detect all things your players collides with, if one of them is the Floor then its likely hes grounded. But it would be possible to touch the floor on the side of the player while falling, to avoid this use the grounded method agian. You said it does work but sometimes fails. So try something like:
void OnCollisionEnter (Collision col)
{
if(col.gameobject.layer == LayerMask.NameToLayer("Floor") && IsGrounded())
{
isGrounded = true;
}
}
void OnCollisionExit (Collision col)
{
if(col.gameobject.layer == LayerMask.NameToLayer("Floor") && !IsGrounded())
{
isGrounded = false;
}
}
Thats untested code so im not 100% sure if it will work. The Exit may not work since IsGrounded may still be able to raycast to the ground. But if you handle your layers/collision in your levels right then you can remove the IsGrounded calls entirely.
This isnt the perfect solution by far but it might work.
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.