I want the player to jump when the player is grounded.
private void OnTriggerStay(Collider other)
{
if(other.gameObject.layer == 8)
{
isGrounded = true;
}else { isGrounded = false; }
}
The player is on air when spawning. After the player falls to the Terrain, which has the tag Ground, isGrounded is still false. When I set isGrounded manually true and jump again, it's still true after collision. I also don't want the player to double jump in the air, which I probaly already coded but is not working because something is wrong.
Changing OnTriggerStay to OnTriggerEnter doesn't change something. I hope you can help me.
Do not use OnTriggerStay to do this. That's not guaranteed to be true very time.
Set isGrounded flag to true when OnCollisionEnter is called. Set it to false when OnCollisionExit is called.
bool isGrounded = true;
private float jumpForce = 2f;
private Rigidbody pRigidBody;
void Start()
{
pRigidBody = GetComponent<Rigidbody>();
}
private void Update()
{
if (Input.GetButtonDown("Jump") && isGrounded)
{
pRigidBody.AddForce(new Vector3(0, jumpForce, 0));
}
}
void OnCollisionEnter(Collision collision)
{
Debug.Log("Entered");
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = true;
}
}
void OnCollisionExit(Collision collision)
{
Debug.Log("Exited");
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = false;
}
}
Before you say it doesn't work, please check the following:
You must have Rigidbody or Rigidbody2D attached to the player.
If this Rigidbody2D, you must use OnCollisionEnter2D and
OnCollisionExit2D.
You must have Collider attached to the player with IsTrigger
disabled.
Make sure you are not moving the Rigidbody with the transform such
as transform.position and transform.Translate. You must move
Rigidbody with the MovePosition function.
Use this to check if collision is detected at all, it's good starting point for further debuging:
private void OnTriggerStay(Collider other)
{
Debug.Log(other);
}
You must have Collider attached to the player with IsTrigger disabled.
I think you mean enabled? I was struggling to get this to work but as soon as I enabled the collider's IsTrigger it started actually working. The OnTriggerEnter/Exit doesn't seem to do very much on a collider that isn't actually a trigger...
Related
I have written code to heal the player after colliding with the health potion and then destroy the potion game object making it one time use, however, the gameobject does not get destroyed and the player is not healed. Code is as shown below:
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Player" )
{
playerHealthScript.heal();
Destroy(gameObject);
}
}
}
(code below is in a seperate script, used for player health)
public void heal()
{
currentHealth += healingAmount;
currentHealth = Mathf.Clamp(currentHealth, 0, 100);
healthBar.fillAmount = currentHealth / 100f;
}
Before seek for anything, you should Debug.Log("Collision") in your first function, maybe your code is right but the collision isn't detect.
If so, yo could consideer check if the syntax of "Player" is the same as the tag, or maybe your "Player" doesn't have any rigidbody2D ( 2D is important ! ).
I've started learning Unity and made a small script for a 2d character to move and jump.
The script works, though the problem is, I've made it so the character can only jump when it is on the ground, though after it jumps and touches the ground again, I have to let go of the jump button and press it again to jump again. How can I make it so that I can hold the jump button and have the character automatically jump again when the "if" statement becomes true?
{
Rigidbody2D rb;
public float speed;
private float moveX;
private float moveY;
private bool isjumping;
public float Jump;
public GameObject sqaureee;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
moveX = Input.GetAxis("Horizontal");
moveY = Input.GetAxis("Vertical");
rb.velocity = new Vector2 (moveX * speed, rb.velocity.y);
if (Input.GetKeyDown(KeyCode.Space) && isjumping == false)
{
rb.AddForce(new Vector2(rb.velocity.x, Jump));
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
GetComponent<SpriteRenderer>().color = Color.red;
if (collision.gameObject.CompareTag("Ground"))
{
isjumping = false;
}
}
private void OnCollisionExit2D(Collision2D collision)
{
GetComponent<SpriteRenderer>().color = Color.white;
if (collision.gameObject.CompareTag("Ground"))
{
isjumping = true;
}
}
}
Alright so I've found a solution and am going to leave it here if someone stumbles upon the same problem in the future.
Basically, rather than using Input.GetKeyDown, you just have to use Input.GetKey. That's it!
Now another mistake I realized I made was using AddForce to jump. with Input.GetKey, sometimes it runs the AddForce code multiple times since you are on the ground for multiple frames. I changed AddForce to rb.velocity = (blah blah blah) and now I get persistent jumps.
Good luck!
Edit: I just realized that Rafalon had the idea before me and posted it, I just didn't see it before posting this. Thank you!!
I'm trying to make my character do a drop attack in Unity where I want to ignore the collision detection of boxCollider2D for the moment when character & an enemy collide, then undo the ignore. So far the ignore collision is working but it's not reverting back to detect. So after the first successful drop attack my character can pass through the enemy instead of colliding. Here's my code below,
private Rigidbody2D rb;
private Animator anm;
private Collider2D coll;
private enum State {idle, running, jumping, attacking, falling, hurt}
private void OnCollisionEnter2D(Collision2D other) {
if (other.gameObject.tag == "Enemy") {
Enemy enemy = other.gameObject.GetComponent<Enemy>();
if (state == State.falling && anm.GetBool("dropAtk")) { // hurt enemy if drop attack
enemy.Hurt();
Physics2D.IgnoreCollision(other.gameObject.GetComponent<Collider2D>(), GetComponent<Collider2D>(), true);
} else { // take damange
if (other.gameObject.transform.position.x > transform.position.x) {
PlayerHurt("right");
} else {
PlayerHurt("left");
}
}
}
}
private void OnCollisionExit2D(Collision2D other) {
if (other.gameObject.tag == "Enemy") {
if (coll.IsTouchingLayers(ground)) {
Physics2D.IgnoreCollision(other.gameObject.GetComponent<Collider2D>(), GetComponent<Collider2D>(), false);
}
}
}
How can I re-enable collision detection by turning off the IgnoreCollision when character hits the ground? I'm a novice in unity so any suggestion will be really helpful. Thank you!
hope you get the idea
// Update is called once per frame
void FixedUpdate()
{
if(state==dropattck)
{
ChangeTrigger(player, true);
if(player.transform.position.y<floorvalue/*check your floor value*/)
{
transform.position.y = floorvalue;
}
}else
{
ChangeTrigger(player, false);
}
}
public void ChangeTrigger(GameObject obj,bool tf)
{
if(obj.GetComponent<Collider2D>().isTrigger!=tf)
obj.GetComponent<Collider2D>().isTrigger = tf;
}
a solution that comes to mind is to bound the position on the y axis and then temporarily set your collider to trigger. you bound the y so the player doesn't fall through the floor
otherwise you can check when your animation ends and set the collider back to detecting
Is there a way to detect if the collider on the player (with a rigidbody) object is not colliding with any other collider in a 2D environment?
Not per se, but there are two ways you can get the information. It's easiest to keep an int counter, and increment it in OnCollisionEnter and decrement in OnCollisionExit. When the counter is 0, there are no collisions.
Another way, which will tell you which colliders are overlapping but not necessarily if they are touching, is to use a physics function. Note which type of collider you have--sphere, capsule, box. Knowing the size/shape/position of the collider, you can call Physics.OverlapBox, Physics.OverlapCapsule, or Physics.OverlapSphere. Give the function the same shape as your collider, and it will return the colliders that overlap that space. (For 2D colliders, you can use the Physics2D.Overlap* functions.)
/edit - actually piojo's idea with counters is better, just use int instead of bool.
One way would be to add an int to your script called collisions and set it to 0. Then if at any point the collider fires OnCollisionEnter just increment it, and in OnCollisionExit decrement it.
Something like this should work for 3D:
public int collisions = 0;
void OnCollisionEnter(Collision collision)
{
collisions++;
}
void OnCollisionExit(Collision collision)
{
collisions--;
}
https://docs.unity3d.com/ScriptReference/Collider.OnCollisionEnter.html
https://docs.unity3d.com/ScriptReference/Collider.OnCollisionExit.html
I don't understand what's with all the number keeping. I just did this for when my character jumps or falls off the edge and it works great.
Both my player and terrain have colliders. I tagged my terrain with a "Ground" tag.
Then check if I am currently in contact with the collider with OnCollisionStay()
void OnCollisionStay(Collision collision)
{
if (collision.collider.tag == "Ground")
{
if(animator.GetBool("falling") == true)
{
//If I am colliding with the Ground, and if falling is set to true
//set falling to false.
//In my Animator, I have a transition back to walking when falling = false.
animator.SetBool("falling", false);
falling = false;
}
}
}
void OnCollisionExit(Collision collision)
{
if (collision.collider.tag == "Ground")
{
//If I exit the Ground Collider, set falling to True.
//In my animator, I have a transition that changes the animation
//to Falling if falling is true.
animator.SetBool("falling", true);
falling = true;
}
}
void OnCollisionEnter(Collision collision)
{
if (collision.collider.tag == "Obstacle")
{
//If I collide with a wall, I want to fall backwards.
//In my animator controller, if ranIntoWall = true it plays a fall-
//backwards animation and has an exit time.
animator.SetBool("ranIntoWall", true);
falling = true;
//All player movement is inside of an if(!falling){} block
}
}
I have this C# script attached to my main camera game object which also has a capsule collider attribute. However, it doesn't seem to do anything. How should I modify/add to this to make the camera "jump" and fall down to the ground again?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Jump : MonoBehaviour {
[HideInInspector] public bool jump = false;
public float jumpForce = 1000f;
public Transform groundCheck;
private bool grounded = false;
private Rigidbody rb;
// Use this for initialization
void Awake ()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update ()
{
grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
if (Input.GetButtonDown("Jump") && grounded)
{
jump = true;
}
}
void FixedUpdate()
{
if (jump)
{
rb.AddForce(new Vector2(0f, jumpForce));
jump = false;
}
}
}
Also, I would like to have the key for this be the spacebar if possible, but whatever key works or is there already is fine. I am still learning C#, so please forgive me if the solution is obvious.
This line is most likely causing the problem:
grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));`
There are 2 reason that it wont produce proper results:
You haven't setup your ground tiles or the place where you character moves to the "Ground" layer. You wont have this by default but you can add it from the Project Settings->Tags and Layers menu.
Your colliders are not close enough to the ground thus not causing collision.
Besides that it should work fine.