GameObject not detecting collision with floor - unity3d

My GameObject starts out resting on the floor. isKinematic is set to true and a trigger is set to true on the box collider.
When the player touches the collider. It moves the GameObject down below to floor. Then i set the isKinematic to false and the trigger to false. This forces the game object to fall until it hits the floor and stops. My problem is after the game object hits the floor and stops. I can not get the GameObject to recognize it has collided with the floor. I have a Debug.Log statement in OnCollisionEnter2D and OnCollisionStay2D. The Debug.Log does not appear in the console when they touch. Why is this?
The GameObject has a Rigidbody and box collider. The floor has a box collider and Rigidbody as well.
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player")
{
Debug.Log ("Player is touching the section");
//sectionRigidbody.isKinematic = true;
if (readyToDrop == false)
//moves player
transform.position += newPosition;
readyToDrop = true;
sectionRigidbody.isKinematic = false;
sectionBoxCollider.isTrigger = false;
sectionRigidbody.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
//sectionRigidbody.isKinematic = true;
}
}
void OnCollisionEnter2D(Collider2D col)
{
if (col.gameObject.tag == "Floor")
{
Debug.Log ("section is touching the floor");
}
}
void OnCollisionStay2D(Collider2D col)
{
if (col.gameObject.tag == "Floor")
{
Debug.Log ("section is touching the floor");
}
}

Pay attention when using the collision callback functions with parameter.
OnTriggerEnter2D takes Collider2D as parameter. You got this right.
OnCollisionEnter2D and OnCollisionStay2D takes Collision2D as parameter NOT Collider2D. This is where you failed.
Collider2D and Collision2D sounds so simlar but are not the-same.
They won't be called if you got their parameter wrong.
In the latest version of Unity, error will be thrown in the Editor when you make this mistake. It looks something like this:
Script error: OnCollisionEnter2D This message parameter has to be of
type: The message will be ignored.
and
Script error: OnCollisionStay2D This message parameter has to be of
type: The message will be ignored.
Solution:
Replace
void OnCollisionEnter2D(Collider2D col) and void OnCollisionStay2D(Collider2D col)
with
void OnCollisionEnter2D(Collision2D col) and void OnCollisionStay2D(Collision2D col).

You mentioned that trigger is set to true.
A trigger doesn't register a collision with an incoming Rigidbody. Instead, it sends OnTriggerEnter, OnTriggerExit and OnTriggerStay message when a rigidbody enters or exits the trigger volume.
Source: https://docs.unity3d.com/ScriptReference/Collider-isTrigger.html

Related

How to access the collider attached to the children of a prefab?

I have attached a script to a prefab and the script is:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class destroyer: MonoBehaviour {
Circles circles;
Collider2D collider1;
Collider2D collider2;
private void Start() {
collider1 = gameObject.transform.GetChild(0).GetComponent < Collider2D > ();
collider2 = gameObject.transform.GetChild(1).GetComponent < Collider2D > ();
circles = FindObjectOfType < Circles > ();
}
private void Update() {
if (transform.position.y < 2) {
Destroy(gameObject);
circles.instantiator();
}
}
void OnTriggerStay2D(Collider2D other) {
if (collider1.bounds.Contains(other.bounds.max) && collider1.bounds.Contains(other.bounds.min)) {
print("2");
if (other.bounds.Contains(collider2.bounds.max) && other.bounds.Contains(collider2.bounds.min)) {
print("3");
if (transform.position.y > 3) {
print("4");
Destroy(other.gameObject);
Destroy(gameObject);
circles.instantiator();
}
}
}
}
}
OnTriggerStay2D function is getting called but the condition when a GameObject is completely inside the collider 1 and outside the collider 2 is never true even if the other GameObject satisfies the condition.
Previously when I have attached both collider to the prefab then this condition becomes true when the game object satisfy the condition. But after the change it is not working. I think that I am not accessing the collider of a child properly or there is some other error. Please help me to resolve this problem.
This is the pic of gameobject with two children each having circular collider
and when other game object having circular collider comes in between both the circular collider then I want to perform some action.
this is ultimately what I want to achieve
Edit : the same function is working fine and I am getting what I want when I put the prefab on the scene and then running the game . But it is not working with the same prefab which is instantiated after running the game.
I think you can improve your conditions by using Collider2D.IsTouching like so:
void OnTriggerStay2D(Collider2D other) {
if (collider1.IsTouching(other)) {
print("2");
if (other.IsTouching(collider2)) {
print("3");
if (transform.position.y > 3) {
print("4");
Destroy(other.gameObject);
Destroy(gameObject);
circles.instantiator();
}
}
}
}
Reference: ScriptReference/Collider2D.IsTouching
Check whether this collider is touching the collider or not.
It is important to understand that checking whether colliders are touching or not is performed against the last physics system update; that is the state of touching colliders at that time. If you have just added a new Collider2D or have moved a Collider2D but a physics update has not yet taken place then the colliders will not be shown as touching. This function returns the same collision results as the physics collision or trigger callbacks.
EDIT 1:
You can also combine the previous code with: Physics2D.OverlapCollider
So you can do:
void OnTriggerStay2D(Collider2D other) {
if (collider1.IsTouching(other)) {
Collider2D[] results;
int elements = collider2.OverlapCollider(new ContactFilter2D, results);
if (elements > 0) {
// do some extra work with your result Collider2D array
// here
//
if (transform.position.y > 3) {
print("4");
Destroy(other.gameObject);
Destroy(gameObject);
circles.instantiator();
}
}
}
}

Unity3d - Jump in collision function

I want my character to jump only when he's standing on the ground. Despite I wrote the collision function he doesn't jump when I press the key. What is the problem?
void OnCollisionEnter2D(Collision2D col)
{
if (col.collider.tag == "groundTag")
{
if (Input.GetKeyDown(KeyCode.Space))
{
rb2d.AddForce(new Vector2(rb2d.velocity.x, Jumpforce));
}
}
OnCollisionEnter2D will only run when it collides with the ground(single frame). probably you need to create a bool for this condition. this may not be the best option. make it true when it collides with ground and make it false when it exits the ground. Write your code in the update function then.
bool _canJump;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
rb2d.AddForce(new Vector2(rb2d.velocity.x, Jumpforce));
}
}
void OnCollisionEnter2D(Collision2D col)
{
if (col.collider.tag == "groundTag")
{
_canJump = true;
}
}
void OnCollisionExit2D(Collision2D col)
{
if (col.collider.tag == "groundTag")
{
_canJump = true;
}
}
You are triggering your action only when you enter the ground trigger (the function you are implementing is OnCollisionEnter2D). Your function only works if you are pressing the space key on the same frame the collider collides with a groundTag object.
You could try with OnCollisionStay2D or use a CharacterController; that should make implementing the character a bit easier.

Can I have two colliders attached to my enemy that do different things and if so how?

Is it possible to have two colliders for one object?
My situation is that I have a CircleCollider2D that causes my enemy to chase the player when it enters. This works well but I want to also have a BoxCollider2D that will switch scene to my scene called "BattleScene" when the player enters.
I want it so that when my player enters the circle collider my enemy will follow him but when the player gets closer and enters the box collider (both attached to the enemy) it will switch scenes to the scene called "BattleScene".
Another alternative I thought of was using a rigid body collision but I don't know how to implement that.
Here is my code
private bool checkContact;
private bool checkTrigger;
public float MoveSpeed;
public Transform target;
public Animator anim;
public Rigidbody2D myRigidBody;
BoxCollider2D boxCollider;
public string levelToLoad;
// Start is called before the first frame update
void Start()
{
target = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();//getting the position of our player
anim = GetComponent<Animator>();
myRigidBody = GetComponent<Rigidbody2D>();
boxCollider = gameObject.GetComponent<BoxCollider2D>();
}
// Update is called once per frame
void Update()
{
if (checkTrigger == true)
{
transform.position = Vector2.MoveTowards(transform.position, target.position, MoveSpeed * Time.deltaTime); //move towrds from your position to the position of the player
if (myRigidBody.position.y < target.position.y && Mathf.Abs(target.position.y - myRigidBody.position.y) > Mathf.Abs(target.position.x - myRigidBody.position.x)) //if it is further away from target in x direction than y direction the animation for moving in y is loaded and vice versa
{
anim.SetFloat("MoveY", 1);
anim.SetFloat("MoveX", 0);
}
if (myRigidBody.position.y > target.position.y && Mathf.Abs(target.position.y - myRigidBody.position.y) > Mathf.Abs(target.position.x - myRigidBody.position.x))
{
anim.SetFloat("MoveY", -1);
anim.SetFloat("MoveX", 0);
}
if (myRigidBody.position.x > target.position.x && Mathf.Abs(target.position.y - myRigidBody.position.y) < Mathf.Abs(target.position.x - myRigidBody.position.x))
{
anim.SetFloat("MoveX", -1);
anim.SetFloat("MoveY", 0);
}
if (myRigidBody.position.x < target.position.x && Mathf.Abs(target.position.y -myRigidBody.position.y) < Mathf.Abs(target.position.x - myRigidBody.position.x))
{
anim.SetFloat("MoveX", 1);
anim.SetFloat("MoveY", 0);
}
anim.SetBool("checkTrigger", checkTrigger); //updating if in range
}
}
public void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.name == "Player")
{
checkTrigger = true; //setting our check trigger = true so it will follow if in radius
anim.SetBool("checkTrigger", checkTrigger);
}
}
public void OnTriggerExit2D(Collider2D other)
{
if (other.gameObject.name == "Player")
{
checkTrigger = false; //setting our check trigger = false so it will not follow if not in radius
anim.SetBool("checkTrigger", checkTrigger);
}
EDIT: THIS PROBLEM HAS BEEN RESOLVED
The best way to handle this is by having an empty GameObject with the other collider attached to it, while making sure both GameObjects have a Rigidbody - the child with IsKinematic ticked. Why? Because this will separate the child GameObject from the parent collision structure. Read more about compound colliders.
You should only have more than one collider in one GameObject if they all make part of the same collision structure. If they have different purposes, use different GameObjects with kinematic Rigidbodies, each handling it's own task.
In your specific scenario, I would have the CircleCollider in the enemy itself and the BoxCollider in a child GameObject with a kinematic Rigidbody. This child GameObject can also contain a script with the sole purpose of checking against the Player and loading the BattleScene.

GameObject colliding with Sprite?

So I have a sprite and it's name is "princess" and when a cube touches my sprite
I want the princess to be destroyed. I added a rigidbody, and a box collider, but for some reason the cube just goes through the princess sprite.
The cube is generated with code so it's name is "Cube" according to the hierachy so I wrote this code
private void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.name == "Cube")
{
Destroy(this.gameObject);
}
}
I think Destroy(this.gameObject) would destroy the princess, but they're not even colliding.
Any ideas?
Here is what the "game" looks like.
Game
Check if you checked the "is trigger" inside the box colliders.
You should use tag because if you spawn multiple cubes the will have names like "Cube (1)" and so on.
You need to use collider2d
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Cube")
{
Destroy(this.gameObject);
}
}
both of your object needs to have box collider2d and rigidbody2d and not set to "is trigger". example:
Destroy(this.gameObject) is working for own object where
collision.gameObject.setActive("False") is working for collide object
This code is working on my game. where "Player" is my Sprite tag. And make sure 'Is Trigger' is checked for your Cube
void OnTriggerEnter2D(Collider2D other) {
if (other.tag == "Player")
{
Destroy(gameObject);
}
}
OR alternatively in your case below code you could use in Cube script then might be work
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "princess")
{
collision.gameObject.setActive("False")
}
}

OnTriggerEnter not working

public var enemy:GameObject;
enemy = GameObject.FindGameObjectWithTag("enemy");
function OnTriggerEnter(other:Collider)
{
if(other.gameObject.tag == "enemy")
{
Debug.Log("Dead");
Destroy(gameObject);
}
}
This script is attached to a prefab arrow that gets instantiated. The enemy has a circle collider and the arrow has a box collider. The arrow has on IsTrigger checked. What have I done wrong? Both gameobjects have a rigidbobdy2D attached.
If you use the 2D physics engine, you need to use the 2D functions:
function OnTriggerEnter2D(other: Collider2D)
{
if(other.tag == "enemy")
{
Debug.Log("Dead");
Destroy(gameObject);
}
}