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.
Related
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}");
}
}
I'm trying to make flappy bird and I'm trying to make it when the bird hits the "floor" a variable changes and then the script for the movement is not able to go.
Kinda hard for me to explain but here is the code i have:
void Update()
{
void OnCollisionEnter2D(Collider2D col)
{
if (col.gameObject.tag == "floor") // || col.gameObject.tag == "Pipe")
{
active = 0;
}
}
if (active == 1)
if (Input.GetKeyDown("space"))
{
GetComponent<Rigidbody2D>().velocity = new Vector3(0, 10, 0);
}
}
That is my code ^
Please help : )
void Update()
{
if (active == 1)
{
if (Input.GetKeyDown("space"))
{
GetComponent<Rigidbody2D>().velocity = new Vector3(0, 10, 0);
}
}
}
void OnCollisionEnter2D(Collider2D col)
{
if (col.gameObject.tag == "floor") // || col.gameObject.tag == "Pipe")
{
active = 0;
}
}
This code works fine for me, make sure you add Rigidbody2d to the player + add the box collider and the tag to the floor
First of all you have the OnCollisionEnter2D nested under Update as a local function. Unity doesn't find and call it this way, it needs to be at class level.
And then you set
active = 0;
but check for
active == 1
this seems odd. I would expect you check for the same value.
In general rather use a bool flag:
private bool active;
// reference via the Inspector if possible
[SerializeField] private Rigidbody2D _rigidbody;
private void Awake()
{
// as fallback get it ONCE on runtime
if(!_rigidbody) _rigidbody = GetComponent<Rigidbody2D>();
}
private void Update()
{
if (active)
{
if (Input.GetKeyDown("space"))
{
// only change the Y velocity, keep the rest
// that's needed e.g. if you are moving sideways currently
_rigidbody.velocity = new Vector3(_rigidbody.velocity.x, 10);
// immediately disable jumping
active = false;
}
}
}
private void OnCollisionEnter2D(Collider2D col)
{
if (col.gameObject.CompareTag("floor") || col.gameObject.CompareTag("Pipe"))
{
active = true;
}
}
// also disable jumping when exiting just in case
void OnCollisionExit2D(Collider2D col)
{
if (col.gameObject.CompareTag("floor") || col.gameObject.CompareTag("Pipe"))
{
active = false;
}
}
I'm new in c#, and I'm trying to make a platform falling down when the player stand on it. I used StartCoroutine so the platform fall down after five seconds, but for some reason my couroutine doesn't working.
this is the code:
public GameObject player;
private Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
rb.useGravity = false;
//rb.isKinematic = false;
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "player")
{
StartCoroutine(ObjectFall());
}
}
IEnumerator ObjectFall()
{
yield return new WaitForSeconds(5f);
Debug.Log("Its working");
this.rb.useGravity = true;
//this.rb.isKinematic = true;
}
}
You dont need to use IEnumerable if you have no parameters for the function. You could use Invoke("ObjectFall", 5) and turn your IEnumerable to void without yield. Its probably not the source of the problem but give it a try. Scale in your game is probably wrong that's why mass 1000 works. Try fixing your scale for the whole scene. Remember 1 unit = 1 meter more or less
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);
}
}
With this code I can display object's tag when the "Player" hits the object, but how could I make the tag appear before the collision? I mean, for example when the player stands 3 meters in front of the object?
private bool showInfo = false;
void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag == "Player")
{
showInfo = true;
}
}
void OnCollisionExit(Collision collisionInfo)
{
if (collisionInfo.gameObject.tag == "Player")
{
showInfo = false;
}
}
void OnGUI()
{
if (showInfo)
{
GUIStyle myStyle = new GUIStyle();
Font myFont = (Font)Resources.Load("Fonts/comic", typeof(Font));
myStyle.font = myFont;
myStyle.fontSize = 24;
myStyle.normal.textColor = Color.red;
GUI.Label(new Rect(10, 10, 100, 20), gameObject.tag, myStyle);
}
}
Create a aditional collider with the trigger option enabled, and make it bigger than the collider (to the size you want to detect the pre-collision) and call the OnTriggerEnter function.
void OnTriggerEnter(Collision col)
{
if (col.gameObject.tag == "Player")
{
showInfo = true;
}
}
Or.. you can check in the update of the object the distance to the player with Vector3.distance(Vector3 obj1, Vector3 obj2) and if it's less than 3 meters set showInfo to true
Driconmax's solution is the way I'd do it.
However, to provide another solution you could create a 3m long raycast in the direction of your movement and if it registers a hit, show that objects information. But I reckon thats a sub-par solution in most cases