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;
}
Related
The problem is that - when two objects with the same scripts collide, I need to destroy them and create a new object. But they collide eachother and instead of one final object,i have 2 of them.
private void OnCollisionEnter2D(Collision2D collision)
{
var drop = collision.gameObject.GetComponent<DropBase>();
if (drop != null)
{
Destroy(collision.gameObject);
Instantiate(_pile, transform.position, Quaternion.identity);
Destroy(gameObject);
}
}
I was trying give every of object lifetime,and the longer living object have rights to create new one,but i have situation where thay created at same time,and this method doesn't work.
You can deactive the two game objects before destroying them, then you can ignore the collision if one of the game object is inactive.
private void OnCollisionEnter2D(Collision2D collision)
{
var incomingGameObject = collision.gameObject;
if(!gameObject.activeSelf || !incomingGameObject.activeSelf)
return;
var drop = incomingGameObject.GetComponent<DropBase>();
if (drop != null)
{
incomingGameObject.SetActive(false);
Destroy(incomingGameObject);
Instantiate(_pile, transform.position, Quaternion.identity);
gameObject.SetActive(false);
Destroy(gameObject);
}
}
You can try to notify another object that the collision is already processed. It can be done in different ways, here is one of them:
public bool IsPileInstantiated { get; private set; }
void Awake()
{
IsPileInstantiated = false;
}
private void OnCollisionEnter2D(Collision2D collision)
{
var drop = collision.gameObject.GetComponent<DropBase>();
if (drop != null)
{
if(drop.IsPileInstantiated == false)
{
Instantiate(_pile, transform.position, Quaternion.identity);
this.IsPileInstantiated = true;
}
Destroy(gameObject);
}
}
Perhaps it even has the sense to move this logic out of your drop objects. For example, notify another object (some GameManager or something like that) about a collision, and that object will have events from both objects, can filter these events, destroy objects if needed and create a needed object if it is needed.
I am trying to make a very simple animation in unity where an element fades in and out based on if a character enters a box collider of an NPC. When running the game, I have my Animator window open, and the blue horizontal line that normally appears under the entry state isn't even showing up. When looking at the previews of my animations the sprite I'm animating fades in and out so I know that isn't the problem. For some reason my entry state isn't even being reached and I can't figure out why.
I have the animation clips set up for an open and close state, I have a script that takes a public Animator and dragged the gameobject with the animator into the respective slot in the editor.
Here's the file that triggers the animation: (PS: I've inserted Debug.Log statements and know for a fact I am entering the if(playerInRange) condition.
public class DialogueTrigger : MonoBehaviour {
[SerializeField] private GameObject visualCue;
[SerializeField] private TextAsset inkJSON;
public Animator animator;
bool playerInRange;
void Awake() {
playerInRange = false;
visualCue.SetActive(false);
}
void Update() {
if (playerInRange) {
animator.SetBool("IsOpen", true);
if (InputManager.GetInstance().GetInteractPressed()) {
Debug.Log(inkJSON.text);
}
}
else {
animator.SetBool("IsOpen", false);
}
}
void OnTriggerEnter2D(Collider2D other) {
if (other.gameObject.tag == "Player") {
playerInRange = true;
}
}
void OnTriggerExit2D(Collider2D other) {
if (other.gameObject.tag == "Player") {
playerInRange = false;
}
}
}
UPDATE: aaaaand of course the second I post on stack overflow I figure it out. I needed to remove the visualCue.SetActive("False") line as that was disabling the sprite I was trying to animate, had that in there from a tutorial I was following earlier.
I have a game that I want a restart button to appear if you die (The game object destroys itself).
This is what I have. This is the script attached to the button:
public GameObject Player;
public GameObject Button;
bool player;
public void RestartGame(){
SceneManager.LoadScene("SampleScene");
}
void Start(){
player = true;
}
void Update(){
if (!Player){
player = false;
}
if(player == true) {
Button.SetActive(false);
}
if(player == false){
Button.SetActive(true);
}
}
And this is the code attached to the object that gets deleted:
void OnTriggerEnter(Collider other)
{
Destroy(gameObject);
}
When it starts the Button is disabled but when I die nothing appears. I have tried many things like checking if it is == null and all of that stuff but it still doesn't work. My goal is to make the restart button appear once the object is destroyed.
From what I understand you are checking if player get destroyed or not. However you are destroying trigger.
There must be a tag on player object use that. On your trigger object use this code. Pass player and button on inspector.
public GameObject Player;
Public GameObject Button;
void OnTriggerEnter(Collider other)
{
if (other.gameobject.comparetag("Player"))
{
Destroy (Player);
Button.SetActive(true);
}
}
For this to work both objects player and trigger must have colliders
and at least one of them must have rigidbody , and player tag must be Player
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.
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,