My collider object has two child objects, there are camera and collider(is Triggered = true). I need to detect collision child collider and recognize all touched object by this child collider.
gameObject(CapsuleCollider(isTriggered = false), Rigidbody)
gameObject(Camera)
gameObject(CapsuleCollider(isTriggered = true))
I think this is wrong code, but maybe not, at least just for some imagination:
CapsuleCollider legsTrigger;
void Update()
{
legsTrigger= GetComponentInChildren<CapsuleCollider>();
if(legsTrigger.contact...){
Debug.Log("This is : ");
Debug.Log(legsTrigger.gameObject.tag);
}
}
You need to add a monobehaviour to your child. Otherwise you can't detect. If you want to check it from your parent gameobject, on this link there is a really nice solution for it by rsodre. I copied the codes from it and converted from 2D colliders to 3D.
Firstly, create a Bridge script between parent gameobject and childs
public class ColliderBridge : MonoBehaviour
{
ColliderListener _listener;
public void Initialize(ColliderListener l)
{
_listener l;
}
void OnCollisionEnter(Collision collision)
{
_listener.OnCollisionEnter(collision);
}
void OnTriggerEnter(Collider other)
{
_listener.OnTriggerEnter(other);
}
}
Then, add this ColliderBridge script to all childs, and then listen collision events from parent like this(Add ColliderListener script to parent gameobject).
public class ColliderListener : MonoBehaviour
{
void Awake()
{
// Check if Colider is in another GameObject
Collider collider = GetComponentInChildren<Collider>();
if (collider.gameObject != gameObject)
{
ColliderBridge cb = collider.gameObject.AddComponent<ColliderBridge>();
cb.Initialize(this);
}
}
public void OnCollisionEnter(Collision collision)
{
// Do your stuff here
}
public void OnTriggerEnter(Collider other)
{
// Do your stuff here
}
}
Related
I am creating a game with unity and I have a question.
I have 5 game objects + player. And they always rotate when the game has started. I want that if the player collides with the object that is tagged snowflake, the other 4 objects pause the rotation.
Have a static event on your player script, when player collide invoke that event. On other scripts subscribe to that event.
For example in your PlayerScript should be something like
public class PlayerScript : MonoBehaviour {
public static UnityAction OnPlayerCollidedWithSnowFlakes;
private void OnCollisionEnter(Collision other) {
if (other.gameObject.tag.Equals("snowflake")) {
OnPlayerCollidedWithSnowFlakes?.Invoke();
}
}
}
And your RotatingObjectScript should be something like
public class RotatingObjectScript : MonoBehaviour {
private void Awake() {
PlayerScript.OnPlayerCollidedWithSnowFlakes += CollidedWithSnowflakeEventHandler;
}
private void OnDestroy() {
PlayerScript.OnPlayerCollidedWithSnowFlakes -= CollidedWithSnowflakeEventHandler;
}
private void CollidedWithSnowflakeEventHandler() {
.
.
// Stop rotating
.
.
}
}
Im currently trying to code a health system for my game and I want my Player GameObject to ignore collision with the Health Potion GameObject if the Player has max health. My problem is that I cannot simply turn off the collision between the Player Layer and Health Potion Layer because I only want to ignore collision if the Player has Max Health. I tried doing it myself but it didn't work. Here's my code:
public class ExampleCodeUA : MonoBehaviour{
public int PlayerMaxHealth = 100, PlayerCurrentHealth;
public HealthBar healthBar;
private void Start()
{
PlayerCurrentHealth = PlayerMaxHealth;
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("HealthPotion"))
{
if (PlayerCurrentHealth == PlayerMaxHealth)
{
Physics2D.IgnoreLayerCollision(6, 7);
}
else if (PlayerCurrentHealth > 50)
{
GetHealth(PlayerMaxHealth - PlayerCurrentHealth);
}
else if (PlayerCurrentHealth <= 50)
{
GetHealth(50);
}
}
}
void GetHealth(int healing)
{
PlayerCurrentHealth += healing;
healthBar.SetHealth(PlayerCurrentHealth);
}
}
You don't want to modify your physics configuration at runtime. What you could do to avoid the collision... is to make it impossible, by having nothing to collide with. Both of your objects have a collider. What you could do is to disable all existing HealthPotion colliders by modifying their code. An implementation could be the following:
using System.Collections.Generics;
using UnityEngine;
public class HealthPotion : MonoBehaviour
{
private static List<HealthPotion> _existingPotions = new List<HealthPotion>();
public static void EnablePotionsCollider(bool value)
{
foreach (var potion in _existingPotions)
{
potion._collider.enabled = value;
}
}
private Collider _collider;
void Awake()
{
_collider = GetComponent<Collider>();
}
void OnEnable()
{
_existingPotions.Add(this);
}
void OnDisable()
{
_existingPotions.Remove(this);
}
}
Then you just have to call the method when you want to enable/disable by doing
HealthPotion.EnablePotionsCollider(value you want);
so I'm making a 2d platform. My level is made up of a multiple platforms that are all part of a prefab. I want to make it so when my player presses a key (in this case 'E') inside of a collider2d the platform above the player is destroyed and the box resting on the platform falls down.
I've got the detection working for when 'E' is pressed inside of the trigger but can't figure out how to destroy just the single platform in the prefab.
Any help would be appreciated!
public class SwitchController : MonoBehaviour
{
public Collider2D switchCollider;
public Rigidbody2D player;
void Start()
{
switchCollider = GetComponent<Collider2D>();
}
private void OnTriggerStay2D(Collider2D col)
{
// var player = col.GetComponent<PlayerController>();
var actionBtn = PlayerController.action;
if (player)
{
Debug.Log("Collided");
if (Input.GetKeyDown(KeyCode.E))
{
actionBtn = true;
Debug.Log("Action Pressed");
}
}
}
}
If possible, the simplest solution would be to store the platform via the inspector (of the prefab).
Then you would destroy the game-object when needed, like so:
public class SwitchController : MonoBehaviour {
// ...
public GameObject targetPlatform;
private void OnTriggerStay2D(Collider2D col) {
// ...
Destroy(targetPlatform); // Destroy the platform.
}
}
Or, you can raycast upwards from the player
public class SwitchController : MonoBehaviour {
public Collider2D switchCollider;
public Rigidbody2D player;
[SerializeField, Tooltip("The layer mask of the platforms.")]
public LayerMask platformLayerMask;
void Start() {
switchCollider = GetComponent<Collider2D>();
}
private void OnTriggerStay2D(Collider2D col) {
var actionBtn = PlayerController.action;
if (player) {
if (Input.GetKeyDown(KeyCode.E)) {
actionBtn = true;
// Raycast upwards from the player's location.
// (Raycast will ignore everything but those with the same layermask as 'platformPlayerMask')
RaycastHit2D hit = Physics2D.Raycast(player.transform.position, Vector2.up, Mathf.Infinity, platformLayerMask);
if (hit.collider != null) {
// Destroy what it hits.
Destroy(hit.transform.gameObject);
}
}
}
}
}
Compared to the first solution, this solution is more dynamic.
You just have to set the Layers of the platforms in the inspector.
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;
}
I writing simple game on Unity (C#)
I have player and want to make the destroyer, that will destroy player.
I create prefab of destroyer. And next, I create Quad.
I have spawn script:
using UnityEngine;
using System.Collections;
public class SpawnScript : MonoBehaviour {
public GameObject[] obj;
public float spawnMin = 1f;
public float spawnMax = 2f;
// Use this for initialization
void Start () {
Spawn();
}
void Spawn()
{
Instantiate(obj[Random.Range(0, obj.GetLength(0))], transform.position, Quaternion.identity);
Invoke("Spawn", Random.Range(spawnMin, spawnMax));
}
}
Also I write DestroyerScript:
using UnityEngine;
using System.Collections;
public class DestroyerScript : MonoBehaviour {
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
Application.LoadLevel(1);
return;
}
if (other.gameObject.transform.parent)
{
Destroy(other.gameObject.transform.parent.gameObject);
}
else
{
Destroy(other.gameObject);
}
}
}
My destroyer spawning, but when player get it, I don't have Game Over screen.
Add rigid body to both player and "player destroyer" and then set onTriggerEnter on your player destroyer like so:
void OnTriggerEnter(Collider other) {
Destroy(other.gameObject);
}
For some fine tuning, you can do some checks if the other object is in fact the Destroyer (you can compare the tag or something, I won't go into too much detail now).
EDIT: Uncheck "isTrigger" on your BoxColliders and try this:
void OnCollisionEnter (Collision col)
{
Destroy(col.gameObject);
}