Function OnCollisionEnter is not working properly - c#

I've written code for destroying the player if it collides with an obstacle. But I get the error
The local function 'OnCollisionEnter' is declared but never used
My Code:
void Update()
{
void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag = "Player")
{
Destroy(col.gameObject);
}
}
}

Your code should look like this:
void Update()
{
}
void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag = "Player")
{
Destroy(col.gameObject);
}
}

You can theoretically define a function in your Update Method, they are called Local Functions.
But you can't do that with Unitys prepgroammed Functions eg. Start(), Update(), OnTriggerEnter(), OnCollisioEnter().
What you need to do instead, is take out your OnCollisionEnter() Function from the locally defined Update scope and instead place it into the MonoBehaviour Scope.
Example:
private void Update() {
}
private void OnCollisionEnter(Collision col) {
// Use CompareTag to get Error Message,
// when the Tag doesn't exist in the Scene
if (col.gameObject.CompareTag("Player")) {
Destroy(col.gameObject);
}
}
Unrelated:
I would also generally advise you to use CompareTag() instead of gameObjec.tag == "". Because CompareTag will throw an Error if there is no such Tag in your Scene and is therefore pretty usefull when you made a typo with the name of the Tag.

Related

How can I input and destroy the other gameObject on Trigger

I want to destroy a GameObject when it hits the trigger but with an input. No errors, but its not working in unity
using UnityEngine;
public class DestroyTile : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Tile"))
{
if(Input.GetKeyDown(KeyCode.Space))
{
Destroy(other.gameObject);
}
}
}
}
what should I do to make this work??
Very unlikely that you manage to hit the key in exactly the same frame the collision happens ;)
As a quick fix rather use OnTriggerStay
OnTriggerStay is called once per physics update for every Collider other that is touching the trigger.
public class DestroyTile : MonoBehaviour
{
// Called once every FixedUpdate for each trigger you are touching
private void OnTriggerStay(Collider other)
{
if (other.CompareTag("Tile"))
{
if(Input.GetKeyDown(KeyCode.Space))
{
Destroy(other.gameObject);
}
}
}
}
With above way there is only one last issue: OnTriggerStay is not actually called every frame but rather every FixedUpdate so you might miss a key press if it happened in a frame where FixedUpdate isn't called. Therefore in general getting User input within FixedUpdate (or other physics based continuous methods) is unreliable and should always be done in Update.
So instead you could/should do something like e.g.
public class DestroyTile : MonoBehaviour
{
private readonly HashSet<GameObject> _currentlyTouching = new HashSet<GameObject>();
private void OnTriggerEnter(Collider other)
{
if (!other.CompareTag("Tile") return;
// For some reason we still have the other object stored
if(_currentlyTouching .Contains(other.gameObject)) return;
// Store the other object
_currentlyTouching.Add(other.gameObject);
}
private void OnTriggerExit(Collider other)
{
// We don't have this other object stored
if(!_currentlyTouching.Contains(other.gameObject) return;
// remove this other object
_currentlyTouching.Remove(other.gameObject);
}
private void Update()
{
// Are we touching anything?
// This check is cheaper than Input.GetKeyDown
if(_currentlyTouching.Count <= 0) return;
if(!Input.GetKeyDown(KeyCode.Space)) return;
// destroy (all) the touched object(s)
foreach(var obj in _currentlyTouching)
{
Destroy(obj);
}
// Don't forget to also clear the HashSet in that case
_currentlyTouching.Clear();
}
}
This way you have the User Input separated in Update (every frame) and only track the entering and exiting colliders via the Physcis based system.

How to check if i`m touching something in Unity

I've got OnCollisionEnter2D function, but it say's only once, when i`m landing on ground, i want function that will return object name(or smthng like this) if i'm touching it, so if i'll stay on it it will say me about it not only once but every frame.
It's as simple as using the correct method OnCollisionStay2D which is called every frame while you are colliding with another object
Sent each frame where a collider on another object is touching this object's collider (2D physics only).
To be fair: Their example in that link is bullshit since it is for OnTriggerStay2D ^^
It could look like
private void OnCollisionStay2D(Collision2D collision)
{
Debug.Log($"I am touching {collision.gameObject.name}", this);
}
If instead you want to keep track of every touching object I would rather use something like
private HashSet<GameObject> _currentlyTouching = new HashSet<GameObject>();
private void OnCollisionEnter2D(Collision2D collision)
{
if(!_currentlyTouching.Contains(collision.gameObject))
{
_currentlyTouching.Add(collision.gameObject);
}
}
private void OnCollisionExit2D(Collision2D collision)
{
if(_currentlyTouching.Contains(collision.gameObject))
{
_currentlyTouching.Remove(collision.gameObject);
}
}
private void Update()
{
var logString = new StringBuilder("I am touching ");
foreach(var touchingObject in _currentlyTouching)
{
logString.Append(touchingObject.name).Append(" ");
}
Debug.Log(logString.ToString(), this);
}

OnCollisionExit is not being called

Why is OnCollisionExit not being called? I am using both OnCollisionEnter and OnCollisionExit but unfortunately only OnCollisionEnter is being called.
public bool HandleCollided = false;
public void OnCollisionEnter(Collision col)
{
if(col.gameObject.name == "RightHandAnchor")
{
HandleCollided = true;
}
}
public void OnCollisionExit(Collision col)
{
if(col.gameObject.name == "RightHandAnchor")
{
HandleCollided = false;
}
}
It's impossible to tell why your code isn't working based the given snippet - this code depends on the configuration of each of the GameObjects' inspector windows in the editor.
Both the GameObject that this script is attached to and the colliding GameObject must have one Collider component attached to each of them (for example, a BoxCollider component or a SphereCollider component). Both Colliders must have their isTrigger checkboxes disabled. The GameObject that this script is attached to must also have a Rigidbody component attached.
In order to debug this situation, add Debug.Log() statements in your functions. This is generally good practice, and it might be that the function is being called but the conditional statement is not true.
Here are some additional ideas on what might be going wrong:
You may be changing the name of the colliding GameObject somewhere else in your code.
You may be destroying the GameObject.
It might be that neither function was being called and HandleCollided was being changed elsewhere in your code.
It might be that the parameter, col, is not what you expect.
public void OnCollisionEnter(Collision col)
{
Debug.Log("Collision Enter!");
Debug.Log(col.gameObject.name);
}
public void OnCollisionExit(Collision col)
{
Debug.Log("Collision Exit!");
Debug.Log(col.gameObject.name);
}
So you said "There are two objects that collides with each other. One has sphere collider attached to it and another has box collider. One of the objects have rigidbody attached as well." On which one is the code? and yes this matters! only 1 of the objects will keep track of the exit meaning that if it's the non-kinematic it will not work.
Unfortunately using OnCollisionExit did not work so instead I used OnTriggerEnter and OnTriggerExit. I activated "isTrigger" for both objects.
public void OnTriggerEnter(Collider col)
{
Debug.Log("entered");
if (col.gameObject.name == "RightHandAnchor")
{
HandleCollided = true;
}
}
public void OnTriggerExit(Collider other)
{
Debug.Log("exit");
if (other.gameObject.name == "RightHandAnchor")
{
print("No longer in contact with " + other.transform.name);
HandleCollided = false;
}
}
You need a non-kinematic rigidbody attached to your object to get the event for OnCollisionExit
Try to use OnCollisionEnter() and OnTriggerExit() !!
Example:
void OnCollisionEnter(Collision collision)
{
if((collision.gameObject.GetComponent<AttributeManager>().attributes & doorType) != 0)
{
this.GetComponent<BoxCollider>().isTrigger = true;
}
}
private void OnTriggerExit(Collider other)
{
this.GetComponent<BoxCollider>().isTrigger = false;
}

Repeat function (unity3d/c#)

First of all, here's the code:
using UnityEngine;
using System.Collections;
namespace UltimateSurvival
{
public class Radiation : MonoBehaviour
{
public GameObject radiationEffect;
public EntityVitals Vitals { get { return m_Vitals; } }
private EntityVitals m_Vitals;
// Use this for initialization
void Start() {
InvokeRepeating ("OnTriggerEnter", 1.5f, 3.5f);
}
// Update is called once per frame
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
radiationEffect.SetActive(true);
//yield return new WaitForSeconds(5);
var entity = other.GetComponent<EntityEventHandler>();
if(entity)
{
var healthEventData = new HealthEventData(-Random.Range(7.0f, 23.0f));
entity.ChangeHealth.Try(healthEventData);
}
//yield return new WaitForSeconds(5);
}
}
void OnTriggerExit(Collider other)
{
if (other.gameObject.tag == "Player")
{
radiationEffect.SetActive(false);
}
}
}
}
What I'm trying to do is that I want this script to execute OnTriggerEnter every 3.5 seconds. As you can see, I'm using InvokeRepeating but it seems like it doesnt work. I've also tried changing void OnTriggerEnter on IENumerator OntriggerEnter and then yield return new WaitForSeconds(5); - It didn't work either. I'm really confused D: Please help!
It seems you're trying to solve the problem of draining HP from the player if player is inside the area of radiation. This is a solution that will use most of your current code, but is not neccesarily the best code. I'd also like to inform you of OnTriggerStay, which
is called once per frame for every Collider other that is touching the trigger.
and can also be used to solve this problem. I'm going to use your already declared OnTriggerEnter and OnTriggerExit to damage every player inside area every 3.5 seconds.
public GameObject radiationEffect;
public EntityVitals Vitals { get { return m_Vitals; } }
private EntityVitals m_Vitals;
// Declare a list that will contain the players.
List<GameObject> playersInArea = new List<GameObject>();
// Use this for initialization
void Start() {
InvokeRepeating ("DamagePlayers", 1.5f, 3.5f);
}
void DamagePlayers() {
foreach (var player in playersInArea) {
var entity = player.GetComponent<EntityEventHandler>();
if(entity)
{
var healthEventData = new HealthEventData(-Random.Range(7.0f, 23.0f));
entity.ChangeHealth.Try(healthEventData);
}
}
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
playersInArea.Add(other.gameObject);
radiationEffect.SetActive(true);
}
}
void OnTriggerExit(Collider other)
{
if (other.gameObject.tag == "Player")
{
playersInArea.Remove(other.gameObject);
if (playersInArea.Count == 0) {
radiationEffect.SetActive(false);
}
}
}
Something like that should work. If you only have 1 player it should work all the same, but this supports multiple players. Let me know if you have any further issues.
You have problems calling your method using InvokeRepeating because of two reasons:
InvokeRepeating can not be used with method that have parameters: you probably have the Trying to Invoke method: [...] couldn't be called. message in your console.
OnTriggerEnter is a method that is automatically called by Unity when the gameobject's collider is set as Trigger and another collider enters it: as #Hellium said, calling such methods manually is a bad idea (same as calling Start or Update manually: this can happen but really doesn't make sense in most of the scenarios).
Hope this helps,

Destroy Parent Object Unity3D

I'm facing the problem that i wish to destroy a parent object but i couldn't do so.
i wish to destroy User01 while bullet hit any of these child.
My code was as below.
JS:
function OnControllerColliderHit(col:ControllerColliderHit){
if(col.gameObject.tag == "Bullet"){
Destroy(col.transform.parent.gameObject);
}
}
C#:
public class PlayerDoe : MonoBehaviour {
private GameObject par;
// Use this for initialization
void Start () {
par = transform.parent.gameObject;
}
// Update is called once per frame
void Update () {
}
void OnCollisionHit(Collision col){
if (col.gameObject.tag == "Bullet") {
Destroy(par);
}
}
}
I believe you need to use OnCollisionEnter, instead of OnCollisionHit.
There is no OnCollisionHit(). You want to use OnCollisionEnter
void OnCollisionEnter(Collision collision)
{
if(col.gameObject.tag == "Bullet")
Destroy(transform.parent.gameObject);
}

Categories