The question is answered, right answer was accepted
OverlapSphere Problem.
Namaste Developers. _/\
My game has a theme of 'Survival Shooter'. Every Enemy has 2 different colliders (Capsule Collider & Sphere Collider). Now, when I use Physics.OverlapSphere for the explosion or making a Tornado Effect, the enemy got killed but it is counting the Enemy DeathCount twice (1 Enemy Killed = 2 Enemy Death Count & Score Value = 20). It is so because I have 2 different colliders on enemy gameObject. When I turn off Sphere Collider then it is counting the death count and Scores normally i.e., 1 enemy killed = 1 enemy deathcount and Score value = 10. My Sphere Collider is a Triggered Collider and my Tornado also has a Sphere collider which is a Triggered too. My Tornado has a script. Below is my code.
private void OnTriggerStay(Collider other)
{
colliders = Physics.OverlapSphere(transform.position, Radius, CollidingLayerMask, QueryTriggerInteraction.Ignore);
foreach (Collider Hit in colliders)
{
Rigidbody RB = Hit.GetComponent<Rigidbody>();
if (RB != null)
{
RB.AddExplosionForce(Power, transform.position, Radius, 5.0f, ForceMode.Acceleration);
}
if ((RB != null) && (Hit.gameObject.tag == "Enemies" || Hit.gameObject.tag == "Birds"
|| Hit.gameObject.tag == "DYZ" || Hit.gameObject.tag == "Ghost" || Hit.gameObject.tag == "RBOSS"
|| Hit.gameObject.tag == "YBOSS" || Hit.gameObject.tag == "SBOSS"))
{
Hit.GetComponent<NavMeshAgent>().enabled = false;
RB.constraints &= ~RigidbodyConstraints.FreezePositionY;
Instantiate(TornadoDeathFx, onePosition.position, onePosition.rotation);
Instantiate(CoinPrefab, onePosition.position, CoinPrefab.transform.rotation);
RB.AddExplosionForce(Power, transform.position, Radius, 5.0f, ForceMode.Impulse);
EH = Hit.GetComponent<EnemyHealth>();
EH.TakeDamageFromTornado(100);
}
}
}
It's been so long I am suffering from this problem. I am frustrated and I am loosing my edge. The edge which strikes fuel for the 'Game Development'.
Any Help will be heartily appreciated.
Answer by Adam-Buckner · Jul 20, 2017 at 10:24 PM
Ok...
Let's step thru this in order.
We know there are two colliders per enemy. We know you are counting both colliders, so you are getting twice the score you should with your code. We need to find a way that we only count one of the two colliders on the enemies.
One solution would be to create a "death limit" in the script controlling the death of the enemy. You could have:
foreach (Collider collider in colliders)
{
var enemyController = collider.GetComponent<MyScript>();
myScript.Die();
}
And then in whatever is controlling your Enemy Death Script:
private bool isDead;
and when you call Die(), you set the flag to true;
public void Die()
{
if (!isDead)
{
// apply visual effects and count points here
isDead = true;
}
}
So, this will only count points on each object once no matter how many times "Die()" is called.
Another way to do this is to isolate which collider you are testing. We can do this by trying to cast the Collider to a SphereCollider. Only the SphereColliders will be successfully cast from Collider, so you can check to see if they are null, and only proceed if they are not.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestScript : MonoBehaviour {
public float radius;
public LayerMask mask;
public QueryTriggerInteraction query;
private int i;
private void Start ()
{
TestCollider();
}
private void TestCollider ()
{
Collider[] colliders = Physics.OverlapSphere(transform.position, radius, mask, query);
foreach (Collider collider in colliders)
{
SphereCollider sc = collider as SphereCollider;
if (sc != null)
{
// apply visual effects and count points here
// i++;
// Debug.Log("Sphere: " + i);
}
}
}
}
Does this help?
Hello Sir, @Adam-Buckner Thank You So $$anonymous$$uch. You really helped me. I owe you one. The 1st option is working 100% like a charm :-) . The 2nd option, I'm struggling getting it. When we are casting 'collider' as SphereCollider to 'sc'. It means we are casting both SphereCollider & Capsule Collider that is attached to the enemy due to 'foreach' statement. As Physics.OverlapSphere() statement returning all the Colliders that are being hit by it and we are using those colliders in 'foreach' statement and it is still counting it twice because we are casting those two colliders.
Anyway, 1st Option is working correctly. Thank You So much for your help. Now I am getting my edge back. :-)
$$anonymous$$y best wishes to you!
The point to casting the Collider to SphereCollider is that you then must only use the Colliders that are successfully cast to SphereCollider and ignore all the rest. Note how, in my example code, I only "do" something if "sc != null". This code is iterating over all of the colliders and trying to cast Collider to SphereCollider. If the cast is successful and sc != null, then we are doing something. You must have that second if.
Now, if it were me, I'd just use option 1 as it's fairly simple. I included the casting as an example of how you'd get just the one type of collider from a group of colliders.
Please note that I've updated the code example above to reflects exactly where you should apply visual effects and count points.
This method of casting will only work in your exact setup as you know you have two colliders per enemy and one is a capsule collider and one is a sphere collider, so by picking out the sphere colliders, you get only one collider per enemy.
Okay! I understand but still it is counting it twice. I am wondering What condition I can put in the 'Second if'.? By the way, I can use option 1 without having any problem. The only thing which will perpetuate in my $$anonymous$$d is that I couldn't resolved this collider conflict. Anyway, you helped me a lot. Thank You so much for that. I am glad I had a great discussion with @Adam-Buckner
Can you post your code here? The code where you're still getting the double count?
If you can, I'll have a look and see where you're going off the rails.
Hello Sir @Adam-Buckner Here is the code of Tornado SphereCollider.
private void OnTriggerEnter(Collider other)
{
colliders = Physics.OverlapSphere(transform.position, Radius, CollidingLayer$$anonymous$$ask);
foreach (Collider Hit in colliders)
{
/*Here I am casting Enemy's Capsule Collider because Enemy's Sphere Collider is a Triggered,
and my tornado also has a Sphere triggered collider.
That is why two triggered collider are not detecting collision and nothing happens. So I used Capsule one.
This code is attached to tornado's sphere collider. As it collides with Enemy's Capsule Collider,
this OnTriggerEnter() function is getting called. */
CapsuleCollider SC = Hit as CapsuleCollider;
if (SC != null)
{
// Here I put visual effects and Coin Prefab.
Instantiate(TornadoDeathFx, onePosition.position, onePosition.rotation);
Instantiate(CoinPrefab, onePosition.position, CoinPrefab.transform.rotation);
//Here I am setting reference to EnemyHealth Script and Calling TakeDamageFromTornado() Function..
EH = SC.GetComponent<EnemyHealth>();
EH.TakeDamageFromTornado(100);
i++;
Debug.Log("Sphere : " + i);
}
}
}
And here is the code of EnemyHealthScript from where I am counting the EnemyDeath & Score Value.
public void TakeDamageFromTornado(int Amount)
{
currentHealth -= Amount;
if (currentHealth <= 0)
{
//Destroying Enemy GameObject here..
Destroy(gameObject);
//Counting Enemy Death count & printing it on console..
enemyDeathCount += 1;
print(enemyDeathCount);
/*Passing Score Value to Score$$anonymous$$anager Script as demonstrated in 'Survival Shooter' tutorials*/
Score$$anonymous$$anager.score += scoreValue;
}
}
Here are two Images of Editor & Play $$anonymous$$ode. You can see my Tornado's Sphere Collider.
You can see clearly, I just killed 2 enemies and got 2 coins but Score Value is 40. Ins$$anonymous$$d of 20 and also Enemy Death Count on the left, it must be 2 but it is 4.
A couple of things here:
One is that you can choose to ignore triggered colliders:
https://docs.unity3d.com/ScriptReference/Physics.SphereCast.html
"queryTriggerInteraction Specifies whether this query should hit Triggers."
The images didn't load for me, so I'll have to take your word for it.
The Score seems to be associated with the TakeDamageFromTornado function. You are also keeping track of enemy death count here... Does the enemy death count seem correct? Or is it double as well?
I do have a question... why is the function TakeDamage FromTornado not just TakeDamage? Is there a difference between tornado damage and any other damage?
Now, getting the cast to work can just be a good exercise in solving problems.
If the original solution (the isDead bool) works, you can simply use that and move on.
Yes Sir @Adam-Buckner , it is much efficient than being trapped in Collider Conflicts. I would like to continue with that. A big Thanks from me. :-) And one more thing, SIr! please don't $$anonymous$$d if I need your further assistance. I will post question here and I will inform you and whenever you'll get time, kindly make sure to retaliate on my problems. I've learned a lot from your tutorials. Thanks!