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

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.

Related

How to disable picking up objects if the object is under the player?

Whenever the player picks up an object underneath him, it causes weird behaviour. So I'm trying to prevent the picking-up whenever the pickable object is under the player. All pickable objects are in a different layer than the player. Here is what I have tried:
if (Physics.Raycast(raycastPos, mainCamera.transform.forward, out hit, maxDistance))
{
if (hit.collider.transform.gameObject.layer == 0 )
{
lookObject = hit.collider.transform.gameObject;
reticle.color = new Color(1, 0, 0, 0.75f);
}
else
{
lookObject = null;
reticle.color = new Color(1, 1, 1, 0.75f);
}
if (PickingUp)
{
if (currentlyPickedUpObject == null)
{
if (lookObject != null)
{
PickUpObject();
}
}
}
But this disabled the entire picking up, now I can't pick up objects whether they are under the player or not.
How can I fix this to achieve what I want?
well change the position of the else .. currently as soon as anything at all (e.g. the ground) is below you do not call PickUpObject.
I also guess you would rather want to check for
hit.collider.gameObject == lookObject
not player.gameObject
if (PickingUp)
{
if (currentlyPickedUpObject == null)
{
if (lookObject != null)
{
if (Physics.Raycast(transform.position, Vector3.down, out hit) && hit.collider.gameObject == lookObject)
{
// object is under player
Debug.Log("can't pick up");
}
else
{
PickUpObject();
}
}
}
}
Since you already seem to know the object you are going to pickup anyway you could also simply define a certain angle range it may not fall in. That might be easier than a Raycast:
float THRESHOLD = 5f;
if (PickingUp)
{
if (currentlyPickedUpObject == null)
{
if (lookObject != null)
{
if(Vector3.Angle(Vector3.down, lookObject.transform.position - transform.position) <= THRESHOLD)
{
PickUpObject();
}
}
}
}
I assume this is a player script.
Since raycast origins at transform.position, I guess the origin is inside the player. There's a good chance ray is being cast and ends immediately always hitting player.
I'm failing to see how searching for player would help, I think what you need is raycasting in search for an object.
Also, as mentioned in the comment, the else statement is in the wrong place, and the solution 1) I provided will fail - else should refer to the most inner if statement, otherwise you won't pick up anything if you hit anything with raycast.
Possible solutions:
in the inner if statement check if you hit the pickable object not the player. I'm assuming there's more than one object, so you can use tags to determine which objects are pickable, anything that works for you. Then, you know, you stand on an object.
You might need to ignore player's layer during raycasting.
Create a trigger at the bottom of the player. If pickable object collides with it, you are standing on it.
Fix the issues with weird behaviour. After all, I guess player should be able to always pick up and item, and being unable to do so would be frustrating.

Collisions in custom physics problems

I'm kind of new to Unity. As by the title, I am having trouble getting the collisions right in my game. I am using the custom physics script from unity: https://unity3d.com/learn/tutorials/topics/2d-game-creation/scripting-gravity?playlist=17093. In my game, I am experiencing difficulties in disable collisions.
For example, when I use
Physics2D.IgnoreLayerCollision (8, 9);
It doesn't change anything and the two characters still collide. Also, for some reasons, the triggers behave strange and are still affected by collisions. Going near a character with triggers will make him float up. I've been stuck on this for a long time and I'd really appreciate the help.
It is worth noting that I am using custom physics and using a box collider 2d to detect attack ranges etc. Here is some code of that:
Collider2D attackbox = Physics2D.OverlapBox (attackPos.position, new Vector2 (attackRangeX, attackRangeY), 0, whatIsPlayer);
if (attackbox != null && !isDead && characterController.isDead == false) {
targetVelocity = Vector2.zero;
animator.SetTrigger ("isPunching");
timeBtwAtk = startTimeBtwAtk;
}
and I have individual punch triggers in the animation to detect when the character is actually being hit:
public void SetColliderIndex(int spriteNum)
{
colliders[currentColliderIndex].enabled = false;
currentColliderIndex = spriteNum;
colliders[currentColliderIndex].enabled = true;
}
public void ClearColliderIndex()
{
colliders[currentColliderIndex].enabled = false;
}
void OnTriggerEnter2D(Collider2D col)
{
if (col.tag == "Player")
{
col.GetComponent<CharacterController2D> ().TakeDamage (enemyDamage);
col.GetComponent<CharacterController2D> ().canWait = false;
col.GetComponent<CharacterController2D> ().canControl = false;
}
}
When I use Physics2D.IgnoreLayerCollision (8, 9); I want both specified layers not to interact whatsoever. I don't want any weird shifts, or floating when they pass through each other. Also when I move my player agains the enemy, I don't want him to be able to push him back. I want it to be as if he is running into a wall.
I have answered something similar to this here. Also, if you don't want the player suddenly floating upon collision, you can just set the rigidbody/rigidbody2d type to kinematic, but this mean the object will not be affected by physics. you will have to do that in code.
i think your problem is that at some point the two colliders interact and/or one of the two gets activated back, but from the code that you posted i can't clearly identify the problem if there's any

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.

TriggerEnter is not working for && operator in unity 2D

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....

Toggle between two materials

I'm wanting to have two textures switch when ever I press the space bar in my project. But when I do, nothing is happening.
can anyone see what I'm doing wrong with my logic? I had this working with switching between 2 shaders, but not it is materials, it isn't working. I'm very confused by this.
void Switch()
{
Debug.Log(gameObject.renderer.material.name);
if(Input.GetButtonDown("Jump"))
{
diffuse = false;
//if(gameObject.renderer.material == diffuse_Material)
}
else
{
diffuse = true;
}
if(diffuse == true)
{
gameObject.renderer.material = mask_Material;
print("1");
Debug.Log(gameObject.renderer.material.name);
}
else
{
gameObject.renderer.material = diffuse_Material;
print("2");
Debug.Log(gameObject.renderer.material.name);
}
My codes changes the material once, but doesn't change back again when I press the space bar again.
update
I've taken my code out of the update method and placed it in its own one. I've since modified it to be a "simple" bool check. Now when I play the game my object starts with the material I first want on it, but when I hit space, it only changed the material for a fraction of a second.
How can I do it so that on the press of a single button, my bool toggles between true and false. I thought i had it, but I guess I don't. My debug log now looks like this:
DepthMask (instance)
1
DepthMask (instance)
2
Diffuse (instance)
Diffuce (instance)
DepthMask (instance)
DepthMask (instance)
1
I think the problem is the following:
When the user presses the jump key the boolean gets set to true, the material changes and its all good. BUT then the update method gets called again, and followed by that I'm assuming your Switch method also.
Input.GetButtonDown("Jump") will now evaluate to false, causing your boolean value diffuse to become true again, and the material changes back.
Is the material supposed to toggle everytime the users presses the Jump button? If so, change your code to (the else statement can be completely removed):
void Switch()
{
Debug.Log(gameObject.renderer.material.name);
if(Input.GetButtonDown("Jump"))
{
diffuse = !diffuse;
// material only needs to change if diffuse changed
if(diffuse)
{
gameObject.renderer.material = mask_Material;
print("1");
Debug.Log(gameObject.renderer.material.name);
}
else
{
gameObject.renderer.material = diffuse_Material;
print("2");
Debug.Log(gameObject.renderer.material.name);
}
}
}
EDIT: included the entire Switch method.
You could try to compare
renderer.sharedMaterial
instead of
renderer.material
to get the non-instanced version of the material. Something like this:
public Material a;
public Material b;
void Update ()
{
if (Input.GetButtonDown("Jump"))
{
if (renderer.sharedMaterial == a)
{
gameObject.renderer.material = b;
}
else
{
gameObject.renderer.material = a;
}
}
}

Categories