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.
Related
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);
This is my error code :
Assets/Scripts/PlayerDamage.cs(166,35): warning CS0219: The variable `hitCol' is assigned but its value is never used
I'm just not sure why it's not working properly. I thought I was using it in the input function under attackVKC. I should mention this is for a multiplayer game in unity.
Basically damage is getting done to the player casting the attack and not to the other players. I'm trying to get an aoe (area of effect) attack.
private Collider[] hitColliders;
else if (Input.GetButton ("Special") && (Input.GetButtonDown ("Fire2") && offcd == true && offccd == true)) {
attackVKC();
StartCoroutine("GlobalCooldown");
StartCoroutine("GlobalCCooldown");
}
[Client]
void attackVKC(){
hitColliders = Physics.OverlapSphere (transform.position, special.rangeVKC, mask);
{
if (GetComponent<Collider>().tag == PLAYER_TAG)
{
CmdPlayerHit(GetComponent<Collider>().name, special.damageVKC);
}
}
Debug.LogError (GetComponent<Collider>().name);
}
I actually sloved this. I wasn't looping through the array and I didn't realise getcomponent was for the gameobject attached. So that's why it was hitting the player using the attack and not other players.
I have a enemy AI script and a small part of the code isn't working. It's supposed to search for a game object with the Player tag when the target no longer exists. So, when the player collects a power up and a new player prefab spawns in its place it will search. However, it is not finding one and I don't know why.
Here is the part of the code that doesn't work:
IEnumerator SearchForPlayer (){
GameObject sResult = GameObject.FindGameObjectWithTag ("Player");
if (sResult = null) {
yield return new WaitForSeconds (0.5f);
StartCoroutine (SearchForPlayer ());
}
else {
target = sResult.transform;
searchingForPlayer = false;
StartCoroutine (UpdatePath());
return false;
}
}
I know that my prefab has got the correct tag and that it is definitely getting to that part of the script. Does any one have any ideas why it's not working?
if (sResult = null) {
Should be
if (sResult == null) {
Single = is an assignment operator so you are setting the result to null instead of checking if it is null.
Please Guys help, I am new to Unity and programming:
I have a two Bouncing Ball, tag as BouncingBall1 and BouncingBall2, I want when a bullet hit both to destroy and if the time have not exceeded displaySecond and you have destroy the balls you win, but my problem is the OnCollisionEnter is not working. The part of wining is not working the rest are, my code fragment is below.
function OnCollisionEnter(col.collision) {
if ((displaySecond < 30) && (
col.gameObject.tag ==
BouncingBall1 == null &&
col.gameObject.tag ==
BouncingBall1 == null)) {
print("You have won");
}
}
col.gameObject.tag == BouncingBall1 == null
I think the problem is with the way you check if an object is destroyed. This isn't the way to do it. Also, you're checking if two identical lines of code are identical. So this will always return true if the display second is lower than 30.
Try changing it to
if ( (displaySecond < 30) &&
(col.gameObject.tag == "BouncingBall1") ) {
Debug.Log("You have won!")
}
It sounds like you want keep track of whether each ball has been destroyed and display "You have won" when both have been destroyed. This code is a little crude but should achieve this:
var ball1Destroyed = false;
var ball2Destroyed = false;
...
function OnCollisionEnter(col : Collision) {
if (col.gameObject.tag == "BouncingBall1") {
ball1Destroyed = true;
}
if (col.gameObject.tag == "BouncingBall2") {
ball2Destroyed = true;
}
if (displaySecond < 30 && ball1Destroyed && ball2Destroyed) {
Debug.Log("You have won");
}
}
This code assumes that the only collisions will be between bullets and balls (not between one ball and another), this can be done with collision layers.
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.