Hold space bar and jump? - c#

So my problem here is that when the player holds the space button the addForce function is increased which I don't want.
So what I want is that if a player holds the space button they can keep jumping continuously if they're on the ground...
Here is my code:
private void Update()
{
GetComponent<Rigidbody2D>().velocity = new Vector2(1.0f * movementSpeed, GetComponent<Rigidbody2D>().velocity.y);
if (IsGrounded() && Input.GetKey("Jump"))
{
Debug.Log("IS JUMPING");
_rigidBody.AddForce(new Vector2(0, jumpForce), ForceMode2D.Impulse);
}
}
This is the IsGrounded Code:
private bool IsGrounded()
{
RaycastHit2D raycastHid2d = Physics2D.BoxCast(boxCollider2d.bounds.center, boxCollider2d.bounds.size, 0f, Vector2.down, .1f, layerMask);
//Debug.Log(raycastHid2d.collider);
return raycastHid2d.collider != null;
}

As said the issue is most probably that the rigibody doesn't move far enough away from the ground immediately so you might get multiple input frames before IsGrounded returns false.
In general for physics related things you should rather use FixedUdpate.
While Update is executed every frame, FixedUpdate uses a fixed time delta => There might be multiple Update calls before he physics are actually applied and your scene is updated accordingly!
While you will want to get one time event input (GetKeyDown) still in Update (otherwise you might miss it) I would move continuous user input into FixedUpdate
[Serializefield] Rigidbody2D rigidbody;
private void Awake()
{
if(!rigidbody) rigidbody = GetComponent<Rigigbody2D>();
}
private void FixedUpdate()
{
rigidbody.velocity = new Vector2(movementSpeed, rigidbody.velocity.y);
if (IsGrounded() && Input.GetKey("Jump"))
{
Debug.Log("IS JUMPING");
rigidbody.AddForce(Vector2.up * jumpForce), ForceMode2D.Impulse);
}
}
And as said just to be super sure you could still add some cooldown like e.g.
private float timer;
public float jumpCooldown = 0.1f;
private void FixedUpdate()
{
rigidbody.velocity = new Vector2(movementSpeed, rigidbody.velocity.y);
timer += Time.deltaTime;
if(timer < jumpCooldown) return;
if (IsGrounded() && Input.GetKey("Jump"))
{
Debug.Log("IS JUMPING");
rigidbody.AddForce(Vector2.up * jumpForce), ForceMode2D.Impulse);
timer = 0f;
}
}

Related

Can't Jump while moving left and right in 2D

A little bit of context, this is a 2D game I got it so I can move left right and jump, I can't jump while moving left and right and if I move while in midair then the player's decent dramatically slows down
Here's the code:
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
[SerializeField] private float horSpeed;
[SerializeField] private float vertSpeed;
private Rigidbody2D rb;
private bool isJumping;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
private void Update()
{
if (Input.GetKey(KeyCode.Space) && !isJumping)
rb.velocity = new Vector2(0, horSpeed);
isJumping = true;
if (Input.GetKey(KeyCode.A))
rb.velocity = new Vector2(-vertSpeed, 0);
if(Input.GetKey(KeyCode.D))
rb.velocity = new Vector2(vertSpeed, 0);
if (rb.velocity.y==0f)
{
isJumping = false;
}
}
}
I don't see what I've done wrong here, it might be that I'm registering the inputs on different lines of code but I'm not sure how to fix it if that is the problem
The code presented is dealing with the velocity of an object. As such, you want to assign the calculated velocity as one value once all factors have been taken into account. I’ve corrected a few points and come up with this:
private void Update()
{
// we store the initial velocity, which is a struct.
var v = rb.velocity;
if (v.y==0f)
isJumping = false;
if (Input.GetKey(KeyCode.Space) && !isJumping) {
v.y = vertSpeed;
isJumping = true;
}
if (Input.GetKey(KeyCode.A))
v.x = -horSpeed;
if(Input.GetKey(KeyCode.D))
v.x = horSpeed;
rb.velocity = v;
}
The reason the code stores the velocity first, is because any changes you make to the temporary velocity struct needs to be applied back as a single value assignment to the rigid body’s velocity field (this is due to the difference between value and reference type objects). Here’s the Microsoft discussion about the difference.
The reason that you can't jump while moving left or right is because you overwrite your "horizontal" speed when you move. Look at your code for moving left or right. Notice how you set your y velocity to 0 when a or d is pressed.
Try this:
private void Update() {
if (Input.GetKey(KeyCode.Space) && !isJumping) {
rb.velocity.y = horSpeed;
isJumping = true;
}
if (Input.GetKey(KeyCode.A))
rb.velocity.x = -vertSpeed;
if(Input.GetKey(KeyCode.D))
rb.velocity.x = vertSpeed;
if (rb.velocity.y==0f)
{
isJumping = false;
}
}
I think this should work but I don't have access to Unity right now so I'll have to wait til I get home to check it. Also, I didnt change it in this code but it seems like you have horSpeed and vertSpeed flipped. Up and down movement (a.k.a. jumping) should be vertSpeed.

jumping/falling animation script

I'm trying to learn unity 2D and now iI need to do animations. I did walking animation, falling animation, jumping animation and the idle animation. However, when I jump, the falling animation doesn't play as intended. The falling animation isn't working properly, so it looks like this:
https://www.awesomescreenshot.com/video/8054610?key=208b095723f0bd4d8dfb936c88485e76
So when I'm falling, it doesn't play the animation right.
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private Rigidbody2D rb;
private Animator anim;
private SpriteRenderer sprite;
private enum MovementState { idle, running, jumping, falling }
private float dirX = 0f;
[SerializeField] private float moveSpeed = 7f;
[SerializeField] private float jumpForce = 5f;
private void Start()
{
Debug.Log("program started...");
rb = GetComponent<Rigidbody2D>();
sprite = GetComponent<SpriteRenderer>();
anim = GetComponent<Animator>();
}
private void Update()
{
dirX = Input.GetAxisRaw("Horizontal");
rb.velocity = new Vector2(dirX * moveSpeed, rb.velocity.y);
if (Input.GetButtonDown("Jump"))
{
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
}
Animation();
}
private void Animation()
{
MovementState state;
if (dirX > 0f)
{
state = MovementState.running;
sprite.flipX = false;
}
else if (dirX < 0f)
{
state = MovementState.running;
sprite.flipX = true;
}
else
{
state = MovementState.idle;
}
if (rb.velocity.y > .1f)
{
state = MovementState.jumping;
}
else if (rb.velocity.y < -.1f)
{
state = MovementState.falling;
}
anim.SetInteger("state", (int)state);
}
}
i don't know how to fix it, i've searched for about a hour how to fix it.
animations setting (my settings)
the settings that i want
There's a couple of things you can try to do to narrow down the issue. See if commenting out this else statement has an effect on the issue you are experiencing between jump and fall.
else
{
state = MovementState.idle;
}
I think this else could possibly to interrupt your Y velocity animation transition when the object reaches the max height of the jump.
Try to comment out different part of your if else statements until you find the culprit.
Also try to get rid of the overlap on the transition between jump and fall. I think you want to instantly move from jump animation to fall animation.
I suggest you to use two different floats for your animations, one for Movement and one for Jumping.
Then something like following to handle them.
private void Animation() {
sprite.flipX = dirX > 0f;
//Do some sort of ground check
if (isGrounded) {
anim.SetFloat("Move", dirX);
}
else {
anim.SetFloat("Jump", rb.velocity.y);
}
}
And of course you need to change your condition that you have setup in your Animator as well from your Animator window to make it work.
As it has been suggested, I would add what is called a ground check to your player, which is exactly what it sounds like. An easy way to do this would be to Raycast downward from your player's position offset by the sprite's extents and only detect casts against a specific ground LayerMask.
Once you have a ground check done, you can set the state of your animation based on 4 criteria.
Is the player grounded?
What is your relative velocity? (Positive / Negative)
With your four states, the logic would look as follows
•Idle - Grounded and X Velocity equals 0 (Or default)
•Running - Grounded and X Velocity not equal to 0
•Jumping - Not Grounded and Y Velocity greater than or equal to 0
•Falling - Not Grounded and Y Velocity less than 0
With this in mind, here is how I would edit your existing code to work as intended
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private Rigidbody2D rb;
private Animator anim;
private SpriteRenderer sprite;
private enum MovementState { idle, running, jumping, falling }
private float dirX = 0f;
[SerializeField] private float moveSpeed = 7f;
[SerializeField] private float jumpForce = 5f;
[SerializeField] private LayerMask groundMask;
[SerializeField] private float groundLengthCheck = 0.03f;
private Vector3 spriteGroundOffset = Vector3.zero;
private bool isGrounded = false;
private void Start()
{
Debug.Log("program started...");
rb = GetComponent<Rigidbody2D>();
sprite = GetComponent<SpriteRenderer>();
anim = GetComponent<Animator>();
// offset the raycast check to be half our sprite bounds in the Y (the bottom of your sprite)
spriteGroundOffset = new Vector3(0f, sprite.bounds.extents.y, 0f);
}
private void Update()
{
dirX = Input.GetAxisRaw("Horizontal");
rb.velocity = new Vector2(dirX * moveSpeed, rb.velocity.y);
// determine if our player is grounded by casting down from their feet with our slight offset
isGrounded = Physics2D.Raycast(transform.position - spriteGroundOffset, Vector2.down, groundLengthCheck, groundMask);
if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
{
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
}
Animation();
}
private void Animation()
{
// default our state to idle - as if we are just standing
MovementState state = MovementState.idle;
// change
if (isGrounded)
{
if (dirX > 0f)
{
state = MovementState.running;
sprite.flipX = false;
}
else if (dirX < 0f)
{
state = MovementState.running;
sprite.flipX = true;
}
}
else
{
if (rb.velocity.y > 0)
{
state = MovementState.jumping;
}
else if (rb.velocity.y < 0f)
{
state = MovementState.falling;
}
}
anim.SetInteger("state", (int)state);
}
}
Keep in mind
Add a new layer, assign it to your ground objects, and set the serialized field groundMask to check for this new layer.
There are a few other issues that might come about with the current code. The current snippet I have provided only fixes the issue related to jumping/falling.
Here is a gif of the current code in action - I am using a public domain sprite as I do not currently have any art for a 2D player.

How can I make this unity movement script work?

How can I make this script work, or another alternative player movement script? This basic movement script in Unity doesn't do anything when i press WASD for some reason. I am a beginner at C# and unity and I kind of need an alternative player movement script that actually works.
void Update()
{
if (Input.GetKeyDown(KeyCode.W))
transform.Translate(Vector3.forward);
if (Input.GetKeyDown(KeyCode.S))
transform.Translate(Vector3.back);
if (Input.GetKeyDown(KeyCode.A))
transform.Translate(Vector3.left);
if (Input.GetKeyDown(KeyCode.D))
transform.Translate(Vector3.right);
I recommend using the GetAxis("Horizontal") and GetAxis("Vertical") methods which maps wasd and arrow keys by default to help slim down your big if tree.
Below is a small example from an old unversity project of mine.
Note: the "* speed * Time.deltaTime" as this is used to help translate as time/frames move on, speed is just a multiplier in this case.
public float speed = 10.0f;
private float translation;
private float straffe;
// Use this for initialization
void Start()
{
// turn off the cursor
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
// Input.GetAxis() is used to get the user's input
// You can further set it on Unity. (Edit, Project Settings, Input)
translation = Input.GetAxis("Vertical") * speed * Time.deltaTime;
straffe = Input.GetAxis("Horizontal") * speed * Time.deltaTime;
transform.Translate(straffe, 0, translation);
if (Input.GetKeyDown("escape"))
{
// turn on the cursor
Cursor.lockState = CursorLockMode.None;
}
}
Input.GetKeyDown checks if you pressed the w key on that frame. You need Input.GetKey. That checks if you are holding
You should use GetAxis("Horizontal") & GetAxis("Vertical");
Here is my basic code for my projects default movement:
//movement
Rigidbody rb;
float xInput;
float yInput;
public float speed;
public float defSpeed;
public float sprint;
public bool isGrounded = true;
public float jump;
// Start is called before the first frame update
private void Awake()
{
rb = GetComponent<Rigidbody>();
}
void Start()
{
}
// Update is called once per frame
void Update()
{
xInput = Input.GetAxis("Horizontal");
yInput = Input.GetAxis("Vertical");
//Things is still can't understand
Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
float cameraRot = Camera.main.transform.rotation.eulerAngles.y;
rb.position += Quaternion.Euler(0, cameraRot, 0) * input * speed * Time.deltaTime;
//sprint
if (Input.GetKeyDown(KeyCode.LeftShift))
{
speed = sprint;
}
else if (Input.GetKeyUp(KeyCode.LeftShift))
{
speed = defSpeed;
}
//jump
if (Input.GetKeyDown(KeyCode.Space) && isGrounded == true)
{
rb.AddForce(0, jump, 0);
//Debug.Log("Jump!");
}
Hope this helps:)

UNITY 2D: Player flying when space/mousebutton is holded

So basicy i need my character to go up when space or mousebutton are pressed. I added rigbody 2d and box colider 2d to my gameobject (player). The problem is when I hit space or mousebuttonit only jump not constantly moving up.
Here is my code:
using UnityEngine;
using System.Collections;
public class PixelMovement : MonoBehaviour {
Vector3 velocity = Vector3.zero;
public Vector3 PressVelocity;
public float maxSpeed = 5f;
public float fowardSpeed = 1f;
public float jumpForce;
bool didPress = false;
// Use this for initialization
void Start () {
}
//Do Graphic & Input updates
void Update()
{
if (Input.GetKey(KeyCode.Space) || Input.GetMouseButton(0))
{
didPress = true;
}
}
//Do physics engine updates here
void FixedUpdate()
{
velocity.x = fowardSpeed;
if (didPress == true)
{
didPress = false;
velocity += PressVelocity * Time.deltaTime *jumpForce;
}
velocity = Vector3.ClampMagnitude(velocity, maxSpeed);
transform.position += velocity * Time.deltaTime;
}
}
Ok this works for me. Thanks everyone for help :)
using UnityEngine;
using System.Collections;
public class PixelMovement : MonoBehaviour {
public float playerSpeed;
public Vector3 gravity;
public float maxSpeed = 5f;
Vector3 velocity = Vector3.zero;
public float fowardSpeed = 1f;
bool didPress = false;
void Update()
{
if (Input.GetKey(KeyCode.Space) || Input.GetMouseButton(0))
{
didPress = true;
}
else
{
didPress = false;
}
}
void FixedUpdate()
{
velocity.x = fowardSpeed;
transform.position += velocity * Time.deltaTime;
if (didPress == true)
{
float amntToMove1 = playerSpeed * Time.deltaTime;
transform.Translate(Vector3.up * amntToMove1);
}
velocity = Vector3.ClampMagnitude(velocity, maxSpeed);
transform.position += velocity * Time.deltaTime;
}
}
If you are using gravity and RigitBody2D's mass. I recomend you use the RigitBody2D.Addforce() method to jump your caracter, because if you just change the caracter position, the gravity will turn down him to the ground inmediately
This code creates the effect of a "rocketman" that takes off when the user keeps the spacebar pressed:
using UnityEngine;
using System.Collections;
public class jumpAntigravity : MonoBehaviour {
Vector2 upForce;
void Start () {
//Up force set to double of gravity
upForce = new Vector2(0, 9.8f*2);
}
void Update () {
if (Input.GetKey(KeyCode.Space))
{
print("Spacebar is down");
GetComponent<Rigidbody2D>().AddForce(upForce);
}
}
}
if (Input.GetKey(KeyCode.Space) || Input.GetMouseButton(0))
{
didPress = true;
}
else
{
didPress = false;
}
and remove didPress = false; from FixedUpdate() function
EDIT: Ok, wait, I just noticed you update transform.position in FixedUpdate() which is not really a good idea. When you do so you basically teleport your object from one position to another ignoring all kinds of physics (which probably is the reason you are using FixedUpdate()). With your script colliding with other objects will give you weird results. Find a tutorial on using RigidBodies to do proper physics-aware movement, or just move all your code to Update() because right now you might have some frames where your object doesn't move and other frames where it moves twice the distance. This will happen because FixedUpdate() may get executed any number of times (including 0) in a single frame, depending on a setup. FixedUpdate runs firmly 50 times per second by default, while Update runs roughly 60 times per second (on mobile 30) by default. And lastly, in FixedUpdate never use Time.deltaTime, use Time.fixedDeltaTime:
Time.deltaTime is equal to roughly 1 / 60th of a second (1 frame duration)
Time.fixedDeltaTime is roughly 1 / 50th of a second (1 physics update duration)
FixedUpdate can be called multiple times per frame in succession. This is based on the physics settings for your project. You can edit this to add more or less accuracy to your physics.
Update is called only 1 time a frame.
So you want to avoid doing logic in the FixedUpdate. If you want to move a rigid body use MovePosition.
From the Unity docs: If Rigidbody interpolation is enabled on the Rigidbody, calling Rigidbody.MovePosition results in a smooth transition between the two positions in any intermediate frames rendered. This should be used if you want to continuously move a rigidbody in each FixedUpdate.

Make ball Jumping

I am trying to make a script where i can move a ball, horizontal and vertical. I managed to get that working.
But now I want to make my ball "jump". I ended with script below, but now my ball just get launched like a rocket xD
Can anyone help me out
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour
{
public float speed;
public float jumpSpeed;
public GUIText countText;
public GUIText winText;
private int count;
void Start()
{
count = 0;
SetCountText();
winText.text = " ";
}
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0, moveVertical);
Vector3 jump = new Vector3 (0, jumpSpeed, 0);
GetComponent<Rigidbody>().AddForce (movement * speed * Time.deltaTime);
if (Input.GetButtonDown ("Jump"));
GetComponent<Rigidbody>().AddForce (jump * jumpSpeed * Time.deltaTime);
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "PickUp") {
other.gameObject.SetActive(false);
count = count +1;
SetCountText();
}
}
void SetCountText()
{
countText.text = "Count: " + count.ToString();
if (count >= 10)
{
winText.text = "YOU WIN!";
}
}
}
Jumping does not work with adding a continuous force on an object. You will have to apply a single impulse to the object once when the jump button is first pressed. This impulse will also not include a time factor, because it is applied only once. So you would get something like this:
bool jumping;
if (Input.GetButtonDown ("Jump") && !this.jumping);
{
GetComponent<Rigidbody>().AddForce (jumpForce * new Vector3(0,1,0));
this.jumping = true;
}
Also note that in your example you are multiplying the upward unit vector by the jumpspeed twice. Once in the jump vector initialization and then once in the AddForce method.
Of course, you will also have to make sure that gravity applies to pull the object back down (and if the object hits the ground, reset the jump bool.
In general, depending on what kind of game you are making, it is easier to just set the velocity of the object yourself and don't work with the Unity physics engine to do some simple moving around.
There is an error in your code in the function FixedUpdate:
if (Input.GetButtonDown ("Jump"));
in that way you are applying a force on your object at every frame because the semicolon is excluding the row below from the condition. By removing the semicolon you will have a correct if implementation in case of a jump, as long as on your RigidBody component UseGravity is enabled.
if (Input.GetButtonDown ("Jump"))
GetComponent<Rigidbody>().AddForce (jump * jumpSpeed * Time.deltaTime);
Hope it helps.
Thanks everyone, it was a great help. I now have a jumping character. One who can only jump when grounded.
public bool IsGrounded;
void OnCollisionStay (Collision collisionInfo)
{
IsGrounded = true;
}
void OnCollisionExit (Collision collisionInfo)
{
IsGrounded = false;
}
if (Input.GetButtonDown ("Jump") && IsGrounded)
{
GetComponent<Rigidbody>().velocity = new Vector3(0, 10, 0);
}

Categories

Resources