unity physic.OverlapSphere as trigger - unity3d

I wanna make sphere collision as trigger everytime player shoot by physics.overlapsphere. but it seems like it only create make collision which is not trigger. so how can i solve this?
Collider[] cs = Physics.OverlapSphere(transform.position, redi);
foreach (Collider c in cs)
{
Rigidbody r = c.gameObject.GetComponent<Rigidbody>();
if (r != null)
{
r.AddExplosionForce(power, transform.position, redi);
}
if (c.gameObject.tag == "enemy")
{
Destroy(c.gameObject);
}
if (c.gameObject.tag == "player")
{
c.gameObject.GetComponent<movee>().health -= 5;
}
}

Physics queries rely on Physics.queriesHitTriggers property which defines, if certain calls hit trigger colliders or not (see https://docs.unity3d.com/ScriptReference/QueryTriggerInteraction.html).
You can set QueryTriggerInteraction for your OverlapSphere call as a method parameter. If you do not do so, it uses the global setting, which might be set to ignore triggers in your case.
Proper method call:
Collider[] hitColliders = Physics.OverlapSphere(position, range, layerMaskSphere, QueryTriggerInteraction.Collide);

Related

Force occasionally being applied twice with OnCollisionEnter

I am creating a first person rocket jumping game, with the premise of shooting a rocket launcher at the players feet to move around.
I am having problems with my OnCollisionEnter function which stores all colliders in a radius and applies explosion force to them. When the player is completely on top of the explosion, force is being applied twice. Here is the code:
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Player")
{
}
else
{
GetComponent<AudioSource>().Stop();
Instantiate(explosionPrefab, transform.position, transform.rotation);
Vector3 explosionPos = transform.position;
//Use overlapshere to check for nearby colliders
Collider[] collidersToDestroy = Physics.OverlapSphere(explosionPos, radius);
foreach (Collider hit in collidersToDestroy)
{
//searches for what needs to be destroyed before applying force, this is for destructable objects
Destructible dest = hit.GetComponent<Destructible>();
if (dest != null)
{
dest.DestroyWall();
}
ExplosiveBarrel barrel = hit.GetComponent<ExplosiveBarrel>();
if (barrel != null)
{
barrel.BarrelExplode();
}
}
Collider[] collidersToMove = Physics.OverlapSphere(explosionPos, radius);
foreach (Collider hit in collidersToMove)
{
Rigidbody rb = hit.GetComponent<Rigidbody>();
//Add force to nearby rigidbodies
if (rb != null)
{
rb.AddExplosionForce(power * 5, explosionPos, radius, 3.0F);
if (hit.gameObject.tag == "Player")
{
//if player is hit
UnityEngine.Debug.Log("Hit");
}
}
Destroy(gameObject);
}
}
}
I can tell the force is being applied twice to the player by using UnityEngine.Debug.Log("Hit"); , which appears twice in the console. Furthermore, I am pretty sure this is happening on the same frame, as putting Destroy(gameObject); within the if (player hit) statement yields the same results.
This only occurs when the player is right next to the explosion, if the player is a small distance away the force is only applied once. I would very much like to solve this problem and have the force only applied once.
All help is greatly appreciated, thank you in advance.
I solved it!
OnCollisionEnter was being called twice because I had two colliders perfectly stacked on one another, so the projectile was hitting the 2 colliders on the same time step.

Prevent Collision Forces in Unity Physics in Collision Callback

How do I prevent a collision from applying forces in Unity? I am using 2D physics and want an arrow to stick into a crate. I can easily remove the rigid body and collider in the collision callback, but it seems that a frame of collision force is still applied to the arrow, causing slight jumps in position and rotation. Settings isKinematic on the rigid bodies in the collision callback also appears to not prevent this one frame of force being applied.
I am hoping to tell Unity to not apply physics for the collision.
Using kinematic for the life time of the arrow is not an option because the arrow needs to fly realistically until it hits something.
Here is the code for the crate object that handles the collision:
protected virtual void HandleCollision(ArrowScript arrow, Collision2D coll)
{
StickArrow(arrow, coll);
if (DestroyAfterSeconds >= 0.0f)
{
Destroy(arrow.gameObject, DestroyAfterSeconds);
}
}
private void OnCollisionEnter2D(Collision2D coll)
{
ArrowScript script = coll.gameObject.GetComponent<ArrowScript>();
if (script != null)
{
HandleCollision(script, coll);
}
}
private bool StickArrow(ArrowScript arrow, Collision2D coll)
{
Vector2 surfaceNormal = coll.contacts[0].normal;
float surfaceAngle = Mathf.Atan2(surfaceNormal.y, surfaceNormal.x);
float arrowAngle = Mathf.PI + (arrow.transform.eulerAngles.z * Mathf.Deg2Rad);
float angleDifference = Mathf.Abs(BowAndArrowUtilities.DifferenceBetweenAngles(surfaceAngle, arrowAngle));
float penetration = arrow.PercentPenetration * PenetrationPercentageModifier * (1.0f - angleDifference);
if (penetration <= MinimumPenetrationPercentage)
{
arrow.PercentPenetration = 0.0f;
return false;
}
// Make the arrow a child of the thing it's stuck to
arrow.transform.parent = transform;
arrow.gameObject.transform.Translate(new Vector3(-penetration * arrow.Length, 0.0f, 0.0f));
SpriteRenderer thisSpriteRenderer = GetComponent<SpriteRenderer>();
if (thisSpriteRenderer != null)
{
arrow.GetComponent<SpriteRenderer>().sortingLayerID = thisSpriteRenderer.sortingLayerID;
arrow.GetComponent<SpriteRenderer>().sortingOrder = Mathf.Max(0, thisSpriteRenderer.sortingOrder - 1);
}
BowAndArrowUtilities.PlayRandomSound(arrow.CollisionAudioClips, penetration * 5.0f);
// destroy physics objects from the arrow (rigid bodies, colliders, etc.). This unfortunately doesn't prevent this frame from apply force (rotation, position) to the arrow.
arrow.DestroyPhysicsObjects();
return true;
}
Unity version is 5.3.4.
I ended up making the arrow head a trigger. Inside of OnTriggerEnter2D, I then perform a circle cast in the direction the arrow is pointing with a width of the arrow head sprite. Triggers do not get affected by Unity physics calculations.
private void OnTriggerEnter2D(Collider2D coll)
{
ArrowScript script = coll.gameObject.GetComponent<ArrowScript>();
if (script != null)
{
Vector2 dir = -script.ArrowHead.transform.right;
// ray cast with the arrow size y value (thickness of arrow)
RaycastHit2D[] hits = Physics2D.CircleCastAll(script.ArrowHead.transform.position, script.Size.y, dir);
foreach (RaycastHit2D hit in hits)
{
// collider2d is a member variable assigned in Start that is the Collider2D for this object
if (hit.collider == collider2d)
{
HandleCollision(script, hit.normal);
break;
}
}
}
}
Your problem is that OnCollisionEnter and OnTriggerEnter are called after all the collisions are resolved.
The simplest way to solve this without affecting anything would be to change the weight of the box, arrow, or both.
Set the weight of the crate to a high value, and the weight of the arrow to a low value.
Another way is to use trigger colliders, as you have done. However trigger colliders have problematic side-effects. For example, it doesn't call OnCollisionEnter or OnTriggerEnter on the crate. You will have to do all the logic inside the arrow script, which is not much of a problem.
There are a lot of other ugly hacks however. You could set the velocity of the box to 0 after impact, but it would freeze the crate if you hit it as it was moving. You could use the collision information to cancel the force applied to the crate to solve the collision. You could save the last velocity of the crate every frame, and reapply it to the rigid body during the OnCollision call.
I wouldn't suggest any of these, but they are possible.

Colliding objects bouncing off when isTrigger is true instead of passing through

I have looped through some game objects to set the isTrigger property before a certain collision occurs but though the property is true collision with the object still occurs. Please see the relevant code below:
void OnCollisionEnter2D(Collision2D col) {
if (col.gameObject.tag == "object1") {
for (int i = 0; i < badGuys.Count; i++) {
badGuys[i].getBadGuyGameObject().GetComponent<Collider2D>().isTrigger = true;
}
}
else if (col.gameObject.tag == "object2") {
// collision with object1 always occurs before object2, though isTrigger is true the colliding object doesn't pass through the badGuys game objects, it bounces off on collision
}
else if (col.gameObject.tag == "object3") {
for (int i = 0; i < badGuys.Count; i++) {
badGuys[i].getBadGuyGameObject().GetComponent<Collider2D>().isTrigger = false;
}
}
else if (col.gameObject.tag == "badGuy") {
}
}
collision with object1 always occurs before object2, though isTrigger is true the colliding object doesn't pass through the badGuys game objects, it bounces off on collision. How can I solve this?
UPDATE 1
I just realized that the isTrigger value is true or false in the inspector depending on the time I stop the game. For example if I stop the game after Object1 collision the isTrigger is true and when I stop the game after collision with object3 it false. This inconsistency makes debugging very cumbersome. Is this a bug or something?
UPDATE 2
Based on recommendation from Joe Blow and Agustin0987 I used the enabled property of Collider2D instead of isTrigger. I also removed virtually all the code in OnCollisionEnter2D to get a simple test scenario. Please see code below:
void OnCollisionEnter2D(Collision2D col) {
if (col.gameObject.tag == "object1") {
if (badGuys[4].getBadGuyGameObject().GetComponent<Collider2D>().enabled = false) {
badGuys[4].getBadGuyGameObject().GetComponent<Collider2D>().enabled = true;
Debug.Log ("CHANGED TO TRUE");
Debug.Log ("bad guy collider enabled is " + badGuys[4].getBadGuyGameObject().GetComponent<Collider2D>().enabled);
}
else if (badGuys[4].getBadGuyGameObject().GetComponent<Collider2D>().enabled = true) {
badGuys[4].getBadGuyGameObject().GetComponent<Collider2D>().enabled = false;
Debug.Log ("CHANGED TO FALSE");
Debug.Log ("bad guy collider enabled is " + badGuys[4].getBadGuyGameObject().GetComponent<Collider2D>().enabled);
}
}
else if (col.gameObject.tag == "badGuy") {
Debug.Log("collided with bad guy"); // DOESN'T OCCUR
}
}
Instead of looping through this time, I decided to test for one. The else if is where enabled is true always satisfied though the Log prints false and the if where enabled is false is never satisfied. In the inspector, the Box Collider2D for bad guys is always unchecked. Collision with the badGuy never occurs. Based on my simple scenario code I thought it should be working.
Never, ever ever
I mean absolutely never
use "else if".
Simply, never, ever - ever - type "else if" for the rest of your life, until you die.
In the first instance, delete all your code and replace it with this:
void OnCollisionEnter2D(Collision2D col)
{
Debug.Log("We will deal with this ......... " +col.gameObject.name);
if (col.gameObject.tag == "object1")
{
Debug.Log("\t handling 'object' type issue");
HandleObjectIssue(col)
return; //NOTE HERE
}
if (col.gameObject.tag == "object1")
{
Debug.Log("\t handling 'bad guy' type issue");
HandleBadGuyIssue(col)
return; //NOTE HERE
}
}
private void HandleObjectIssue(Collision2D col)
{
Debug.Log("'\t\t object', I'm dealing with this .. " +col.gameObject.name);
}
private void HandleBadGuyIssue(Collision2D col)
{
Debug.Log("\t\t 'badguy', I'm dealing with this .. " +col.gameObject.name);
}
Run that extensively and "unit test" it. If you like, convert back (USING THAT CODE) to a "loop" method to look at all items. In any event, test that extensively.
--
Secondly, add this routine ..
private void ToggleColliderOnGameObject( GameObject gg )
{
Debug.Log("I'm supposed to toggle the collider on: " +gg.name);
Collider2D { or whatever } col = gg.GetComponent<Collider2D>();
bool currentState = GetComponent<Collider2D>().enabled;
Debug.Log("\t it is currently: " +currentState);
bool newState = ! currentState;
col.enabled = newState;
Debug.Log("\t\t but now it is: " +newState);
}
... and start unit testing with it. So you will have code like:
ToggleColliderOnGameObject( badGuys[4].getBadGuyGameObject() );
For example, try some things like this:
void Start()
{
InvokeRepeating("teste", 1f, 1f);
}
private void Teste()
{
ToggleColliderOnGameObject( badGuys[4].getBadGuyGameObject() );
}
After experimenting with that for some time and unit testing, you will be able to move on.
Note that apart from other problems, it is likely that (for example) your routine "getBadGuyGameObject" is returning the wrong thing - or some similar problem.
EDIT:
Remove badGuy = badGuyPrefab; from your public void createBadGuy(GameObject badGuyPrefab, BadGuyType badGuyType, Vector3 badGuyPosition) function. This was a mistake in Programmer's code from the link in your comment.
It seems like you are trying to enable/detect the collision between badGuys and object2 only if object1 collides with whatever object has this script attached (seems to be some kind of BadGuyManager). So I would recommend that instead of setting isTrigger to true or false, you should try to enable or disable the whole `Collider2D.
P.S: I agree with Joe Blow in that you should explain what are you trying to achieve.

Compare tags in UnityScript

We are building a 3D game and right now I am stuck on an issue where I need to compare multiple tags to activate or deactivate a trigger that sends the player back to the respawn position.
This is currently the code:
#pragma strict
var spawnPoint : GameObject;
function OnTriggerStay ( other : Collider )
{
if (other.tag == "Player" && other.tag != "Ball")
{
other.tag == "Player";
other.gameObject.transform.position = spawnPoint.transform.position;
}
else if ( other.tag == "Ball" && other.tag == "Player" )
{
}
}
I am uncertain how to fix this to do the following:
If the player touches the trigger without there being a ball colliding with it, the player respawns. This is to create the feeling that the particles kill you.
If the player touches the trigger when there is a ball colliding with it as well, nothing happens to the player and so the player can freely pass through.
What we want to do is that we want to push a ball over a geyser so it covers it and if the geyser is not covered and the player tries to pass over it, the player respawns.
We also tried with another code and while it allows the ball to pass, it does not allow the player to do so. Even after the ball has been placed.
#pragma strict
var spawnPoint : GameObject;
function OnTriggerStay ( other : Collider )
{
if (other.tag == "Ball")
{
other.enabled = false;
}
else if (other.tag == "Player")
{
other.gameObject.transform.position = spawnPoint.transform.position;
}
}
So, I believe your problem is, when you use that function, you are only checking the first collision. So whats happening is your getting a value of either the player or the ball, not both. You need to store all the collision so you can compare all of them. To do that you can follow the generals of this documentation. http://docs.unity3d.com/ScriptReference/Collision-contacts.html
It's talking about collisions, but the same general principle should apply.
Hope this helps!

Falling Platform using rigidbody

I have a platform that i want to fall once the player has stepped on it. It has two box colliders. One for it's physical being and the other as a trigger. It also has a rigidbody which is kinematic by default so it doesn't fall straight away. However when the player steps on it it does nothing. Can any one tell me what's wrong with my code?
var yourObject : GameObject;
function OnTriggerEnter(Other : Collider){
if(Other.gameObject.tag == "Player"){
yourObject.rigidbody2D.isKinematic = false;
}
}
Plase check your gameobjects tag.
and also i see you use Rigidbody2D so you don't add below
var yourObject : GameObject;
function OnTriggerEnter(Other : Collider){
if(Other.gameObject.tag == "Player"){
yourObject.rigidbody2D.isKinematic = false;
}
}
You need to use this
function OnTriggerEnter2D(other: Collider2D) {
if(other.gameObject.tag == "Player"){
yourObject.rigidbody2D.isKinematic = false;
}
}
And also please check you add tag to gameobjects (I think you mean check names)
Like
function OnTriggerEnter2D(other: Collider2D) {
if(other.gameObject.name == "Player"){ //check name
yourObject.rigidbody2D.isKinematic = false;
}
}
To achieve a falling platform of sorts you do not have to make use of the IsKinematic function.
Instead, you can just turn off the Use Gravity function. This will prevent the object from falling, until another object with a rigidbody and a mass bigger then the mass of the platform touches it. As can be seen in the GIF below.