TriggerEnter is not working for && operator in unity 2D - c#

I have craete 2 ball sprite & one hole sprite, when this 2 ball sprite enters into the hole it need to load new scene.
im trying to find multi collision with AND operator but it's not working,if i try with one condition it workes fine, i don't know why.
void OnTriggerEnter2D(Collider2D col)
{
if ((col.gameObject.tag == "ball2") && (col.gameObject.tag == "ball")) {
Application.LoadLevel("Main");
}
}

Logistically, the code you've presented can never equate to true, because you're comparing the same string against two different values. If it returns false from the first test, it returns false. If it returns true from the first test, then it will always return false from the second, because the first evaluated it as being "ball2" - and thus it will return false.
If you're looking for it to return true if either (not both) side is true, use the or operator (condition1 || condition2)
void OnTriggerEnter2D(Collider2D col)
{
if ((col.gameObject.tag == "ball2")
|| (col.gameObject.tag == "ball"))
{
Application.LoadLevel("Main");
}
}
ps, yes, I like the Visual Studio code formatting, particularly for cases where conditional blocks are multiple lines
EDIT: Going by your comments, you're waiting to get two objects into the collision. In such a case, you cannot perform this AND test, because you're testing the same object since you only received the col parameter once. Because you get each collision as a discreet, separate event, you should instead set a flag per occurrence, and then advance when both flags have been set.
private bool ball = false;
private bool ball2 = false;
void OnTriggerEnter2D(Collider2D col)
{
// Set each flag individually to allow for separate events triggering each
if(col.gameObject.tag == "ball") ball = true;
if(col.gameObject.tag == "ball2") ball2 = true;
// Perform operation once both flags have been set
if(ball && ball2) Application.LoadLevel("Main");
}

Add two different collider with two different Gameobject and add two different collider script. Access one variable from other script if that's true then go on...
void OnTriggerEnter2D(Collider2D col) // Collider1 Script
{
if ((col.gameObject.tag == "ball2"))
{
firstcollider = true;
}
}
void OnTriggerEnter2D(Collider2D col) // Collider2 Script
{
if (Collider1.firstcollider == true ) && (col.gameObject.tag == "ball"))
{
Application.LoadLevel("Main");
}
}
Refer Google to access a variable from one script to another script if you dont know. I don't know this is the best way for code but just for crack....

Related

Unity Collide two same GameObjects with same scripts. OnCollisionEnter() executes twice (once on each script)

I have two exactly the same GameObjects colliding.
Both have script atached, in which I have OnCollisionEnter().
Context: two Armies of ships(single game object with script: ShipBehaviour) is fighting and one that have more ships inside lives, the other is destroys;
The problem is that OnCollisionEnter() being called twice (once on each GameObject),
therefore final calculating number(ShipsInside) is double than it should be.
OnCollisionEnter(Collision collision) method:
if(collision.gameObject.tag == "Ship")
{
var shipBehaviour = collision.gameObject.GetComponent<ShipBehaviour>();
if ( shipBehaviour != null )
{
if(shipBehaviour.ShipsInside > ShipsInside)
{
shipBehaviour.ShipsInside -= ShipsInside;
Destroy(gameObject);
}
else if(shipBehaviour.ShipsInside < ShipsInside)
{
ShipsInside -= shipBehaviour.ShipsInside;
Destroy(shipBehaviour.gameObject);
}
else if (shipBehaviour.ShipsInside == ShipsInside)
{
Destroy(gameObject);
Destroy(shipBehaviour.gameObject);
}
}
return;
}
So I want to execute OnCollisionEnter() logic in one GameObject and ignore it in other.
I have a solution: simly add in calculation division by 2. Than final number would be accurate. But obviosly it's not a right way to go about it.
Is there more afficient way to do so?
You don't actually need a flag for this.
Your battle outcomes are exactly symmetrical, meaning either one party is the winner.
So the simplest fix in my eyes would be to only let the winning (or alternately loosing) party handle the outcome of the battle and do e.g.
// Note that your tag check is actually redundant
// this would already be enough and you don't need to remember assigning tags
if(collision.gameObject.TryGetComponent<ShipBehaviour>(out var shipBehaviour))
{
if(shipBehaviour.ShipsInside < ShipsInside)
{
ShipsInside -= shipBehaviour.ShipsInside;
Destroy(shipBehaviour.gameObject);
}
else if (shipBehaviour.ShipsInside == ShipsInside)
{
Destroy(shipBehaviour.gameObject);
}
}
This should be enough then since the other collision party already handles the other cases on their side anyway.
You could of course as well turn it the other way round and handle your own loosing case. The same way you might prefer rather only destroying yourself in the == case.
If you don't care about the one redundant subtraction (since the object is destroyed anyway) you could even as well shorten it down to
if(collision.gameObject.TryGetComponent<ShipBehaviour>(out var shipBehaviour))
{
if(shipBehaviour.ShipsInside <= ShipsInside)
{
ShipsInside -= shipBehaviour.ShipsInside;
Destroy(shipBehaviour.gameObject);
}
}
You can simply add a flag to solve this.
private bool _collisionHandled = false;
private void OnCollisionEnter(Collision collision)
{
if (_collisionHandled || collision.gameObject.tag != "Ship")
{
return;
}
var shipBehaviour = collision.gameObject.GetComponent<ShipBehaviour>();
if (shipBehaviour != null)
{
if (shipBehaviour.ShipsInside > ShipsInside)
{
shipBehaviour._collisionHandled = true;
shipBehaviour.ShipsInside -= ShipsInside;
Destroy(gameObject);
}
else if (shipBehaviour.ShipsInside < ShipsInside)
{
_collisionHandled = true;
ShipsInside -= shipBehaviour.ShipsInside;
Destroy(shipBehaviour.gameObject);
}
else if (shipBehaviour.ShipsInside == ShipsInside)
{
_collisionHandled = true;
shipBehaviour._collisionHandled = true;
Destroy(gameObject);
Destroy(shipBehaviour.gameObject);
}
}
}

Multiple triggers in Unity

Reference image
I have a certain object in my game and I'm trying to see whether the object triggers multiple triggers. I tried with the code bellow but for some reason it doesn't work.
void OnTriggerEnter2D(Collider2D col)
{
if (col.tag == "speed")
{
//do something
}
else if (col.tag == "speed" && col.tag == "point")
{
//do something
}
}
How can I recognize if the object only hit "Col1" or "Col1" and "Col2"
OnTriggerEnter is only called when your object is colliding with one specific trigger. Thus, the tag of the collider (col) can't be speed and point at the same time.
You have to track if the object is colliding with your triggers using a boolean variable for example :
private bool collidingWithSpeed;
private bool collidingWithPoint;
void OnTriggerEnter2D(Collider2D col)
{
if (col.CompareTag("speed"))
{
collidingWithSpeed = true ;
//do something
}
else if (col.CompareTag("point"))
{
collidingWithPoint = true ;
//do something
}
if( collidingWithSpeed && collidingWithPoint )
{
// Do something when your object collided with both triggers
}
}
// Don't forget to set the variables to false when your object exits the triggers!
void OnTriggerExit2D(Collider2D col)
{
if (col.CompareTag("speed"))
{
collidingWithSpeed = false;
}
else if (col.CompareTag("point"))
{
collidingWithPoint = false;
}
}
While #Hellium's answer would work perfectly, I personally prefer using a list to store all my colliding objects (or at least some of them). Like so
private readonly List<string> collidingTags = new List<string>();
void OnTriggerEnter2D(Collider2D collider)
{
//Add some kind of filter or safety check if needed
collidingTags.Add(collider.tag);
}
void OnTriggerExit2D(Collider2D collider)
{
//Add some kind of safety check if needed
collidingTags.Remove(collider.tag);
}
In theory, this is far less efficient in terms of performances (compared to storing a bool) but stills, it adds a nice layer of flexibility.
In practice, the difference in performances is incredibly small so you decide!

Play audio once when two identical objects collide [duplicate]

I have an object that moves towards another object and physically collides with it, I want that collision/colliding event to happen only once. I tried using a bool but it didn't work as intended. It seems that I'm doing something wrong.
bool doDamage = true;
void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.tag == "Target" && doDamage)
{
doDamage = false;
// damage code
}
}
void OnCollisionExit2D(Collision2D other)
{
if (other.gameObject.tag == "Target")
{
doDamage = true;
}
}
Edit:
I want the "damage code" to run only once, even if the 2 objects are still in contact. This script is only assigned to 1 object, not both.
I don't know the easiest way to explain why your code is not working but I will try.
You have two GameObjects:
GameObject A with doDamage variable.
GameObject B with doDamage variable.
When GameObject A collides with GameObject B:
A.The OnCollisionEnter2D function is called on GameObject A.
if(other.gameObject.tag == "Target" && doDamage) executes because doDamage is true.
B.The doDamage variable from GameObject A is then set to false.
This does not affect the doDamage variable from GameObject B.
Then
C.The OnCollisionEnter2D function is called on GameObject B.
if(other.gameObject.tag == "Target" && doDamage) executes because doDamage is true.
D.The doDamage variable from GameObject B is then set to false.
Both your damage code will run because doDamage is always true in each OnCollisionEnter2D call. What you are currently doing is only affecting doDamage variable in each individual script.
What you are currently doing:
Setting doDamage in the local/this script to false while also checking if local/this doDamage is set or not.
What you need to do:
Set doDamage in the other script to false but read the local/this doDamage to check if it is set or not.
This is what it should look like:
public class DamageStatus : MonoBehaviour
{
bool detectedBefore = false;
void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("Target"))
{
//Exit if we have already done some damage
if (detectedBefore)
{
return;
}
//Set the other detectedBefore variable to true
DamageStatus dmStat = other.gameObject.GetComponent<DamageStatus>();
if (dmStat)
{
dmStat.detectedBefore = true;
}
// Put damage/or code to run once below
}
}
void OnCollisionExit2D(Collision2D other)
{
if (other.gameObject.tag == "Target")
{
//Reset on exit?
detectedBefore = false;
}
}
}
If you want to run a snippet of code once, run the code directly in the callback event that you want to trigger your code.
void OnCollisionEnter2D(Collision2D other)
{
DoSomeDamageTo(other.gameObject);
}
This should only trigger once upon collision.
If you want this to only ever happen once (e.g. if the object holding the script were to hit something again), you'll need a flag to say that the damage has already been done:
bool hasHitSomething = false;
void OnCollisionEnter2D(Collision2D other)
{
if (!hasHitSomething)
{
DoSomeDamageTo(other.gameObject);
hasHitSomething = true;
}
}
I suspect given the code you've shared, that either the objects are colliding multiple times in engine (very possible if they're solid and physics-controlled), leading to OnCollisionEnter being called multiple times. OnCollisionEnter should only be called once per collision. If you are observing it being called multiple times, either you are actually observing multiple collisions, or you've found an obscure Unity bug. The former is much, much more likely.

OnCollisionStay at a time Collision detection for two plane in C# unity?

I am a beginner and working in Stacker game and there are multiple planes, but one of them is true and other is false. Now my problem is that, sometimes stacker stops at two plane simultaneously and both function gets called on 'is game over' and other 'go to next level'. Tell me how can I compare two tags, that if both true then do something. thanks here is my code.
void OnCollisionStay(Collision collision) {
if (collision.collider.tag == "plane1") {
if (script2.rb.velocity.magnitude == 0.0f) {
collision.collider.gameObject.GetComponent<Renderer> ().material.mainTexture = color1;
cont++;
SetCountText ();
script1.jump1 ();
StartCoroutine (wait ());
}
} else if (collision.collider.tag == "plane2") {
if (script2.rb.velocity.magnitude == 0.0f) {
script.jump ();
Time.timeScale = 0;
}
else {
if (script2.rb.velocity.magnitude == 0.0f) {
script.jump ();
Time.timeScale = 0;
}
}
}
if (collision.collider.tag == "plane1" && collision.collider.tag == "plane2") {
script.jump ();
Time.timeScale = 0;
Debug.Log("hello");
}
Your code doesn't entirely match your question, but I gather that the problem is that both the "win" and "lose" condition are triggered by physics, and both are happening in the same frame?
The most straightforward way to handle that is to have a bool (or better, an enum) to store the state of your game--if the level is over, the collision functions shouldn't do anything. It does seem like there should be a pretty, elegant way to solve this, but I'm not aware of one. Disabling the colliders probably won't work, since both collisions have already occurred by the time your physics callback functions are called.

Trigger's not responding how I want in unity 3d

I need help with a game I am creating. I am building the game with the Unity engine and am pretty new to C# coding. I am creating a 2d game where the player controls the color of a square and must change it to the correct color as when it passes a certain colored object. The player changes colors great and the objects are triggers. When a player passes the trigger if its not the right color the player dies. Well that works perfect but only for the first object the next one no matter the color of the player the object dies. I have tried if's in if statements and else if's I can't seem to figure it out. Your help would be greatly appreciated!
Here is the code for the player
void OnTriggerEnter (Collider other)
{
if (other.transform.tag == "Blue") {
blue = true;
}
else {
blue=false;
}
if (other.transform.tag == "Red") {
red = true;
}
else {
red =false;
}
if (other.transform.tag == "Blue" && GameObject.Find ("Blue").GetComponent<Blue> ().mb == false) {
yield return 0;
Die ();
} else if (other.transform.tag == "Red" && GameObject.Find ("Red").GetComponent<Red> ().mr == false) {
Die ();
}
}
Here is the code for each different colored object. This one happens to be blue.
void Update () {
if (GameObject.Find ("Player").GetComponent<Movement> ().blue == true && GameObject.Find ("Player").GetComponent<Movement> ().playerBlue == true) {
mb = true;
} else {
mb = false;
}
if (!GameObject.Find("Player").GetComponent<Movement>().blue) {
mb = false;
}
}
Your execution order is a little messy, that's probably why it's not working. Try to make all your logic follow one path, not two. Right now, you are:
(1)Colliding, (2) setting some boolean variables, (3)checking some variables, (4)optionally dying.
At a separate time in a separate class, set the boolean that was set in step 1 and setting the variable that's checked in step 3
This is what we call spaghetti code. It's all twisted together. Can you think of a way to untangle it, so the two bits of logic don't mutually depend on each other?
For example, I see in the latter block of code, you're checking whether the player is blue. Could you instead run that code when the player sets blue (or sets blue=false)?
Edit: I know this isn't strictly answering your question, but this untangling is the first step of the problem solving process.

Categories