Here's what I have for my 3D code, on my Player. Debug.Log() does not print to console, nor does any other output.
void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.tag = "Enemy" && Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("Working");
}
}
Very simple code and I cannot find out what's wrong with it.
When I get rid of "&& Input.GetKeyDown(KeyCode.Space)" it works perfectly. Yes, I'm colliding with another GameObject tagged "Enemy", and my Player has Rigidbody attached. They're not positive for IsTrigger. I've even tried Input.GetKeyDown("space") instead of the KeyCode.
pretty unlikely that you manage to press down the key exactly in the same frame as the collision is detected!
Rather do e.g.
private GameObject currentEnemy;
private void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.CompareTag("Enemy"))
{
currentEnemy = collision.gameObject;
}
}
private void OnCollisionExit(Collision collision)
{
if(collision.gameObject.CompareTag("Enemy") && collision.gameObject == currentEnemy)
{
currentEnemy = null;
}
}
private void Update()
{
if(currentEnemy && Input.GetKeyDown(KeyCode.Space))
{
Debug.Log($"Working, interacting with {currentEnemy}");
}
}
Related
I am trying to achieve jumping on a 2d sprite in 3d world.
I can jump fine but I'm able to keep jumping in the air which I do not want.
I've been trying to find the problem for hours but still cannot come up with a solution.
{
public float jumpHeight = 5f;
public static bool isJumping = false;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && (isJumping == false))
{
gameObject.GetComponent<Rigidbody>().AddForce(new Vector2(0f, jumpHeight), ForceMode.Impulse);
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.collider.tag == "Ground")
{
isJumping = false;
}
}
private void OnCollisionExit(Collision collision)
{
if (collision.collider.tag == "Ground")
{
isJumping = true;
}
}
}
Am I missing something?
Put a collider as trigger on your 2D object and check if it is colliding with the terrain or ground. Only then you can jump. The same could be done with a Ray which collides with the ground. You dont need to use both just jump OnCollisionStay and thats it
I am developing a platform game, where a ball should be able to move left and right and to jump. I could make the character jump or move successfully, but when i tried to check if it was on the ground, by creating an element as child of the character, with a trigger collider 2D, and wrote the code using a variable that was supposed to be true when the player was touching the ground, and false when it wasn't, it just did not activate.
Here is the code for the main movement script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Grounded : MonoBehaviour
{
GameObject Player;
// Start is called before the first frame update
void Start()
{
Player = gameObject.transform.parent.gameObject;
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (GetComponent<Collider2D>().tag == "Ground")
{
Player.GetComponent<Move2D>().isGrounded = true;
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (GetComponent<Collider2D>().tag == "Ground")
{
Player.GetComponent<Move2D>().isGrounded = true;
}
}
}
And this is the Grounded script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move2D : MonoBehaviour
{
public float moveSpeed = 5f;
public bool isGrounded = false;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Jump();
Vector3 movement = new Vector3(Input.GetAxis("Horizontal"), 0f, 0f);
transform.position += movement * Time.deltaTime * moveSpeed;
}
void Jump()
{
if (Input.GetButtonDown("Jump") && isGrounded)
{
gameObject.GetComponent<Rigidbody2D>().AddForce(new Vector3(0f, 5f), ForceMode2D.Impulse);
}
}
}
Any help or information is really appreciated.
In
GetComponent<Collider2D>().tag == "Ground"
you are checking the tag of this GameObject's (child of Player) collider itself!
You probably rather wanted to check the tag of the thing you collided with.
Also avoid repeated GetComponent calls .. rather do it only once.
(Thanks #Jichael) You should also rather use CompareTag instead of using tag == "XY". It is more efficient and also actually checks if the given compare string exists as tag. If not an error is thrown while using == simply returns false which makes it hard to find evtl. typos.
// Would be better even to already reference this via Inspector
[SerializeField] private Move2D Player;
private void Awake()
{
if(!Player) Player = GetComponentInParent<Move2D>();
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.CompareTag("Ground"))
{
Player.isGrounded = true;
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.CompareTag("Ground"))
{
Player.isGrounded = true;
}
}
The same also in Move2D
[SerializeField] private Rigidbody2D rigidbody;
private void Awake()
{
if(!rigidbody) rigidbody = GetComppnent<Rigidbody2D>();
}
void Jump()
{
// This is very small but it is slightly cheaper to check the
// isGrounded value so this order is minimal faster if isGrounded is false
if (isGrounded && Input.GetButtonDown("Jump"))
{
rigidbody.AddForce(new Vector3(0f, 5f), ForceMode2D.Impulse);
}
}
Also note: Whenever a Rigidbody is involved you should not control the position via the Transform component but rather use Rigidbody2D.MovePosition to keep the Physics intact!
This has to be done however in FixedUpdate so your code would become something like
private Vector3 movement;
void Update()
{
Jump();
movement = new Vector3(Input.GetAxis("Horizontal"), 0f, 0f);
}
private void FixedUpdate ()
{
rigidbody.MovePosition(rigidbody.position += movement * Time.deltaTime * moveSpeed);
}
void Jump()
{
if (Input.GetButtonDown("Jump") && isGrounded)
{
rigidbody.AddForce(new Vector3(0f, 5f), ForceMode2D.Impulse);
}
}
Whether both objects require a Rigidbody or only the player depends on the ground objects (afaik):
ground objects are static → one (player) Rigidbody is enough
ground objects move → both need a rigidBody (the ground e.g. a kinematic)
Could you check both ball and ground has a rigidbody? which is required to trigger a trigger.
*Note: Trigger events are only sent if one of the Colliders also has a Rigidbody attached. *
Also could you change your code
private void OnTriggerEnter2D(Collider2D collision)
{
if (GetComponent<Collider2D>().tag == "Ground")
{
Player.GetComponent<Move2D>().isGrounded = true;
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "Ground")
{
Player.GetComponent<Move2D>().isGrounded = true;
}
}
Also I also recommend to use "layer" instead of using tag
I'm making a Mario replica in unity for my homework, and I'm trying to make the "Invisible" block, it starts off invisible, then when hit, it turns visible. I'm trying to use SpriteRenderer.enable to make it work, it works for turning it off in the start, but not when trying to make it visible.
I've tried to create a separate script for this particular block, but results are the same. All the tags are set correctly, I've tried using Debug.log to see if I enter the "if" where the sprite should be enabled, but the result is negative.
This is the start method turning off the sprite renderer for the particular block (it works):
private void Start()
{
//rendObject = this.gameObject.GetComponent<SpriteRenderer>();
if (gameObject.tag == "Invisible")
{
gameObject.GetComponent<SpriteRenderer>().enabled = false;
}
}
This is all the blocks script:
private void OnCollisionEnter2D(Collision2D collision)
{
if (timesToBeHit > 0)
{
if (collision.gameObject.tag == "Player" && IsPlayerBelow(collision.gameObject))
{
if (gameObject.tag == "Invisible")
{
gameObject.GetComponent<SpriteRenderer>().enabled = true;
}
collision.gameObject.GetComponent<PlayerController>().isJumping = false; //Mario can't jump higher
Instantiate(prefabToAppear, transform.parent.transform.position, Quaternion.identity); //instantiate other obj
timesToBeHit--;
anim.SetTrigger("GotHit"); //hit animation
}
}
if (timesToBeHit == 0)
{
anim.SetBool("EmptyBlock", true); //change sprite in animator
}
}
We've found a solution in chat, but for all people who may run or have run on this kind of problem will need to check for the next things:
Must have 2 Colliders of any type, 1 per gameObject.
At least 1 Rigidbogy.
Appropriately Collider setup.
Appropriate Tags.
Appropriate Layer Collision Matrix.
The code below will work.
public SpriteRenderer render;
void Start()
{
render.enabled = false;
}
private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.tag == "Player")
{
render.enabled = true;
}
}
public class InvisibleBlock : MonoBehaviour
{
public SpriteRenderer rendObject;
private void Start()
{
if (gameObject.tag == "Invisible")
{
rendObject.enabled = false;
}
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Player")
{
rendObject.enabled = true;
}
}
}
Separate script, sprite is attached in inspector, same results.
I got a Cube with a box collider and a trigger on it. When the player stands on it, it falls down.
I want the platform to destroy itself after colliding with something and before that, instantiate itself at its starting position.
So my code looks this:
void OnTriggerEnter(Collider col)
{
if (col.CompareTag("Player"))
isFalling = true;
}
void OnCollisionEnter(Collision col)
{
if (!col.gameObject.CompareTag("Player"))
{
Instantiate(gameObject, startPosition, startRotation);
Destroy(gameObject);
}
}
void Update()
{
if (isFalling)
{
fallingSpeed += Time.deltaTime / 20;
transform.position = new Vector3(transform.position.x, transform.position.y - fallingSpeed, transform.position.z);
}
}
Well when my platform crashes down, it just passes through the ground. There is even no collision detected.
Does someone got a hint for me?
So I just got my mistake.
The platform got no rigidbody attached. Therefore it was not able to collide with the ground.
This is my new code:
private void Start()
{
data.PlatformRigid.useGravity = false; // Disable the gravity to make it stay in the air
}
private void OnTriggerEnter(Collider col)
{
if (!data.Activated) // just do this 1 time
{
if (col.CompareTag("Player")) // just start executing the following code if the colliding object is the player
{
data.Activated = true; // don't execute this code a second time
data.PlatformRigid.useGravity = true; // start falling
}
}
}
private void OnCollisionEnter(Collision col)
{
if (!col.gameObject.CompareTag("Player"))
{
Instantiate(gameObject, data.StartPosition, data.StartRotation); // Create itself at default
Destroy(gameObject); // Destroy itself
}
}
I don't need to calculate the fallspeed in the update anymore. I just disable the gravity and enable it, when the player hits the platform.
If your collider is set to trigger, it won't fire the OnCollisionEnter event. Instead, put your code in the OnTriggerEnter like this:
void OnTriggerEnter(Collider col)
{
if (col.CompareTag("Player")) {
isFalling = true;
}
else
{
Instantiate(gameObject, startPosition, startRotation);
Destroy(gameObject);
}
}
My character can jump as much as you press ( W or space) I've read that you can prevent it with Raycast, but I don't understand how to do so. This is my character's code(this is a platformer game) :
private Rigidbody2D myRigidBody2D;
void Start () {
myRigidBody2D = GetComponent<Rigidbody2D>();
}
private void Update()
{
if (Input.GetButtonDown("Jump"))
{
myRigidBody2D.AddForce(new Vector2(0, jumpForce));
}
}
I've read that you can prevent it with Raycast
Yes, you can but you will likely run into problems which can still be fixed.
The best way to do this is to use a boolean variable to check if the character is touching the ground or not. You can set this variable to true or false in the OnCollisionEnter2D and OnCollisionExit2D functions.
Create a tag called "Ground". Change all your ground Gameobjects to this tag then the example below should prevent multiple jumping.
bool isGrounded = true;
private float jumpForce = 2f;
private Rigidbody2D myRigidBody2D;
void Start()
{
myRigidBody2D = GetComponent<Rigidbody2D>();
}
private void Update()
{
if (Input.GetButtonDown("Jump") && isGrounded)
{
myRigidBody2D.AddForce(new Vector2(0, jumpForce));
}
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = true;
}
}
void OnCollisionExit2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = false;
}
}