Infinite jump in unity 3D - c#

My character keeps floating up if space bar is held down until you let go, I tried all day on how to make the character to jump normal but I am just stuck. I'm using unity to create the game. The issue started when I changed onfloor=true, before when it was false the character could only jump once. Here is the code for the character in C#
Thank you
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
private Transform rotateBody;
private Vector3 Direction;
private const float gravity = 0.1f;
private const float jump_force = 0.09f;
public Transform groundCheckTransform;
private bool shiftKeyWasPressed;
private bool jumpKeyWasPressed;
private float horizontalInput;
private Rigidbody RigidbodyComponent;
public LayerMask playerMask;
private int superJumpsRemaing;
private bool on_floor = true;
// Start is called before the first frame update
void Start()
{
RigidbodyComponent = GetComponent<Rigidbody>();
shiftKeyWasPressed = false;
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.Space) & Direction.y > 0){
jumpKeyWasPressed = true;
}
horizontalInput = Input.GetAxis("Horizontal");
if(Input.GetKeyDown(KeyCode.LeftShift)){
shiftKeyWasPressed = true;
}
horizontalInput = Input.GetAxis("Horizontal");
}
void FixedUpdate(){
Direction.y -= gravity;
Direction.x = 0;
if (Input.GetKey(KeyCode.Space)){
if (Direction.y < 0 && on_floor){
Direction.y = 0;
}
if(on_floor){
Direction.y += jump_force*2;
on_floor = true;
}
}else{
jumpKeyWasPressed = false;
}
if (Input.GetKey(KeyCode.D)){
Direction.x += 2;
}
if (Input.GetKey(KeyCode.A)){
Direction.x -= 2;
}
if (Input.GetKey(KeyCode.LeftShift))
if(shiftKeyWasPressed==true)
Direction.x *= 6;
if(Physics.OverlapSphere(groundCheckTransform.position, 0.1f, playerMask).Length == 0){
return;
}
if (jumpKeyWasPressed)
{
float jumpPower = 7;
if (superJumpsRemaing > 0){
jumpPower *=2;
superJumpsRemaing--;
}
RigidbodyComponent.AddForce(Vector3.up*jumpPower, ForceMode.VelocityChange);
jumpKeyWasPressed = false;
}
RigidbodyComponent.velocity = Direction;
}
private void OnTriggerEnter(Collider other)
{
if ( other.gameObject.layer == 8){
jumpKeyWasPressed = true;
if(Direction.y > 8)
jumpKeyWasPressed = false;
}
if (other.gameObject.layer == 6){
Destroy(other.gameObject);
}
if (other.gameObject.layer == 7){
Destroy(other.gameObject);
superJumpsRemaing++;
}
}
}

Your on_floor variable never becomes false which results in constantly adding y value when ever space button is held down. You need to add the check for ground collision and set on_floor to false whenever player hits ground object. You can use raycast towards downward direction for this something like:
public dist = 10;
public RaycastHit hit;
public void CheckGroundBelow()
{
dist = 10; //Distance to calculate height from
dir = Vector3(0,-1,0); //Downward Direction
if(Physics.Raycast(transform.position,dir,hit,dist)){
on_floor = true;
}
else
{
on_floor = false;
}
}
Here it checks if something is below your player's transform . If there is something within 10 m then it means player is on ground otherwise it ignores input . You can call it just above your if condition here you check for on_floor.
More about Raycast here : https://docs.unity3d.com/ScriptReference/Physics.Raycast.html
Alternatively you can also use Character Controller Component inside Unity which already has a check named as IsGrounded :
More about Character controller here : https://docs.unity3d.com/ScriptReference/CharacterController.html

Related

How to rotate object towards target smooth slowly ? The object is not rotating facing the target

The goal in the end is to rotate the object when he start moving so the object will facing towards the target he is moving to and also that the laser that coming out from the object eye will be facing the same target.
The object that i want to rotate is at first at position 0,0,0 because the object is a child. the player is holding the object by hand. Then the object is getting throw with animation towards a target.
The object is moving to the target but now i want the object to rotate also smooth slowly to the target in this case i set the rotation duration 1 second. and i see that the object rotation is changing but not facing the target.
This screenshot show the object while it's still in the player hand at position 0,0,0
Then the object get throw and start moving to the target at this time the object rotation change :
The object that throw have a child transform the eye and from the eye a laser beam should be coming out and then i want to make that the object will rotate towards the target so the laser from the eye will be facing the target.
I marked the eye with a small red circle :
In this screenshot i marked the target far away, the laser in green is not facing the target and also the eye is not facing the target. the laser should come out the eye and the whole object should facing the target so the laser also should be facing the target with the eye.
This screenshot is of the object before running the game the eye is facing forwards with the object. this is just to show that the eye is aligned with the object facing forward.
This script is attached to my player and make the object to be thrown to the target and also should make the object to be rotating towards the target :
The throw part that make the object move to the target is working fine but the rotating part is not :
private IEnumerator AnimateRotationTowards(Quaternion transformRot, Quaternion targetRot, float dur)
{
float t = 0f;
while (t < dur)
{
transformRot = Quaternion.Slerp(transformRot, targetRot, t / dur);
yield return null;
t += Time.deltaTime;
}
transformRot = targetRot;
}
Also i see that making transformRot = targetRot; for some reason there is a small message say unnecessary assignment not sure why.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ThrowObject : MonoBehaviour
{
public Transform objectToThrow;
public Transform target;
public Transform objectToThrowParent;
public float throwingSpeed;
public float waitAtTargetTime;
public float distanceToStopFromTarget;
public bool go = false;
public AnimationCurve animationCurve;
private Animator anim;
private bool startThrowAnimationOnce = true;
private bool reParent = false;
private bool startMovingBack = false;
private void Start()
{
anim = GetComponent<Animator>();
}
private void Update()
{
if (anim != null && startThrowAnimationOnce)
{
anim.SetTrigger("Throw");
startThrowAnimationOnce = false;
}
if (go)
{
objectToThrow.parent = null;
StartCoroutine(Throw());
StartCoroutine(AnimateRotationTowards(objectToThrow.rotation, target.rotation, 1f));
go = false;
}
if (reParent)
{
objectToThrow.position = objectToThrowParent.position;
}
if (startMovingBack)
{
if (Vector3.Distance(objectToThrow.position, objectToThrowParent.position) >= 0.1f)
{
float step = 5 * Time.deltaTime;
objectToThrow.position = Vector3.MoveTowards(objectToThrow.position, objectToThrowParent.position, step);
}
else
{
objectToThrow.position = objectToThrowParent.position;
objectToThrow.parent = objectToThrowParent;
objectToThrow.localPosition = new Vector3(0, 0, 0);
}
}
}
public void ThrowEvent()
{
go = true;
}
IEnumerator Throw()
{
while(Vector3.Distance(objectToThrow.position, target.position) >= distanceToStopFromTarget)
{
objectToThrow.position = Vector3.MoveTowards(
objectToThrow.position,
target.position,
throwingSpeed * Time.deltaTime
);
yield return null;
}
yield return new WaitForSeconds(waitAtTargetTime);
startMovingBack = true;
}
private IEnumerator AnimateRotationTowards(Quaternion transformRot, Quaternion targetRot, float dur)
{
float t = 0f;
while (t < dur)
{
transformRot = Quaternion.Slerp(transformRot, targetRot, t / dur);
yield return null;
t += Time.deltaTime;
}
transformRot = targetRot;
}
}
This script is attached to the object eye and fire the laser :
The target in this script is the same target as in the ThrowObject script :
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System;
using UnityEngine;
public class Hovl_DemoLasers : MonoBehaviour
{
public List<Transform> targets;
public GameObject FirePoint;
public Camera Cam;
public float MaxLength;
public GameObject[] Prefabs;
private Ray RayMouse;
private Vector3 direction;
private Quaternion rotation;
[Header("GUI")]
private float windowDpi;
private int Prefab;
private GameObject Instance;
private Hovl_Laser LaserScript;
private Hovl_Laser2 LaserScript2;
private bool rotateMouse = true;
private bool startLaser = true;
private float buttonSaver = 0f;
private Hovl_LaserDemo hovl_laserDemo;
private float maxDistance = 0;
private int closestIndex = 0;
void Start()
{
if (Screen.dpi < 1) windowDpi = 1;
if (Screen.dpi < 200) windowDpi = 1;
else windowDpi = Screen.dpi / 200f;
Counter(0);
}
void Update()
{
//Enable lazer
if (Input.GetMouseButtonDown(0))
{
Destroy(Instance);
Instance = Instantiate(Prefabs[Prefab], FirePoint.transform.position, FirePoint.transform.rotation);
Instance.transform.parent = transform;
LaserScript = Instance.GetComponent<Hovl_Laser>();
LaserScript2 = Instance.GetComponent<Hovl_Laser2>();
rotateMouse = true;
}
if (Input.GetMouseButtonDown(1))
{
rotateMouse = false;
}
if ((Input.GetKey(KeyCode.A) || Input.GetAxis("Horizontal") < 0) && buttonSaver >= 0.4f)// left button
{
buttonSaver = 0f;
Counter(-1);
}
if ((Input.GetKey(KeyCode.D) || Input.GetAxis("Horizontal") > 0) && buttonSaver >= 0.4f)// right button
{
buttonSaver = 0f;
Counter(+1);
}
buttonSaver += Time.deltaTime;
if (startLaser)
{
rotateMouse = false;
Destroy(Instance);
Instance = Instantiate(Prefabs[Prefab], FirePoint.transform.position, FirePoint.transform.rotation);
Instance.transform.parent = transform;
LaserScript = Instance.GetComponent<Hovl_Laser>();
LaserScript2 = Instance.GetComponent<Hovl_Laser2>();
hovl_laserDemo = Instance.GetComponent<Hovl_LaserDemo>();
startLaser = false;
}
if (targets != null)
{
maxDistance = Mathf.Infinity;
for (int i = 0; i < targets.Count; i++)
{
float distance = Vector3.Distance(gameObject.transform.position, targets[i].position);
if (distance < maxDistance)
{
maxDistance = distance;
closestIndex = i;
}
}
if (hovl_laserDemo != null)
{
float distance = Vector3.Distance(gameObject.transform.position, targets[closestIndex].position);
MaxLength = distance;
hovl_laserDemo.MaxLength = distance;
}
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, MaxLength))
{
RotateToMouseDirection(gameObject, targets[closestIndex].position);
}
else
{
RotateToMouseDirection(gameObject, targets[closestIndex].position);
}
}
if (Cam != null && rotateMouse)
{
RaycastHit hit;
var mousePos = Input.mousePosition;
RayMouse = Cam.ScreenPointToRay(mousePos);
if (Physics.Raycast(RayMouse.origin, RayMouse.direction, out hit, MaxLength))
{
RotateToMouseDirection(gameObject, hit.point);
}
else
{
var pos = RayMouse.GetPoint(MaxLength);
RotateToMouseDirection(gameObject, pos);
}
}
else
{
Debug.Log("No camera");
}
}
void OnGUI()
{
GUI.Label(new Rect(10 * windowDpi, 5 * windowDpi, 400 * windowDpi, 20 * windowDpi), "Use the keyboard buttons A/<- and D/-> to change lazers!");
GUI.Label(new Rect(10 * windowDpi, 20 * windowDpi, 400 * windowDpi, 20 * windowDpi), "Use left mouse button for shooting!");
}
void Counter(int count)
{
Prefab += count;
if (Prefab > Prefabs.Length - 1)
{
Prefab = 0;
}
else if (Prefab < 0)
{
Prefab = Prefabs.Length - 1;
}
}
void RotateToMouseDirection(GameObject obj, Vector3 destination)
{
direction = destination - obj.transform.position;
rotation = Quaternion.LookRotation(direction);
obj.transform.localRotation = Quaternion.Lerp(obj.transform.rotation, rotation, 1);
}
}
This is one situation where it is important to understand the difference between passing by value, or passing by reference. In your AnimateRotationTowards function, all of the parameters to that function are passed by value. Changes to those rotations will affect the local values within the function scope, but those are not the same values that get used in the scene.
What you probably want instead is a reference to some Transform object. If you assign a new rotation to that Transform, it will use that rotation in the scene.
It looks like this script component is attached to the GameObject that will be rotating. Is that right? If yes, you can set a new rotation by assigning a value to transform.rotation:
private IEnumerator AnimateRotationTowards(Quaternion transformRot, Quaternion targetRot, float dur)
{
float t = 0f;
while (t < dur)
{
transform.rotation = Quaternion.Slerp(transformRot, targetRot, t / dur);
yield return null;
t += Time.deltaTime;
}
transform.rotation = targetRot;
}
If you need to assign a rotation to some other GameObject, you can pass in a reference to that GameObject or its Transform and use that to assign the rotation.

Changing a game objects velocity on button press in unity

So I'm trying to add a dash mechanic to a game character im building. However for some reason i can't get the game objects velocity to actually change. I tried using addForce which worked, but i had to add a lot in order to get the desired effect and that behaved strangely sometimes!
Do i need to do anything else to the game objects velocity than i already doing?
Heres my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float dashSpeed;
private int dashDirection;
private float dashCoolDown;
public float startDashCoolDown;
private float dashTime;
public float startDashTime;
public GameObject dashEffect;
public float speed;
public float jumpForce;
private float moveInput;
private Rigidbody2D rb;
private bool isFacingRight = true;
private Animator anim;
private bool isGrounded;
public Transform groundCheck;
public float checkRadius;
public LayerMask whatIsGround;
private int extraJumps;
public int extraJumpsValue;
public GameObject dustEffect;
public GameObject trailEffect;
private void Awake()
{
// Setting up references.
isGrounded = transform.Find("GroundCheck");
anim = GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
}
void Start()
{
extraJumps = extraJumpsValue;
rb = GetComponent<Rigidbody2D>();
dashTime = startDashTime;
dashCoolDown = startDashCoolDown;
}
void FixedUpdate()
{
isGrounded = false;
// Check to see if grounded
Collider2D[] colliders = Physics2D.OverlapCircleAll(groundCheck.position, checkRadius, whatIsGround);
for (int i = 0; i < colliders.Length; i++)
{
if (colliders[i].gameObject != gameObject)
{
isGrounded = true;
anim.SetBool("Ground", isGrounded);
}
}
// Check if movement is allowed
if (!GameMaster.disableMovement)
{
// Move character
moveInput = Input.GetAxis("Horizontal");
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
Instantiate(trailEffect, groundCheck.position, Quaternion.identity);
anim.SetFloat("Speed", Mathf.Abs(moveInput));
}
// Flip character
if (isFacingRight == false && moveInput > 0)
{
Flip();
}
else if (isFacingRight == true && moveInput < 0)
{
Flip();
}
}
private void Update()
{
// Check if the player is grounded
if (isGrounded == true)
{
extraJumps = extraJumpsValue;
}
// Check if movement is allowed
if (!GameMaster.disableMovement)
{
// Check for jump
// If the player has more than one jump available
if (Input.GetKeyDown(KeyCode.Space) && extraJumps > 0)
{
isGrounded = false;
anim.SetBool("Ground", isGrounded);
rb.velocity = Vector2.up * jumpForce;
extraJumps--;
Instantiate(dustEffect, groundCheck.position, Quaternion.identity);
}
// If the player only has one jump available
if (Input.GetKeyDown(KeyCode.Space) && extraJumps == 0 && isGrounded == true)
{
isGrounded = false;
anim.SetBool("Ground", isGrounded);
rb.velocity = Vector2.up * jumpForce;
}
// Check for dash
if (dashCoolDown <= 0)
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
anim.SetBool("Dash", true);
Dash();
dashTime = startDashTime;
}
}
else
{
dashCoolDown -= Time.deltaTime;
}
}
}
void Dash()
{
if (dashTime <= 0)
{
dashCoolDown = startDashCoolDown;
anim.SetBool("Dash", false);
}
else
{
dashTime -= Time.deltaTime;
if (isFacingRight)
{
rb.velocity = Vector2.right * dashSpeed;
}
else if (!isFacingRight)
{
rb.velocity = Vector2.left * dashSpeed;
}
}
}
void Flip()
{
isFacingRight = !isFacingRight;
// Multiply the player's x local scale by -1.
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
If you dont get the desired dash effect with Rigidbody.velocity, you can try using Rigidbody.addForce(). I know you said you already used it, but there are multiple different force modes you can apply here. I would suggest using this one, because it applies full force from the start and then drops it off. You can read more about it yourself here.
So you could modify your code like so:
void Dash()
{
if (isFacingRight)
{
rb.AddForce(Vector2.right*dashSpeed, ForceMode.VelocityChange);
}
else if (!isFacingRight)
{
rb.AddForce(Vector2.left*dashSpeed, ForceMode.VelocityChange);
}
}
Note, that you also dont need to call dash repeatedly to falloff the velocity. this function should now be only called onse the button to dash (shift) has been pressed.
Hope this helped!

I animated my 2D game but my character doesn't move

I've been following Brackeys tutorials to make a 2D game and right now I'm on animation. The animation plays he attacks, the sprite flips both directions, etc.. but still stuck in the same spot. I've watched and rewatched the tutorial and can't figure it out.
Before adding animation everything worked perfectly. He moved across the screen, he jumped, etc.. So i know that him not moving is directly tied to trying to animating
This is my playermovement script I made from following his tutorial.
public class playermovement : MonoBehaviour
{
public CharacterController2D controller;
public Animator animator;
public float runSpeed = 40f;
float horizontalMove = 0f;
bool jump = false;
bool Attack = false;
void Update()
{
horizontalMove = Input.GetAxisRaw("Horizontal") * runSpeed;
animator.SetFloat("Speed", Mathf.Abs(horizontalMove));
if (Input.GetButtonDown("Jump"))
{
jump = true;
animator.SetBool("IsJumping", true);
}
if (Input.GetKeyDown(KeyCode.Mouse0))
{
animator.SetBool("Attack", true);
Attack = false;
}
}
public void OnLanding ()
{
animator.SetBool("IsJumping", false);
}
private void FixedUpdate()
{
controller.Move(horizontalMove * Time.fixedDeltaTime, false, jump);
jump = false;
}
}
This is my character controller
public class CharacterController2D : MonoBehaviour
{
[SerializeField] private float m_JumpForce = 400f; // Amount of force added when the player jumps.
[Range(0, 1)] [SerializeField] private float m_CrouchSpeed = .36f; // Amount of maxSpeed applied to crouching movement. 1 = 100%
[Range(0, .3f)] [SerializeField] private float m_MovementSmoothing = .05f; // How much to smooth out the movement
[SerializeField] private bool m_AirControl = false; // Whether or not a player can steer while jumping;
[SerializeField] private LayerMask m_WhatIsGround; // A mask determining what is ground to the character
[SerializeField] private Transform m_GroundCheck; // A position marking where to check if the player is grounded.
[SerializeField] private Transform m_CeilingCheck; // A position marking where to check for ceilings
[SerializeField] private Collider2D m_CrouchDisableCollider; // A collider that will be disabled when crouching
const float k_GroundedRadius = .2f; // Radius of the overlap circle to determine if grounded
private bool m_Grounded; // Whether or not the player is grounded.
const float k_CeilingRadius = .2f; // Radius of the overlap circle to determine if the player can stand up
private Rigidbody2D m_Rigidbody2D;
private bool m_FacingRight = true; // For determining which way the player is currently facing.
private Vector3 m_Velocity = Vector3.zero;
[Header("Events")]
[Space]
public UnityEvent OnLandEvent;
[System.Serializable]
public class BoolEvent : UnityEvent<bool> { }
public BoolEvent OnCrouchEvent;
private bool m_wasCrouching = false;
private void Awake()
{
m_Rigidbody2D = GetComponent<Rigidbody2D>();
if (OnLandEvent == null)
OnLandEvent = new UnityEvent();
if (OnCrouchEvent == null)
OnCrouchEvent = new BoolEvent();
}
private void FixedUpdate()
{
bool wasGrounded = m_Grounded;
m_Grounded = false;
// The player is grounded if a circlecast to the groundcheck position hits anything designated as ground
// This can be done using layers instead but Sample Assets will not overwrite your project settings.
Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, m_WhatIsGround);
for (int i = 0; i < colliders.Length; i++)
{
if (colliders[i].gameObject != gameObject)
{
m_Grounded = true;
if (!wasGrounded)
OnLandEvent.Invoke();
}
}
}
public void Move(float move, bool crouch, bool jump)
{
// If crouching, check to see if the character can stand up
if (!crouch)
{
// If the character has a ceiling preventing them from standing up, keep them crouching
if (Physics2D.OverlapCircle(m_CeilingCheck.position, k_CeilingRadius, m_WhatIsGround))
{
crouch = true;
}
}
//only control the player if grounded or airControl is turned on
if (m_Grounded || m_AirControl)
{
// If crouching
if (crouch)
{
if (!m_wasCrouching)
{
m_wasCrouching = true;
OnCrouchEvent.Invoke(true);
}
// Reduce the speed by the crouchSpeed multiplier
move *= m_CrouchSpeed;
// Disable one of the colliders when crouching
if (m_CrouchDisableCollider != null)
m_CrouchDisableCollider.enabled = false;
} else
{
// Enable the collider when not crouching
if (m_CrouchDisableCollider != null)
m_CrouchDisableCollider.enabled = true;
if (m_wasCrouching)
{
m_wasCrouching = false;
OnCrouchEvent.Invoke(false);
}
}
// Move the character by finding the target velocity
Vector3 targetVelocity = new Vector2(move * 10f, m_Rigidbody2D.velocity.y);
// And then smoothing it out and applying it to the character
m_Rigidbody2D.velocity = Vector3.SmoothDamp(m_Rigidbody2D.velocity, targetVelocity, ref m_Velocity, m_MovementSmoothing);
// If the input is moving the player right and the player is facing left...
if (move < 0 && !m_FacingRight)
{
// ... flip the player.
Flip();
}
// Otherwise if the input is moving the player left and the player is facing right...
else if (move > 0 && m_FacingRight)
{
// ... flip the player.
Flip();
}
}
// If the player should jump...
if (m_Grounded && jump)
{
// Add a vertical force to the player.
m_Grounded = false;
m_Rigidbody2D.AddForce(new Vector2(0f, m_JumpForce));
}
}
private void Flip()
{
// Switch the way the player is labelled as facing.
m_FacingRight = !m_FacingRight;
// Multiply the player's x local scale by -1.
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
private void OnCollisionEnter2D(Collision2D collision)
{
if(collision.gameObject.tag == "Enemy")
{
Destroy(collision.gameObject);
}
}
}
It's probably a bit late to help the OP now, but I had exactly the same issue today and finally figured it out.
I was scaling the main object for some of my animations. To fix it I went in and removed any scaling of the main container object and instead scaled the internal objects individually and now the flipping works.
Clearly the animation scaling interferes with the controller flip scaling.
Try This Code but make shure you Character has a 2DRigidbody and a 2DBoxcollider and watch out that the script has the name "Character2DController"
I hope it will help you ;)
using UnityEngine;
public class Character2DController : MonoBehaviour
{
public float MovementSpeed = 1;
public float JumpForce = 1;
public Animator animator;
private bool facingRight;
private Rigidbody2D _rigidbody;
void Start()
{
facingRight = true;
_rigidbody = GetComponent<Rigidbody2D>();
}
void Update()
{
if (Input.GetAxis("Horizontal") < 0)
{
transform.localScale = new Vector2 (-1.5f, transform.localScale.y);
}
if (Input.GetAxis("Horizontal") > 0)
{
transform.localScale = new Vector2(1.5f, transform.localScale.y);
}
var movement = Input.GetAxis("Horizontal");
transform.position += new Vector3(movement, 0, 0) * Time.deltaTime * MovementSpeed;
animator.SetFloat("Movement Speed", Mathf.Abs(movement));
{
}
if ((Input.GetKeyDown(KeyCode.UpArrow) || Input.GetKeyDown(KeyCode.W) || Input.GetButtonDown("Jump")) && Mathf.Abs(_rigidbody.velocity.y) < 0.001f)
{
_rigidbody.AddForce(new Vector2(0, JumpForce), ForceMode2D.Impulse);
}
}`enter code here`
}
You may check the values from horizontalMove while debugging or add a Debug.Log statement to check its value while testing, just to make sure that the value is what is expected.
Also ensure that controller was assigned.

Unity 2D Jump script

So I was trying to implement double jumping in my game, which doesn't work. And now, somehow, not only can't my players double jump, they can't even jump either!
update: they can jump now, still can't double jump though.
This is my whole movement script:
using UnityEngine;
namespace Players
{
public class Actor : MonoBehaviour
{
//in order to control both players using 1 script.
public int playerIdx;
//Variables.
public float movementSpeed = 150f;
public float jumpForce = 250f;
//Ground stuff.
public LayerMask whatIsGround;
public bool grounded;
//boolean stuff.
private bool facingRight;
private bool moving;
//Needed to check if player is on the ground.
public Transform groundCheck;
//Limit player's movement speed.
public float maxMovementSpeed = 400f;
//Double jump stuff.
private bool doubleJumpReady;
//rb
private Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
doubleJumpReady = true;
rb = GetComponent<Rigidbody2D>();
facingRight = true;
}
// Update is called once per frame
void FixedUpdate()
{
SlowDown();
}
private void LateUpdate()
{
grounded = Physics2D.OverlapCircle(groundCheck.position, 0.1f, whatIsGround);
if (grounded)
doubleJumpReady = true;
}
private void SlowDown()
{
if (moving) return;
//if player is not moving, slow them down.
if (rb.velocity.x > 0.2f)
rb.AddForce(movementSpeed * Time.deltaTime * -Vector2.right);
if (rb.velocity.x < -0.2f)
rb.AddForce(movementSpeed * Time.deltaTime * Vector2.right);
}
public void Move(int dir)
{
//Flip the player.
Flip(dir);
//Moving the player.
moving = true;
float xVel = rb.velocity.x; //Get x velocity.
if ( dir > 0)
rb.AddForce(movementSpeed * Time.deltaTime * Vector2.right * dir);
else if (dir < 0)
rb.AddForce(movementSpeed * Time.deltaTime * Vector2.right * dir);
else if (dir == 0) { } //do nothing.
//Help player turn around faster.
if (xVel > 0.2f && dir < 0)
rb.AddForce(movementSpeed * 3.2f * Time.deltaTime * -Vector2.right);
if (xVel < 0.2f && dir > 0)
rb.AddForce(movementSpeed * 3.2f * Time.deltaTime * Vector2.right);
}
private void Flip(int dir)
{
if (facingRight && dir == -1 || !facingRight && dir == 1)
{
facingRight = !facingRight;
transform.Rotate(0f, 180f, 0f);
}
}
protected void Jump()
{
if (grounded)
{
rb.AddForce(Vector2.up * jumpForce);
grounded = false;
doubleJumpReady = true;
}
else if (!grounded && doubleJumpReady)
{
rb.AddForce(Vector2.up * jumpForce);
doubleJumpReady = false;
}
}
}
}
I don't know if it is because of my jump script, or my player script:
void Update()
{
if (playerIdx == 1)
{
if (Input.GetKey(KeyCode.A))
Move(-1);
if (Input.GetKey(KeyCode.D))
Move(1);
if (Input.GetKey(KeyCode.W))
Jump();
}
if (playerIdx == 2)
{
if (Input.GetKey(KeyCode.LeftArrow))
Move(-1);
if (Input.GetKey(KeyCode.RightArrow))
Move(1);
if (Input.GetKey(KeyCode.UpArrow))
Jump();
}
}
So how can I fix this?
as far as i can see you never reset the
doubleJumpReady = false;
Variable. To fix this simply change the jump code to:
protected void Jump()
{
if (grounded)
{
rb.AddForce(Vector2.up * jumpForce);
grounded = false;
doubleJumpReady = true;
}
else if (!grounded && doubleJumpReady)
{
rb.AddForce(Vector2.up * jumpForce);
doubleJumpReady = false;
}
}
Hope it works ;).
EDIT:
grounded is set by overlapping spheres. Therefore no need to set it here.
Use this code and press your jump btn 2 times and see if the Debug.Log message shows up. Also, your player ID (idx is not needed.) As far as i can see your script is attached two to different objects. Therefore their variables are not shared anyways.
protected void Jump()
{
if (grounded)
{
rb.AddForce(Vector2.up * jumpForce);
doubleJumpReady = true;
}
else if (!grounded && doubleJumpReady)
{
rb.AddForce(Vector2.up * jumpForce);
doubleJumpReady = false;
Debug.Log("I am double jumping");
}
}
And the final problem is, you do not execute one of your jumps you execute both at once.
THis happens due to your execution.
Input.GetKey(KeyCode.UP)
instead use:
Input.GetKeyDown(KeyCode.Up);
GetKeyDown returns true when the button is pressed.
GetKey returns true WHILE the button is pressed.
Hope it works now ;)
I would implement it with a counter, you can set the number of jumps you want.
The code would be like this:
jumpCount = 0;
protected void Jump()
{
if(!grounded && jumpCount < 2)
{
jumpCount++;
rb.AddForce(Vector2.up * jumpForce);
}
if(grounded)
jumpCount = 0;
}
Going off the assumption that you can now perform the normal jump again after reading the comments. I think the reason you can't 'double jump' is that when you call the Jump() method, you don't just call it once, you call it twice, so what happens is the player jumps and then immediately double jumps and so you don't actually notice that the double jump has occurred. You could make it so that your doubleJumpReady boolean is only true after a set amount of time after you have jumped initially using some sort of co-routine or something I implemented for a sort of double jump mechanic once was that the user could press the jump button again to double jump only when the player had reached the maximum height of the initial jump or after.

how can i use a for loop so my character can double jump?

I am trying to code a platforming game as right now all my character model can do is either jump infinitely or doesn't jump at all. I want to use a for loop so my character can jump one when grounded and once more when he is in the air but I cant figure out how to make it stop after double jumping once and resetting when the character hits the floor again. please help!!
public class SimplePlatformController : MonoBehaviour
{
[HideInInspector]
public bool facingRight = true;
[HideInInspector]
public bool jump = false;
public float moveForce = 365f;
public float maxSpeed = 5f;
public float jumpForce = 1000f;
public Transform groundCheck;
private bool grounded = false;
private Animator anim;
private Rigidbody2D rb2d;
// Use this for initialization
void Awake()
{
anim = GetComponent<Animator>();
rb2d = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
for (int i = 0; i <= 1; i++)
{
grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
if (Input.GetButtonDown("Jump") && grounded)
{
i = 0;
jump = true;
}
if (Input.GetButtonDown("Jump") && !grounded)
{
jump = true;
i = i + 1;
}
}
}
void FixedUpdate()
{
float h = Input.GetAxis("Horizontal");
anim.SetFloat("Speed", Mathf.Abs(h));
if (h * rb2d.velocity.x < maxSpeed)
rb2d.AddForce(Vector2.right * h * moveForce);
if (Mathf.Abs(rb2d.velocity.x) > maxSpeed)
rb2d.velocity = new Vector2(Mathf.Sign(rb2d.velocity.x) * maxSpeed, rb2d.velocity.y);
if (h > 0 && !facingRight)
Flip();
else if (h < 0 && facingRight)
Flip();
if (jump)
{
anim.SetTrigger("Jump");
rb2d.AddForce(new Vector2(0f, jumpForce));
jump = false;
}
}
void Flip()
{
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
A for loop is inappropriate for this, because you only want to advance the counter if you jump. and you need to leave the loop when it's time for the frame to end. You could in theory make it happen with a while loop in a Coroutine but that is unnecessarily complicated.
A better alternative is to just keep a counter as a class field and update it appropriately, according to the double jump state.
Also, since the if statement is being reached on every frame, you have to check if you have any more air jumps before you double jump.
If you want to be able to double-jump after you simply walk off a platform, you'll want to set the jump counter to 0 anytime grounded is set to be true.
Combining all of these suggestions might look like this:
public class SimplePlatformController : MonoBehaviour
{
// ...
private int airJumpCount = 0; // Add this counter
// ...
// Update is called once per frame
void Update()
{
grounded = Physics2D.Linecast(
transform.position, groundCheck.position,
1 << LayerMask.NameToLayer("Ground"));
if (grounded) airJumpCount = 0; // reset the counter when grounded
if (Input.GetButtonDown("Jump") && grounded)
{
jump = true;
}
// Only enter the air jump block if we still have more air jumps
if ( Input.GetButtonDown("Jump") && !grounded && airJumpCount < 1)
{
airJumpCount++;
jump = true;
}
}
// ...
}

Categories