Unity2D Jump doesn't work for unknown reasons - c#

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))

Related

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),

Collision update is one physics update late, and it caused object to cancel its velocity

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.

Unity - how do I get my jump animation cycle to work?

I am new to unity and C# so would appreciate any help.
I have made my sprite jump which works fine, however, the only animation which will play is the landing animation. The takeoff animation won't play and the sprite stays in an idle position whilst jumping until the velocity goes below 0 then the landing animation plays.
What am I doing wrong? I am hoping to achieve a takeoff animation playing when the player jumps up and then move straight into a landing animation when it falls.
Here is my code:
using UnityEngine;
public class Player : MonoBehaviour
{
private Rigidbody2D myRigidbody;
private Animator myAnimator;
[SerializeField]
private float movementSpeed;
private bool facingRight;
private bool attack;
private bool slide;
[SerializeField]
private Transform[] groundPoints;
[SerializeField]
private float groundRadius;
[SerializeField]
private LayerMask whatIsGround;
private bool isGrounded;
private bool jump;
private bool airControl;
[SerializeField]
private float jumpForce;
// Use this for initialization
void Start()
{
facingRight = true;
myRigidbody = GetComponent<Rigidbody2D>();
myAnimator = GetComponent<Animator>();
}
void Update()
{
HandleInput();
}
// Update is called once per frame
void FixedUpdate()
{
float horizontal = Input.GetAxis("Horizontal");
HandleMovement(horizontal);
isGrounded = IsGrounded();
Flip(horizontal);
HandleAttacks();
HandleLayers();
ResetValues();
}
private void HandleMovement(float horizontal)
{
if (myRigidbody.velocity.y < 0)
{
myAnimator.SetBool("land", true);
}
if (!myAnimator.GetBool("slide") && !this.myAnimator.GetCurrentAnimatorStateInfo(0).IsTag("Attack")&&(isGrounded || airControl))
{
myRigidbody.velocity = new Vector2(horizontal * movementSpeed, myRigidbody.velocity.y);
}
if (isGrounded && jump)
{
isGrounded = false;
myRigidbody.AddForce(new Vector2(0, jumpForce));
myAnimator.SetTrigger("jump");
}
if (slide && !this.myAnimator.GetCurrentAnimatorStateInfo(0).IsName("Slide"))
{
myAnimator.SetBool("slide", true);
}
else if (!this.myAnimator.GetCurrentAnimatorStateInfo(0).IsName("Slide"))
{
myAnimator.SetBool("slide", false);
}
myAnimator.SetFloat("speed", Mathf.Abs(horizontal));
}
private void HandleAttacks()
{
if (attack && !this.myAnimator.GetCurrentAnimatorStateInfo(0).IsTag("Attack"))
{
myAnimator.SetTrigger("attack");
myRigidbody.velocity = Vector2.zero;
}
}
private void HandleInput()
{
if(Input.GetKeyDown(KeyCode.Space))
{
jump = true;
}
if (Input.GetKeyDown(KeyCode.LeftShift))
{
attack = true;
}
if (Input.GetKeyDown(KeyCode.LeftControl))
{
slide = true;
}
}
private void Flip(float horizontal)
{
if (horizontal > 0 && !facingRight || horizontal < 0 && facingRight)
{
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
private void ResetValues()
{
attack = false;
slide = false;
jump = false;
}
private bool IsGrounded()
{
if (myRigidbody.velocity.y <= 0)
{
foreach (Transform point in groundPoints)
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(point.position, groundRadius, whatIsGround);
for (int i = 0; i < colliders.Length; i++)
{
if (colliders[i].gameObject != gameObject)
{
myAnimator.ResetTrigger("jump");
myAnimator.SetBool("land", false);
return true;
}
}
}
}
return false;
}
private void HandleLayers()
{
if (!isGrounded)
{
myAnimator.SetLayerWeight(1, 1);
}
else
{
myAnimator.SetLayerWeight(1, 0);
}
}
}
I think the way you have your animations set up is making this more challenging than necessary. Let's change some things that will hopefully make animating your character a little easier.
First, it is my opinion that using an animation trigger is unreliable when it comes to scripting jumping animations. A better approach is to create a float in your animator, which I have called velocityY, that represents the player's Rigidbody2D.velocity.y. I've also created a new bool called isGrounded, as I think this is clearer and more applicable to many "jump" scenarios.
Once these variables have been created you can link your three animations - idle, jump and land - in the following way:
Set the default animation to "idle".
Make a transition from "idle" to "jump" in which the conditions are:
velocityY > 0
isGrounded = false
Make a transition from "jump" to "land" with the conditions:
velocityY < 0
isGrounded = false
Make a transition from "land" to "idle" when isGrounded = true.
Finally, to animate your character when it falls (without jumping first), you can optionally make a transition from "idle" to "land" where:
velocityY < 0
isGrounded = false
Now to the code. Here's a working example that I tested in a project to achieve your desired results. Note that I did not include everything in your script, just the parts that let the character move and animate its jump correctly. Try using this script and playing around with the movement values, as well as the gravity multiplier on your player's Rigidbody2D component; the default values and a gravity multiplier of 3.5 felt fun to me!
using UnityEngine;
public class Player : MonoBehaviour
{
//Components on Player GameObject
private Rigidbody2D myRigidbody;
private Animator myAnimator;
//Movement variables
[SerializeField]
private float movementSpeed = 9; //Set default values so you don't always
[SerializeField] //have to remember to set them in the inspector
private float jumpForce = 15;
//Ground checking
[SerializeField]
private Transform groundPoint;
[SerializeField]
private float groundRadius = 0.1f;
[SerializeField]
private LayerMask whatIsGround;
private float velocityX;
private bool isGrounded;
private bool facingRight;
// Use this for initialization
private void Start()
{
facingRight = true;
myRigidbody = GetComponent<Rigidbody2D>();
myAnimator = GetComponent<Animator>();
}
private void Update()
{
Flip();
HandleInput();
HandleAnimations();
}
private void FixedUpdate()
{
HandleMovement(); //It's generally considered good practice to
//call physics-related methods in FixedUpdate
}
private void HandleAnimations()
{
if (!isGrounded)
{
myAnimator.SetBool("isGrounded", false);
//Set the animator velocity equal to 1 * the vertical direction in which the player is moving
myAnimator.SetFloat("velocityY", 1 * Mathf.Sign(myRigidbody.velocity.y));
}
if (isGrounded)
{
myAnimator.SetBool("isGrounded", true);
myAnimator.SetFloat("velocityY", 0);
}
}
private void HandleMovement()
{
isGrounded = Physics2D.OverlapCircle(groundPoint.position, groundRadius, whatIsGround);
velocityX = Input.GetAxis("Horizontal");
myRigidbody.velocity = new Vector2(velocityX * movementSpeed , myRigidbody.velocity.y);
}
private void HandleInput()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Jump();
}
}
private void Jump()
{
if (isGrounded)
{ //ForceMode2D.Impulse is useful if Jump() is called using GetKeyDown
myRigidbody.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
}
else
{
return;
}
}
private void Flip()
{
if (velocityX > 0 && !facingRight || velocityX < 0 && facingRight)
{
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
}
I also took some time to reorganize your code. You don't necessarily need to concern yourself with too much organization right now, but I thought it might interest you since you're still learning.
As you can see, each method in the script handles a concrete task. For example, there's a method solely for handling animation, and another that lets the player jump. It's a good idea to set up your code this way so that if you have to change one aspect later, such as player movement, then all of the related code is in the same place. I think this is especially true for creating methods that deal with player "actions" like jumping or attacking; if you have enough of them you could even create an entire Actions class.
One last thing to mention is this line of code:
isGrounded = Physics2D.OverlapCircle(groundPoint.position, groundRadius, whatIsGround);
I found that this was an easier way to determine when the player is grounded. I achieved this by adding a child GameObject to the player, adding a colorful icon for ease of placement (you can do this by clicking the colorful box near the name of a GameObject), and placing it in between the player's feet.

Character won't jump in Unity2D but entered the jump statement

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.

Unity Click on 1 object to trigger another object

Please keep in mind that I'm new to Unity. I have 2 script that I want to "combline" but when I try then it don't Work.
I have a Script (Name : RobotController). This script controls the movement of the player. Up/Jump, Down, Left and Right. (This Works with Keyboard keys only atm)
This script Works just fine but now I want to add the feature of touch keys for phone. With this I mean that if a person click on the "up-Arrow" the player shall jump.
The Up-Arrow is an object.
This is were I get my problem. I have created the Up-Arrow with a collider and a script.
Up-Arrow script:
public class NewJumpScript : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnMouseOver()
{
if ((Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began) || (Input.GetMouseButtonDown(0)))
{
Debug.Log("test");
}
}
}
Here is the RobotController script´, with ground check and so on.
public class RobotController : MonoBehaviour {
//This will be our maximum speed as we will always be multiplying by 1
public float maxSpeed = 2f;
public GameObject player;
public GameObject sprite;
//a boolean value to represent whether we are facing left or not
bool facingLeft = true;
//a value to represent our Animator
Animator anim;
//to check ground and to have a jumpforce we can change in the editor
bool grounded = true;
public Transform groundCheck;
public float groundRadius = 1f;
public LayerMask whatIsGround;
public float jumpForce = 300f;
private bool isOnGround = false;
void OnCollisionEnter2D(Collision2D collision) {
isOnGround = true;
}
void OnCollisionExit2D(Collision2D collision) {
anim.SetBool ("Ground", grounded);
anim.SetFloat ("vSpeed", rigidbody2D.velocity.y);
isOnGround = false;
}
// Use this for initialization
void Start () {
player = GameObject.Find("player");
//set anim to our animator
anim = GetComponent <Animator>();
}
void FixedUpdate () {
//set our vSpeed
//set our grounded bool
grounded = Physics2D.OverlapCircle (groundCheck.position, groundRadius, whatIsGround);
//set ground in our Animator to match grounded
anim.SetBool ("Ground", grounded);
float move = Input.GetAxis ("Horizontal");//Gives us of one if we are moving via the arrow keys
//move our Players rigidbody
rigidbody2D.velocity = new Vector3 (move * maxSpeed, rigidbody2D.velocity.y);
//set our speed
anim.SetFloat ("Speed",Mathf.Abs (move));
//if we are moving left but not facing left flip, and vice versa
if (move > 0 && !facingLeft) {
Flip ();
} else if (move < 0 && facingLeft) {
Flip ();
}
}
void Update(){
if ((isOnGround == true && Input.GetKeyDown (KeyCode.UpArrow)) || (isOnGround == true && Input.GetKeyDown (KeyCode.Space))) {
anim.SetBool("Ground",false);
rigidbody2D.AddForce (new Vector2 (0, jumpForce));
}
if (isOnGround == true && Input.GetKeyDown (KeyCode.DownArrow))
{
gameObject.transform.localScale = new Vector3(transform.localScale.x, 0.2f, 0.2f);
}
if (isOnGround == true && Input.GetKeyUp (KeyCode.DownArrow))
{
gameObject.transform.localScale = new Vector3(transform.localScale.x, 0.3f, 0.3f);
}
}
//flip if needed
void Flip(){
facingLeft = !facingLeft;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
What needs to happen is that when The "Up-arrow" in the game is clicked then The person shall jump on the same tearms as in the RobotController script.
I hope you understand my question.
Thanks for your time and help.
I posted this same answer to both of the questions, because they are so similar. You can easily modify the code to your needs.
This is only one way to do it. There are probably many more, but this is the best I have encountered so far.
On the QUI button, script like this is needed:
private Mover playerMover;
void Start()
{
playerMover = GameObject.Find("Character").GetComponent<Mover>();
}
void OnMouseOver()
{
if (Input.GetMouseButton(0))
{
Debug.Log("pressed");
playerMover.MoveButtonPressed();
}
}
Notice that find is only done ones in start function, because it is computationally heavy.
And on the Character gameobject, script component like this is needed:
using UnityEngine;
using System.Collections;
public class Mover : MonoBehaviour {
public void MoveButtonPressed()
{
lastPressedTime = Time.timeSinceLevelLoad;
}
public double moveTime = 0.1;
private double lastPressedTime = 0.0;
void Update()
{
if(lastPressedTime + moveTime > Time.timeSinceLevelLoad)
{
// Character is moving
rigidbody.velocity = new Vector3(1.0f, 0.0f, 0.0f);
}
else
{
rigidbody.velocity = new Vector3(0.0f, 0.0f, 0.0f);
}
}
}

Categories