I'm an absolute beginner in Unity and C# and I'm having some issues inserting a double jump on my Unity 2D Project. My question is: How can I be able to add a double jump on this code?
I tried to follow a lot of tutorials on internet, but I wasn't successful in any of the tutorials. This code I'm using right now is working normally, but I need to add the double jump function on the game.
Here's the code I'm using, I really need some help.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private Rigidbody2D rigidbody;
private BoxCollider2D collider;
private SpriteRenderer sprite;
private Animator animator;
[SerializeField] private LayerMask jumpableGround;
private float dirX = 0f;
[SerializeField]private float PlayerMovementSpeed = 7f;
[SerializeField]private float PlayerJumpSpeed = 8f;
private enum MovementState { idle, running, jumping, falling }
// Start is called before the first frame update
private void Start()
{
rigidbody = GetComponent<Rigidbody2D>();
collider = GetComponent<BoxCollider2D>();
sprite = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
}
// Update is called once per frame
private void Update()
{
dirX = Input.GetAxisRaw("Horizontal");
rigidbody.velocity = new Vector2(dirX * PlayerMovementSpeed, rigidbody.velocity.y);
if (Input.GetButtonDown("Jump") && IsGrounded())
{
GetComponent<Rigidbody2D>().velocity = new Vector2(0, PlayerJumpSpeed);
}
UpdateAnimationState();
}
private void UpdateAnimationState()
{
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 (rigidbody.velocity.y > .1f)
{
state = MovementState.jumping;
}
else if (rigidbody.velocity.y < -.1f)
{
state = MovementState.falling;
}
animator.SetInteger("state", (int)state);
}
private bool IsGrounded()
{
return Physics2D.BoxCast(collider.bounds.center, collider.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
}
}
The easy way to make this in your code is adding a counter of jumps, the variable starts in 0 and adds 1 to value on every jump, then you reset de variable when the character in on ground.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private Rigidbody2D rigidbody;
private BoxCollider2D collider;
private SpriteRenderer sprite;
private Animator animator;
[SerializeField] private LayerMask jumpableGround;
private float dirX = 0f;
[SerializeField]private float PlayerMovementSpeed = 7f;
[SerializeField]private float PlayerJumpSpeed = 8f;
private enum MovementState { idle, running, jumping, falling }
// NEW VARIABLE
private int jumpCounter;
// Start is called before the first frame update
private void Start()
{
rigidbody = GetComponent<Rigidbody2D>();
collider = GetComponent<BoxCollider2D>();
sprite = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
jumpCounter = 0;
}
// Update is called once per frame
private void Update()
{
dirX = Input.GetAxisRaw("Horizontal");
rigidbody.velocity = new Vector2(dirX * PlayerMovementSpeed, rigidbody.velocity.y);
//THE CONDITION CHANGES
if (Input.GetButtonDown("Jump") && jumpCounter<2)
{
GetComponent<Rigidbody2D>().velocity = new Vector2(0, PlayerJumpSpeed);
jumpCounter++;
}
if(IsGrounded())
{
jumpCounter = 0;
}
enter code here
UpdateAnimationState();
}
private void UpdateAnimationState()
{
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 (rigidbody.velocity.y > .1f)
{
state = MovementState.jumping;
}
else if (rigidbody.velocity.y < -.1f)
{
state = MovementState.falling;
}
animator.SetInteger("state", (int)state);
}
private bool IsGrounded()
{
return Physics2D.BoxCast(collider.bounds.center, collider.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
}
}
EDIT:
Added a fix to the IsGrounded method.
Related
When shooting a bullet or making a bomb explode, the player doesn't move as a projectile. Instead, they just move an unusually little distance. The players move as expected - a projectile, after reassigning groundCheck to "none", but the players themselves can't be moved any more. When colliding with a bullet or is in the range of a bomb, how can I change the code so that the player can move as a projectile without assigning groundCheck to "none" ?
Code of player:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveWASDPlayer1 : MonoBehaviour
{
public float speed = 5;
public float jumpForce = 10;
private float moveInput;
private Rigidbody2D rb;
private bool facingRight = true;
private bool isGrounded;
public Transform groundCheck;
public float checkRadius = 0.5f;
public LayerMask whatIsGround;
private int extraJumps;
public int extraJumpsValue = 1;
public Sprite Player1Shoot;
public Sprite Player1idle;
public GameObject Player2;
public GameObject PistolBulletToRight, PistolBulletToLeft;
Vector2 PistolBulletPos;
public float fireRate;
public int remainingBullet = 10;
private void Start()
{
extraJumps = extraJumpsValue;
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
Physics2D.IgnoreLayerCollision(6, 7);
Shoot();
CheckJumps();
Flip();
StartCoroutine(Fire());
moveInput = Input.GetAxis("Horizontal1");
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
if (Input.GetKeyDown(KeyCode.S))
{
Physics2D.IgnoreLayerCollision(3, 6, true);
Invoke("StopCollidingIntoGround", 0.25f);
}
}
void CheckJumps()
{
isGrounded = Physics2D.OverlapCircle(groundCheck.position, checkRadius, whatIsGround);
if (isGrounded == true)
{
extraJumps = extraJumpsValue; ;
}
if (Input.GetKeyDown(KeyCode.W) && extraJumps > 0)
{
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
extraJumps--;
Physics2D.IgnoreLayerCollision(3, 6, true);
Invoke("StopCollidingIntoGround", 0.48f);
}
else if (Input.GetKeyDown(KeyCode.W) && extraJumps == 0 && isGrounded == true)
{
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
}
}
void Flip()
{
if (facingRight == false && moveInput > 0)
{
facingRight = !facingRight;
Vector3 Scaler = transform.localScale;
Scaler.x *= -1;
transform.localScale = Scaler;
}
else if (facingRight == true && moveInput < 0)
{
facingRight = !facingRight;
Vector3 Scaler = transform.localScale;
Scaler.x *= -1;
transform.localScale = Scaler;
}
}
void StopCollidingIntoGround()
{
Physics2D.IgnoreLayerCollision(3, 6, false);
}
void Shoot()
{
if (Input.GetKeyDown(KeyCode.Z))
{
this.gameObject.GetComponent<SpriteRenderer>().sprite = Player1Shoot;
}
if (Input.GetKeyUp(KeyCode.Z))
{
this.gameObject.GetComponent<SpriteRenderer>().sprite = Player1idle;
}
}
IEnumerator Fire()
{
PistolBulletPos = transform.position;
if (remainingBullet < 1)
{
yield return new WaitForSeconds(2);
remainingBullet = 10;
}
if (Input.GetKeyDown(KeyCode.Z) && remainingBullet > 0)
{
if (facingRight)
{
PistolBulletPos += new Vector2(+1f, -0.1f);
Instantiate(PistolBulletToRight, PistolBulletPos, Quaternion.identity);
remainingBullet--;
yield return new WaitForSeconds(fireRate);
}
else
{
PistolBulletPos += new Vector2(-1f, -0.1f);
Instantiate(PistolBulletToLeft, PistolBulletPos, Quaternion.identity);
remainingBullet--;
yield return new WaitForSeconds(fireRate);
}
}
}
}
Code of bomb:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bomb : MonoBehaviour
{
Collider2D[] inExplosionRadius = null;
[SerializeField] private float ExplosionForceMulti = 5;
[SerializeField] private float ExplosionRadius = 5;
private void Update()
{
if(Input.GetKeyDown(KeyCode.X))
{
Explode();
}
}
void Explode()
{
inExplosionRadius = Physics2D.OverlapCircleAll(transform.position, ExplosionRadius);
foreach(Collider2D o in inExplosionRadius)
{
Rigidbody2D o_rigidbody = o.GetComponent<Rigidbody2D>();
if (o_rigidbody != null)
{
Vector2 distanceVector = o.transform.position - transform.position;
if(distanceVector.magnitude > 0)
{
float explosionForce = ExplosionForceMulti / distanceVector.magnitude;
o_rigidbody.AddForce(distanceVector.normalized * explosionForce);
}
}
}
}
private void OnDrawGizmos()
{
Gizmos.DrawWireSphere(transform.position, ExplosionRadius);
}
}
Code of bullet:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PistolBullet : MonoBehaviour
{
public float velX = 5f;
float velY = 0f;
Rigidbody2D rb;
Collider2D[] inShootRadius = null;
[SerializeField] public float ShootForceMulti = 5;
[SerializeField] public float ShootRadius = 5;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
private void Update()
{
rb.velocity = new Vector2(velX, velY);
Destroy(gameObject, 3f);
Shoot();
}
public void Shoot()
{
inShootRadius = Physics2D.OverlapCircleAll(transform.position, ShootRadius);
foreach (Collider2D o in inShootRadius)
{
Rigidbody2D o_rigidbody = o.GetComponent<Rigidbody2D>();
if (o_rigidbody != null)
{
Vector2 distanceVector = o.transform.position - transform.position;
if (distanceVector.magnitude > 0)
{
float explosionForce = ShootForceMulti / distanceVector.magnitude;
o_rigidbody.AddForce(distanceVector.normalized * explosionForce);
}
}
}
}
private void OnCollisionEnter(Collision collision)
{
Destroy(gameObject);
}
}
If I understand correctly: When getting hit by a bullet or explosion the player is not flung as expected?
I would argue this is the culprit: rb.velocity = new Vector2(moveInput * speed, rb.velocity.y); as you are overriding the player velocity every frame without taking in account the current velocity, unless moveInput has that calculated into.
As to why it works when GroundCheck is unassigned, because the script stops executing due to the missing reference beforehand and the Rigidbody will only be modified from the other scripts.
I have an enemy prefab with and a bullet prefab with rigidbody2D and boxcolliders to both of them. I have made a TakeDamage function for the enemy when i made meelee combat and also a bullet shooting script. I made a simple OnCollisionEnter2D on the enemy(code is below) and they do collide and give the collision effect but the function doesn't work, it doesn't give any errors either... What do I do now?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enemy : MonoBehaviour
{
public Transform player;
private Rigidbody2D rb;
[SerializeField] private SpriteRenderer sr;
private Vector2 movement;
public float moveSpeed = 5f;
public int maxHealth = 100;
int currentHealth;
Color32 colorRes = new Color32(255, 100, 50, 255);
public ParticleSystem deathParticles;
public GameObject projectile;
public int enemyDamage = 50;
public LayerMask rock;
// Start is called before the first frame update
void Start()
{
rb = this.GetComponent<Rigidbody2D>();
sr = GetComponent<SpriteRenderer>();
currentHealth = maxHealth;
}
// Update is called once per frame
void Update()
{
sr.flipX = player.position.x - transform.position.x > 0;
Vector3 direction = player.position - transform.position;
direction.Normalize();
movement = direction;
}
private void FixedUpdate()
{
moveCharacter(movement);
}
void moveCharacter(Vector2 direction)
{
rb.MovePosition((Vector2)transform.position + (direction * moveSpeed));
}
public void TakeDamage()
{
currentHealth -= enemyDamage;
if(currentHealth <= 0)
{
Die();
}
StartCoroutine(BecomeRed());
}
void Die()
{
Instantiate(deathParticles, transform.position, Quaternion.identity);
Destroy(gameObject);
}
IEnumerator BecomeRed()
{
sr.color = colorRes;
yield return new WaitForSeconds(0.6f);
sr.color = Color.white;
}
void OnCollisionEnter2D(Collision2D coll)
{
Debug.Log("test");
if (coll.gameObject.name == "rock")
{
TakeDamage();
Destroy(projectile);
}
}
}
I Am trying to add a swinging system to my game but whenever my player does the swinging animation it goes back to the same place how would I fix something like that? here is a video showing what it does: https://streamable.com/7jxgqx
I Use a character controller to move the player so does anyone know how to prevent the player from snapping back to the place it came from
Problem: https://streamable.com/7jxgqx
my codes: 1)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Swinging : MonoBehaviour
{
[SerializeField]Animator m_Animator;
CharacterController cc;
[SerializeField]GameObject jumpArea;
PlayerController playerController;
private void Start()
{
cc = GetComponent<CharacterController>();
playerController = GetComponent<PlayerController>();
playerController.enabled = true;
cc.enabled = true;
}
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Collider"))
{
StartCoroutine(StartSwinging());
}
}
IEnumerator StartSwinging()
{
m_Animator.SetTrigger("swing");
cc.enabled = false;
playerController.enabled = false;
yield return new WaitForSeconds(2.3f);
m_Animator.SetBool("afterSwing", true);
Destroy(jumpArea);
playerController.enabled = true;
cc.enabled = true;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
CharacterController cc;
public Transform groundCheck;
public LayerMask groundLayer;
float wallJumpVelocity;
public Animator m_Animator;
private Vector3 direction;
public float speed = 5f;
public float jumpForce = 8f;
public float gravity = -20f;
public bool canDoubleJump = true;
public bool isGrounded;
void Start()
{
cc = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
float horizontalInput = Input.GetAxis("Horizontal");
direction.x = horizontalInput * speed;
m_Animator.SetFloat("run", Mathf.Abs(horizontalInput)); // Mathf.Abs i igivea rac modulebi anu |-5| = 5
isGrounded = Physics.CheckSphere(groundCheck.position, 0.2f, groundLayer);
m_Animator.SetBool("isGrounded", isGrounded);
Jump();
if (horizontalInput != 0)
{
Quaternion flip = Quaternion.LookRotation(new Vector3(0, 0, horizontalInput));
transform.rotation = flip;
}
cc.Move(direction * Time.deltaTime);
}
void Jump()
{
// es kodi anichebs chvens motamashes axtomis funqicas
if (isGrounded)
{
canDoubleJump = true;
if (Input.GetButtonDown("Jump"))
{
direction.y = jumpForce;
}
}
else
{
if (canDoubleJump && Input.GetButtonDown("Jump"))
{
m_Animator.SetTrigger("doubleJump");
direction.y = jumpForce;
canDoubleJump = false;
}
}
direction.y += gravity * Time.deltaTime;
}
}
I Tried applying root motion too but it did not work i am using animations from mixamo.
Thanks <3
The Setup
I have a basketball player with an animator and 5 assigned animations to that animator as followed:
PlayerIdle
PlayerWalk
PlayerJump
PlayerBend
PlayerShoot
Setup_FruitHoops
Player Animation Window with Parameters
The Problem
In PlayMode, the player is able to move and jump successfully. The issue comes when the player attempts to grab the apple that is on the ground. The desired game design that I wanted was for the player to bend over and grab the apple by pressing the G key and then press G again to throw the apple towards the hoop to score a point. However, when I run it and after I first press G, the player can no longer jump, grab, or throw. The below section is the code for PlayerMovement and GrabberScript. Any advice is greatly appreciated.
PlayerMovement.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float speed = 5f;
private Rigidbody2D rb;
private Animator anim;
private bool isGrounded, jumped;
private float jumpshotPower = 6f;
public Transform groundCheck;
public LayerMask groundLayer;
private void Awake()
{
rb = GameObject.Find("Player Parent").GetComponent<Rigidbody2D>();
anim = GameObject.Find("Player Parent").GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
CheckIfGrounded();
PlayerJump();
}
private void FixedUpdate()
{
PlayerWalk();
}
void PlayerWalk()
{
float h = Input.GetAxisRaw("Horizontal");
if (h > 0)
{
//going right
anim.SetBool("isWalking", true);
rb.velocity = new Vector2(speed, rb.velocity.y);
ChangeDirection(-1);
}
else if (h < 0)
{
//going left
anim.SetBool("isWalking", true);
rb.velocity = new Vector2(-speed, rb.velocity.y);
ChangeDirection(1);
}
else
{
//standing still
anim.SetBool("isWalking", false);
rb.velocity = new Vector2(0f, rb.velocity.y);
}
}
void ChangeDirection(int d)
{
Vector3 temp = transform.localScale;
temp.x = d;
transform.localScale = temp;
}
void CheckIfGrounded()
{
isGrounded = Physics2D.Raycast(groundCheck.position, Vector2.down, 0.1f, groundLayer);
if (isGrounded)
{
if (jumped)
{
jumped = false;
anim.SetBool("isJumping", false);
}
}
}
void PlayerJump()
{
if (isGrounded)
{
if (Input.GetKey(KeyCode.UpArrow))
{
jumped = true;
rb.velocity = new Vector2(rb.velocity.x, jumpshotPower);
anim.SetBool("isJumping", true);
}
}
}
}
GrabberScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GrabberScript : MonoBehaviour
{
private bool grabbed, throwObject;
private RaycastHit2D hit;
public float distance;
public Transform holdpoint;
public float throwForce;
public LayerMask notFruitLayer;
private Animator anim;
private void Awake()
{
anim = GameObject.Find("Player Parent").GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.G))
{
if (!grabbed)
{
//grab fruit
anim.Play("PlayerBend");
Physics2D.queriesStartInColliders = false;
hit = Physics2D.Raycast(transform.position, Vector3.down * transform.localScale.x, distance);
if(hit.collider != null && hit.collider.tag == "Apple")
{
grabbed = true;
}
}
else if(!Physics2D.OverlapPoint(holdpoint.position, notFruitLayer))
{
//throw fruit
grabbed = false;
if(hit.collider.gameObject.GetComponent<Rigidbody2D>() != null)
{
PlayerShooting();
}
}
if (grabbed)
{
hit.collider.gameObject.transform.position = holdpoint.position;
}
}
}
private void OnDrawGizmos()
{
Gizmos.color = Color.green;
Gizmos.DrawLine(transform.position, transform.position + Vector3.down * transform.localScale.x * distance);
}
void PlayerShooting()
{
if (grabbed == true)
{
if (Input.GetKey(KeyCode.G))
{
throwObject = true;
hit.collider.gameObject.GetComponent<Rigidbody2D>().velocity = new Vector2(transform.localScale.x, 1) * throwForce;
anim.Play("PlayerShoot");
}
}
}
}
I am currently creating my final project for my coding class, and I have run into a snag in figuring out how to jump. I have used a tutorial video series as reference to my project, here is the link to the jumping episode. https://www.youtube.com/watch?v=05TCTrpGB-4&t=861s
I most likely have a logic error somewhere but every thing looks fine.
Heres my code:
private Rigidbody2D myRigidbody;
[SerializeField]
private float speed;
[SerializeField]
private Transform[] GroundPoints;
[SerializeField]
private float groundRadius;
[SerializeField]
private LayerMask WhatIsGround;
private bool isGrounded;
private bool Jump;
[SerializeField]
private float JumpForce;
// Use this for initialization
void Start () {
myRigidbody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void FixedUpdate () {
isGrounded = IsGrounded();
if(isGrounded && Jump)
{
isGrounded = false;
myRigidbody.AddForce(new Vector2(0, JumpForce));
}
float horizontal = Input.GetAxis("Horizontal");
HandleMovement(horizontal);
}
private void HandleInput()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Jump = true;
}
}
//Moving left/right
private void HandleMovement(float horizontal)
{
myRigidbody.velocity = new Vector2(horizontal * speed, myRigidbody.velocity.y);
}
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)
{
return true;
}
}
}
}
return false;
}
The HandleInput was not clarified in FixedUpdate. therefore, the code was not read in the update, making the code "invisible". so adding HandleInput like I added HandleMovement allowed for that code to be read.