Player won't jump in unity2d - unity3d

here's my jump code it updates in void Update
void Jump()
{
if(isgrounded == true)
{
amountofjumps = jumps;
}
if(Input.GetKeyDown(KeyCode.UpArrow) && amountofjumps > 0)
{
rb2d.velocity = Vector2.up * jump * Time.deltaTime;
amountofjumps--;
}
else if(Input.GetKeyDown(KeyCode.UpArrow) && amountofjumps == 0 && isgrounded == true)
{
rb2d.velocity = Vector2.up * jump * Time.deltaTime;
}
}
here are the variables I use for my jump code
bool isgrounded;
public float groundcheckradius;
public LayerMask whatisground;
public float jump;
private int amountofjumps;
public int jumps;
here's how I detect the ground
void checkforground()
{
isgrounded = Physics2D.Raycast(transform.position,Vector2.down, groundcheckradius,whatisground);
}
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawLine(transform.position, transform.position + Vector3.down * groundcheckradius);
}
thanks in advance

Velocity is often used for moving object try rigidbody2d.AddForce() instead.
void Jump()
{
if (isgrounded == true)
{
amountofjumps = jumps;
}
if (Input.GetKeyDown(KeyCode.UpArrow) && amountofjumps > 0 && isgrounded == true)
{
rb2d.AddForce(transform.up * jump, ForceMode2D.Impulse);
amountofjumps--;
}
}

First of all Time.deltaTime makes no sense when setting a velocity. A velocity already is frame-rate independent so when you multiply a velocity by Time.deltaTime (about 0.017 for 60 fps) it becomes extremely small/slow.
Secondly currently you overwrite the entire velocity so if your player is moving forward it will completely stop any movement on the X axis.
And finally when you are grounded you want always be able to jump ... not only if amountofjumps == 0 which will never be the case since right before you have set it to amountofjumps = jumps;! You don't want to check the amountofjumps at all when jumping from the ground!
You would probably rather use e.g.
// get the current velocoty of the rigidbody
var velocity = rb2d.velocity;
// Only overwrite the Y velocity with the jump
velocity.y = jump;
// re-assign the changed vector to the rgidbody
rb2d.velocity = velocity;
And then I would change the logic to something like e.g.
private void Jump()
{
if(isgrounded)
{
amountofjumps = jumps;
// when you are grounded you can always jump!
// Not only when the amountofjumps == 0
// actually when you are grounded the amountofjumps shouldn't matter at all
if(Input.GetKeyDown(KeyCode.UpArrow))
{
DoJump();
}
}
// As before while not grounded the amountofjumps is taken into account
else if(amountofjumps > 0)
{
if(Input.GetKeyDown(KeyCode.UpArrow))
{
DoJump();
}
}
}
private void DoJump()
{
// get the current velocoty of the rigidbody
var velocity = rb2d.velocity;
// Only overwrite the Y velocity with the jump
velocity.y = jump;
// re-assign the changed vector to the rgidbody
rb2d.velocity = velocity;
// Always reduce the amount of jumps also when jumping from the ground
amountofjumps--;
}

Related

Is there a way to have an object with rigidbody tilt but not rotate (cube)?

I am working on a project where a player can control a cube and move it around. I love having physics on the cube, but when manuevering, it is very difficult to time a jump when the cube is spinning all over the place. I would like the player to be able to move the cube along the ground, and the cube would gradually tilt towards the direction they are moving it, but not flip entirely. I don't know if it would even work conceptually, but if someone could help me figure out how to alter my code to keep it grounded but still tilt. Thank you.
{
public GameObject Camera;
Collider coll;
private bool isGrounded;
Rigidbody rb;
Vector3 velocity;
public float speed = 12f;
public float gravity = -9.8f;
public float jumpStrength = 1000f;
// Start is called before the first frame update
void Start()
{
Camera = GameObject.Find("Main Camera");
rb = GetComponent<Rigidbody>();
}
void OnCollisionEnter(UnityEngine.Collision collision)
{
if (collision.gameObject.tag == "Floor")
{
isGrounded = true;
Debug.Log("Is Grounded");
}
}
void OnCollisionExit(UnityEngine.Collision collision)
{
if (collision.gameObject.tag == "Floor")
{
isGrounded = false;
Debug.Log("Is Not Grounded");
}
}
// Update is called once per frame
void Update()
{
Camera.transform.position = new Vector3(transform.position.x, transform.position.y + 2.38f, transform.position.z - 3.45f);
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
float mH = Input.GetAxis("Horizontal");
float mV = Input.GetAxis("Vertical");
rb.velocity = new Vector3(mH * speed, rb.velocity.y, mV * speed);
if(isGrounded && Input.GetButtonDown("Jump"))
{
velocity.y = Mathf.Sqrt(3 * -2 * gravity);
}
velocity.y += gravity * Time.deltaTime;
if(Input.GetButtonDown("Jump") && isGrounded)
{
rb.AddForce(0f, jumpStrength, 0f);
Debug.Log("Jump");
}
}
}

(Big unity noob here) I can jump while in the air, and I can't jump while moving on the x-axis

Have tried a few things but they didn't seem to work, so I was hoping that you guys could help me.
I've trying to make this demo for a little time now, but I can't seem to get the jumping to work.
When I try to jump while running, I can't. But I can however jump forever when i get up in the air, which is something that I would like to remove from the game.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movement : MonoBehaviour
{
Rigidbody2D rb2d;
public float moveVelocity = 8f;
public float jumpVelocity = 15f;
public float fallMultiplier = 2.5f;
public float lowJumpMultiplier = 2f;
public const string RIGHT = "right";
public const string LEFT = "left";
public const string UP = "up";
string buttonPressed;
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
}
void Update()
{
if (rb2d.velocity.y < 0)
{
rb2d.velocity += Vector2.up * Physics2D.gravity.y * (fallMultiplier - 1) *
Time.deltaTime;
}
else if (rb2d.velocity.y > 0 && !Input.GetButton ("Jump"))
{
rb2d.velocity += Vector2.up * Physics2D.gravity.y * (lowJumpMultiplier - 1) *
Time.deltaTime;
}
if (Input.GetKey(KeyCode.RightArrow))
{
buttonPressed = RIGHT;
}
else if (Input.GetKey(KeyCode.LeftArrow))
{
buttonPressed = LEFT;
}
else if (Input.GetKey(KeyCode.UpArrow))
{
buttonPressed = UP;
}
else
{
buttonPressed = null;
}
}
private void FixedUpdate()
{
if (buttonPressed == RIGHT)
{
rb2d.velocity = new Vector2(moveVelocity, rb2d.velocity.y);
}
else if (buttonPressed == LEFT)
{
rb2d.velocity = new Vector2(-moveVelocity, rb2d.velocity.y);
}
else if (buttonPressed == UP)
{
rb2d.velocity = Vector2.up * jumpVelocity;
}
else
{
rb2d.velocity = new Vector2(0, rb2d.velocity.y);
}
}
}
I am not sure why you are trying to control the gravity of the player when gravity is already applied to any gameObject with the RigidBody or RigidBody2D component attached to it. It is good that you are reading input in the Update() function and applying the motion inside of the FixedUpdate(). Here is a slight tweak to your current code, let me know how this goes.
Rigidbody2D rb2d;
public float moveVelocity = 8f;
public float jumpVelocity = 15f;
private float horizontalInput = 0.0f;
// did the player just try to jump
private bool justJumped = false;
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
}
void Update()
{
// grab how the player is moving - this value is mapped to your arrow keys
// so horizontal is left / right arrow and Vertical is up/down arrow
// the value is between [-1, 1] respectively
horizontalInput = Input.GetAxis("Horizontal");
// player tried to jump, we are not currently jumping and the player is grounded
if(IsGrounded() && Input.GetKeyDown(KeyCode.UpArrow))
{
justJumped = true;
}
}
private void FixedUpdate()
{
// handle our jump
if(justJumped)
{
// we just applied a jump so do not apply it again
justJumped = false;
// you can either apply the jump by setting velocity, but I would recommend using AddForce instead
rb2d.AddForce(Vector2.up * jumpVelocity);
}
// we are moving in either the left or right direction
if(horizontalInput != 0)
{
// move in the horizontal axis, but keep our Y component of velocity the same in case we jumped
rb2d.velocity = new Vector2 (horizontalInput * moveVelocity, rigidBody.velocity.y);
}
else
{
// just in case we are not moving, assure this by setting the horizontal component of velocity to 0
rb2d.velocity = new Vector2 (0f, rigidBody.velocity.y);
}
}
// determines if this object is currently touching another object that is marked as ground
private bool IsGrounded() {
// our current position (the player)
Vector2 position = transform.position;
// the direction we are going to aim the raycast (down as that is where the ground is)
Vector2 direction = Vector2.down;
// the ground should be close, so check it very close to the player
float distance = 1.0f;
// check if we hit anything that is on the layer of just ground - ignore all other layers
// IMPORTANT:: Make sure to make a Layer and set all of your ground to this layer
RaycastHit2D hit = Physics2D.Raycast(position, direction, distance, LayerMask.GetMask("GroundLayer"));
// we hit a ground collider, so we are grounded
if (hit.collider != null) {
return true;
}
return false;
}
Let me know if this works for you. I changed a few things around such as using GetAxis() instead of using the arrow keys as in Unity, these are the same. I also changed your jump to use an AddForce2D instead of setting velocity. The one addition was I added a IsGrounded() which will detect if whatever object this script is on (I assume it is on your player object) is near or touching objects below them that are marked as GroundLayer. If you have questions comment below.

How to keep player momentum after jumping (2D)?

I'm creating a Mario clone and I need to keep the player's forward momentum into the jump and then onward into the landing. I can't figure out how to achieve this. Every time I land, the player has to build up momentum again. Any Idea how to fix this? I've tried several solutions to no avail. I'm thinking it has something to do with how I'm adding force and acceleration to the player when holding left or right. Not sure though any help would be much appreciated. thanks in advance.
Here's my code:
Animator animator;
Rigidbody2D rb;
bool isGrounded;
public float moveSpeed;
public Vector2 acceleration;
public float jumpHeight;
public float lowjumpMultiplier;
public Transform groundCheckM;
public Transform groundCheckL;
public Transform groundCheckR;
public float storedValue;
void Start()
{
animator = GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
transform.eulerAngles = new Vector3(0, 0, 0);
}
private void Update()
{
if
((Physics2D.Linecast(transform.position,groundCheckM.position, 1 << LayerMask.NameToLayer("Floor/Platforms"))) || //Check if grounded
(Physics2D.Linecast(transform.position, groundCheckL.position, 1 << LayerMask.NameToLayer("Floor/Platforms"))) ||
(Physics2D.Linecast(transform.position, groundCheckR.position, 1 << LayerMask.NameToLayer("Floor/Platforms"))))
{
isGrounded = true;
animator.SetBool("Jump", false);
}
else
{
isGrounded = false;
}
animator.SetFloat("Walk", rb.velocity.x); //Set animation float to x velocity
if (rb.velocity.x <= 0.03f && rb.velocity.x >= -0.03f && isGrounded) //Play "Idle" animation
{
animator.Play("Mario_Idle");
}
if (rb.velocity.x >=4 || rb.velocity.x <=-4)
{
animator.speed = Mathf.Abs(rb.velocity.x / 5.5f); //Increase speed of walking animation with player's walking speed
}
}
void FixedUpdate()
{
if (Input.GetKey("d") || Input.GetKey("right")) //Move player to the right
{
rb.AddForce(acceleration * rb.mass);
transform.rotation = Quaternion.Euler (0, 0, 0);
}
else if (Input.GetKey("a") || Input.GetKey("left")) //Move player to the left
{
rb.AddForce(-acceleration * rb.mass);
transform.rotation = Quaternion.Euler(0, 180, 0);
}
if (rb.velocity.x >= 10)
{
rb.velocity = new Vector2(10, rb.velocity.y); //Cap player speed at 10 when moving right
}
else if (rb.velocity.x <= -10)
{
rb.velocity = new Vector2(-10, rb.velocity.y); //Cap player speed at 10 when moving left
}
if (Input.GetKey("space") && isGrounded) //Player jump
{
rb.velocity += new Vector2(rb.velocity.x, jumpHeight);
animator.SetBool("Jump", true);
}
}
}
I feel dumb but the answer was in the physics material. Once I lowered the friction, it allowed momentum from the jump to carry into the player's run speed. I guess it's a good reminder to tinker directly inside Unity and its built in physics system.
If you want to keep your momentum when jumping, you could store it in a variable that will increase until it reaches the max, or you let go of the key.
float acceleration;
float accelFactor = 0.6f;
float deAccelFactor = 1f;
bool jumping; //you should set it to true when jumping and false, when not.
Rigidbody2D rb;
void Start(){
rb = GetComponent<Rigidbody2D>();
}
void Update(){
if (Input.GetKeyDown(KeyCode.D))
{
Accelerate();
rb.AddForce(acceleration * rb.Mass);
}
else if (jumping)
{
rb.AddForce(acceleration * rb.Mass);
}
else
{
DeAccel();
}
}
void Accelerate(){
acceleration += accelFactor * Time.deltaTime;
acceleration = Mathf.Clamp(acceleration, 0, maxAccel);
}
void DeAccel(){
acceleration -= deAccelFactor * Time.deltaTime;
acceleration = Mathf.Clamp(acceleration, 0, maxAccel);
}
This is what I would recommend using, that is, if I understand what you mean.

Unity jump only once per trigger

I need help with my code where I can only jump once but then it's locked for me I think I'm onto something.
Here is my code:
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Vector3 v = transform.position;
v.x += speed * Input.GetAxis("Horizontal") * Time.deltaTime;
v.z += speed * Input.GetAxis("Vertical") * Time.deltaTime;
transform.position = v;
if (Input.GetKeyDown(KeyCode.Space) && isGrounded==true)
{
GetComponent<Rigidbody2D>().velocity = Vector2.up * jumpVelocity;
isGrounded = false;
}
void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag == ("Ground") && isGrounded == false)
{
isGrounded = true;
}
}
}
}
You nested the OnCollisionEnter method inside the Update.
This way it is a local function and not found by the Unity Physics / Message System -> it will never be called.
Another issue in your code: Whenever there is a Rigibody/Rigibody2D involved you do not want to set or access stuff via the Transform component. This will break the physics and collision detection!
And finally note that Physics and Physics2D are two completely separate engines! If you want to be moving and detect collisions in 3D space then you have to use a Rigidbody, not a Rigibody2D!
It should rather be
[Header("References")]
[SerializeField] private Rigidbody _rigidbody;
[Header("Debugging")]
[SerializeField] private bool isGrounded;
private void Awake()
{
if(!_rigidbody) _rigidbody = GetComponent<Rigidbody>();
}
// Update is called once per frame
private void Update()
{
var x = Input.GetAxis("Horizontal");
var y = Input.GetAxis("Vertical");
// Clamp the vector so it has a maximum magnitude of 1
// this prevents that diagonal movement is overall faster
var moveInput = Vector2.ClampMagnitude(new Vector2(x,y), 1) * speed;
// instead of using the Transform simply change the rigidbody velocity accordingly
var velocity = _rigidbody.velocity;
velocity.x = moveInput.x;
velocity.z = moveInput.y;
_rigidbody.velocity = velocity;
// it is cheaper to first check a simple bool flag
// if this already fails we can skip the more expensive "GetKeyDown"
if (isGrounded && Input.GetKeyDown(KeyCode.Space))
{
_rigidbody.velocity = Vector2.up * jumpVelocity;
isGrounded = false;
}
}
// This method should be on class level and not nested under Update
private void OnCollisionEnter(Collision col)
{
// if already "isGrounded" we can skip the more expensive "CompareTag"
if (!isGrounded && col.gameObject.CompareTag("Ground"))
{
isGrounded = true;
}
}

Unity stop diagonal movement using transform.position method

I'm having a ton of trouble trying to understand how to stop my Ball objects from moving diagonally when they are swiped left or right, essentially what happens is: I swipe a ball in a direction, and the ball falls from the top of the screen. When i swipe the Ball it moves left and right but it also falls slightly still because of the downwards movement - how do i change this ? My game is 2D
Here is all the code you should need
//Variables
public float ballSpeed = 10; //This will handle our Balls left and Right movement when swiped
public float fallSpeed = 2; //This will handle the speed at which our ball falls
[HideInInspector]
public bool hitWall = false; //Check if our ball has collided with a wall
public bool moveRight, moveLeft;
public RoundHandler roundHandler;
private void OnEnable()
{
//Get our Components
roundHandler = FindObjectOfType<RoundHandler>();
}
#region functions
void checkWhereToMove()
{
if (moveLeft == true)
{
transform.position -= transform.right * Time.deltaTime * ballSpeed;
}
if (moveRight == true)
{
transform.position += transform.right * Time.deltaTime * ballSpeed;
}
}
public void moveDown() {
//Set our Fall Speed modified by our Current rounds
fallSpeed = roundHandler.ballFallSpeed;
if (hitWall != true) {
//Check if we arnt moving left or Right so that we can move down
if (moveLeft == false || moveRight == false)
{
//Move our Ball down
transform.position -= transform.up * Time.deltaTime * fallSpeed;
//Get our movement input
checkWhereToMove();
}
}
}
#endregion
private void FixedUpdate()
{
moveDown();
}
Testing for movement requires checking to see if both directions are false.
checkWhereToMove() is in the wrong place.
After moving down, both directions need to be reset to false.
public void moveDown() {
//Set our Fall Speed modified by our Current rounds
fallSpeed = roundHandler.ballFallSpeed;
//Get our movement input
checkWhereToMove();
if (hitWall != true) {
//Check if we arnt moving left or Right so that we can move down
if (moveLeft == false && moveRight == false) {
//Move our Ball down
transform.position -= transform.up * Time.deltaTime * fallSpeed;
//Reset left and right movement
moveLeft = false;
moveRight = false;
}
}
}