OnCollisonEnter2D Unity c# script for 2D collisions not working - c#

I am trying to make a 2d platformer. I have an object that when the player collides with it, the game restarts. For some reason it doesn't work. I set a simple Debug.Log statement to test it. But, it just doesn't work. Here's the code
using UnityEngine;
public class Collision : MonoBehaviour
{
private void OnCollisionEnter2D(Collision2D collisionInfo)
if (collisionInfo.collider.tag == "Lose")
{
Debug.Log("lose");
}
}
}

Related

"Sticky platform" script not doing anything

I am following a tutorial online for making a basic 2D game on Unity and have gotten stuck on the part of making the "Player" follow along with the moving platform when standing on it. Right now the platform basically just slides out from under the player as it is not even there.
I eyeballed the Hierarchy on Unity while jumping onto the platform and noticed the "Player"'s parent never changes though I think it is supposed to.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StickyPlatform : MonoBehaviour
{
private void onTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.name == "Player")
{
collision.gameObject.transform.SetParent(transform);
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.gameObject.name == "Player")
{
collision.gameObject.transform.SetParent(null);
}
}
}
This is what I have tried, getting it straight from the tutorial (https://www.youtube.com/watch?v=UlEE6wjWuCY&list=PLrnPJCHvNZuCVTz6lvhR81nnaf1a-b67U&index=9)

Instantiated gameObject's self-written component is not working

I'm trying to implement chest mechanic in my game. When a user touches to chest, chest disappears and heart shows up. When player touches the instantiated heart, it must disappear and add 1 to life value, but the script is not working.
Chest.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Chest : MonoBehaviour
{
public GameObject heart;
public GameObject _heart; //Instantiated heart.
void OnTriggerEnter2D(Collider2D col){
if (col.gameObject.tag == "Player"){
Vector3 insPos = transform.position;
_heart = Instantiate(heart,new Vector3(insPos.x,insPos.y+0.5f,insPos.z),Quaternion.identity);
_heart.AddComponent<Heart>();
_heart.GetComponent<Heart>().ls = GameObject.FindGameObjectWithTag("Player").GetComponent<LifeSystem>();
Destroy(gameObject);
}
}
}
Heart.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Heart : MonoBehaviour
{
public LifeSystem ls;
void OnTriggerEnter2D(Collider2D col){
if (col.gameObject.tag == "Player"){
SoundManager.PlaySound("CollectCoinSound");
ls.lifes += 1;
Destroy(gameObject);
}
}
}
I check the components of the instantiated heart when player touches the chest and I can see that life system reference is added and so heart script is.
Thanks for your time.
You need to meet these conditions in order for OnTriggerEnter2D to be called on the spawned Hearth:
At least one between Player and Hearth need to have a Rigidbody2D component
Both Player and Hearth need to have a collider with IsTrigger = true
Player and Hearth GameObjects need to be on two interacting layers in the collision matrix
The Hearth component needs to be either on the same GameObject with a collider or on the same GameObject with the RigidBody2D
I actually simplified rules 1 and 2 a bit to show the most common use-case: if you want to know the actual rules for collisions, you can find them here (see the matrix at the bottom).
Besides the general collision rules I would make sure your fields have the correct type in the first place and already attach the Heart component to your prefab.
Also there is no need for find .. You already know the reference to the player you are colliding with
public class Chest : MonoBehaviour
{
public Heart heartPrefab;
void OnTriggerEnter2D(Collider2D col)
{
if (col.CompareTag("Player"))
{
Instantiate(heart, transform.position + Vector3.up * 0.5f), Quaternion.identity);
Destroy(gameObject);
}
}
}
and then simply do
public class Heart : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D col)
{
if (col.TryGetComponent<LifeSystem>(out var ls))
{
SoundManager.PlaySound("CollectCoinSound");
ls.lifes += 1;
Destroy(gameObject);
}
}
}
and rather have the LifeSystem attached to your player object.
In general I would kind of expect both eventually triggered at the same time since the heart might be already triggered if spawning right where the player is

This message parameter has to be of type: Collision

I have done this in 3D.
I don't have "is trigger" chosen in any objects.
I wanted to write down "it works" when my object hit an object that is tagged "Obstacle". I need help.
using UnityEngine;
public class Collision : MonoBehaviour
{
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Obstacle")
{
Debug.Log("it works");
}
}
}
(I'm new to Unity so please try to explain as I could understand TYSM.)
You should add the Rigidbody component to the object. It is necessary for collision detection

Unity 2D Trigger should only get triggered by one Player Prefab

I have a 2D game with one player as a prefab. And I have an apple with a 2D Trigger on it. But I only want that the trigger only gets triggered by the Player Prefab and not by the moving platforms.
But if i do this:
if (other.CompareTag ("Player")) {
or this:
if (other.gameObject.tag == "Player") {
My Trigger doesn't recognize the Player.
What should I do?
This is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NeuerTrigger : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D other)
{
Debug.Log("Geht");
}
}
You are probably not understanding how trigger is working.
Make sure that
1 On your apple there is a rigidbody and a collider with isTrigger to true
2 On your player there is a collider and a rigidbody
3 ON your player you have the tag "Player" in the inspector
If this is all like this then if you put this on the apple script:
void OnTriggerEnter2D(Collider2D other)
{
if(other.compareTag("Player")
// player touches apple
}

Can't figure out what i've done wrong

I'm new to programming and I'm currently trying to do a simple game in Unity.
The code makes some things dissapear when they touch the ground and it works well but the "Evaporated" variable does not update in the Unity Inspector. When something touch the ground, evaporated should be incremented, but it stays at 0.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
public class EnemyEvaporate : MonoBehaviour
{
public GameObject Enemy;
public int Evaporated;
void OnCollisionEnter(Collision CollisionInfo)
{
if (CollisionInfo.gameObject.name == "Map" || CollisionInfo.gameObject.name == "Player")
{
Thread.Sleep(15);
gameObject.SetActive(false);
Evaporated++;
}
}
}
I'm not really sure what's the behavior you're trying to get in this script. If Evaporated is some kind of 'Global counter' for score, it need to be written different and not store inside script for this gameObject.
It might be related to your gameObject.SetActive(false) which will deactivate your object, so in fact it will disables also the scripts connected with it (and especially this one. SetActive documentation) and removes them from Update() for a given gameObject (so given enemy. If you have 4 Enemy objects on the Scene, in fact you have 4 instances of this script and each has own Evaporated variable)
Why won't you move the void OnCollisionEnter(Collision CollisionInfo) to your Enemy scipt? I think Enemy should now if it collided with anything, not some external script.
You can also use tags instead of names when detecting Collisions.
Also, gameObject.SetActive(false) - if you set your gameObject to disabled, nothing more from its script will happen unless you set it to active again. It e.g. cancels all Coroutine. The gameObject is just "sleeping", I would say. It's not destroyed - you still can see it in your Hierarchy window - but it can't do anything. (By the way, in this case you're setting EnemyEvaporate gameObject as disabled, not Enemy gameObject.)
Also, you can use Coroutine instead of Thread.Sleep(15). It is more common to use Coroutines than Threads in Unity.
Now, Evaporation. If you want to count how many Enemies evaporated (I suppose, looking at Evaporated++;) you should have some external object to count it. The simplest way I can propose fow now is creating a GameObject with EvaporationCounter : MonoBehaviour script attached to it. You can also use Singleton pattern to be sure there's only one object of this type.
public class EvaporationCounter : MonoBehaviour
{
private int evaporates;
public int Evaporates {
get { return evaporates; }
private set
{
if (value >= 0) evaporates = value;
}
}
public void AddEvaporation()
{
Evaporates++;
}
}
Your Enemy class could look like:
public class Enemy : MonoBehaviour
{
private IEnumerator coroutine;
private EvaporationCounter evaporationCounter;
private void Start()
{
evaporationCounter = FindObjectOfType<EvaporationCounter>();
}
private IEnumerator WaitAndSetInactive(float waitTime)
{
yield return new WaitForSeconds(waitTime);
gameObject.SetActive(false);
}
private void OnCollisionEnter(Collision CollisionInfo)
{
if (!CollisionInfo.gameObject.CompareTag("Map") && !CollisionInfo.gameObject.CompareTag("Player")) return;
if (evaporationCounter != null)
evaporationCounter.AddEvaporation();
StartCoroutine(WaitAndSetInactive(15f));
}
}
Calling evaporationCounter.AddEvaporation() from the Enemy script is not the best solution, since it does not apply to the Dependency Inversion principle but I would say it's good for the beginning with Unity.

Categories