How would I check individual lights if my boolean is true constantly - c#

I need a way to check all scripts if boolean is true and then a way in this script to see in the if statement of the current light the character is standing next to has the boolean true to activate and only then should the Instantiate function be triggered.
private bool Once = true;
public Transform Spawnpoint1;
public Transform Spawnpoint2;
public GameObject Prefab1;
public GameObject Prefab2;
//Something like this, but I don't know where to go after that
GameObject[] Lights = GameObject.FindGameObjectsWithTag("lightSwitch");
//foreach(GameObject Light in Lights)
void OnTriggerEnter2D(Collider2D collision)
{
if (Once == true)
{
Debug.Log("It's true");
if (LightOnOff.isON == true) // It needs to check this constantly
{
Debug.Log(" It's Lit");
Instantiate(Prefab1, Spawnpoint1.position, Spawnpoint1.rotation);
Instantiate(Prefab2, Spawnpoint2.position, Spawnpoint2.rotation);
Once = false;
}
}
}
here is the Light script as well
public static bool isON;
public void lightOn()
{
this.GetComponent<Light>().enabled = true;
isON = true;
}

First of all you shouldn't use static
public static bool isON;
for an individual value! static makes the value a "non instanced" value, meaning it belongs to the entire class instead of instances => To say it in simple words this variable is shared between all your components (see this post for more information). Instead use
public bool isON;
Than access the insteance variable of the component like
Update: From the comments I now know that actually the components are not on the collider object but rather on a child of the object this script is attached to
void OnTriggerEnter2D(Collider2D collision)
{
// Update. TODO check if the correct Object collided
//if(!collision.gameObject == <your player>)
if (!Once) return;
// Update this now searches in its own children instead of children of collision
var lightOnOff = GetComponentInChildren<LightOnOff>(true);
if(!lightOnOff)
{
Debug.Log("No LightOnOff found on collision" + collision.name, this);
return;
}
Debug.Log("It's true");
if (!LightOnOff.isON) return;
Debug.Log(" It's Lit");
Instantiate(Prefab1, Spawnpoint1.position, Spawnpoint1.rotation);
Instantiate(Prefab2, Spawnpoint2.position, Spawnpoint2.rotation);
Once = false;
}
But instead of using your LightOnOff component you could also simply acces the Light component and do something like
Update: From the comments I now know that actually the components are not on the collider object but rather on a child of the object this script is attached to
void OnTriggerEnter2D(Collider2D collision)
{
if (!Once) return;
// directly access the Light
// Update this now searches in its own children instead of children of collision
var light = GetComponentInChildren<Light>(true);
if(!light)
{
Debug.Log("No Light found on collision" + collision.name, this);
return;
}
Debug.Log("It's true");
// Directly check if the Light component is enabled
if (!light.enabled) return;
Debug.Log(" It's Lit");
Instantiate(Prefab1, Spawnpoint1.position, Spawnpoint1.rotation);
Instantiate(Prefab2, Spawnpoint2.position, Spawnpoint2.rotation);
Once = false;
}

You don't need to keep track of all the lights just for that.
Something you do need to change is that you should make isON not static. This is because an actual light might be on or not, not that the concept of lights are on or not.
public bool isON;
Check the Collider2D for the associated object you're colliding with, and look for a light there. The following code assumes any light will be on the same GameObject as a Trigger or one of its children.
void OnCollisionEnter2D(Collider2D col) {
// only activate once
if (once) {
// Get light if exists
GameObject collidedObject = col.gameObject;
Light light = collidedObject.GetComponentInChildren<Light>();
if (light != null) {
// We have a light, check if it's on. We only care about the collided light
if (light.isON) {
Debug.Log("It's Lit fam");
Instantiate(Prefab1, Spawnpoint1.position, Spawnpoint1.rotation);
Instantiate(Prefab2, Spawnpoint2.position, Spawnpoint2.rotation);
// Note that if we run into another lit light nothing will happen,
// even if its the first time running into that particular light
Once = false;
}
}
}
}
Also, you can just use if(something) instead of if(something == true)

Related

Multiple collisions happening at the same time

I'm making a Balloon Fight style game and I'm having trouble with object collision. Each character has two balloons on top of his head and each balloon has an on trigger Box Collider. I want to make it so only one balloon can be hit at a time so you can't destroy both balloons at the same time. In order to do this I added a boolean called isAttacking to prevent it from destroying more than one balloon at the same time.
Hello, I'm making a Balloon Fight style game and I'm having trouble with object collision. Each character has two balloons on top of his head and each balloon has an on trigger Box Collider. I want to make it so only one balloon can be hit at a time so you can't destroy both balloons at the same time. In order to do this I added a boolean called isAttacking to prevent it from destroying more than one balloon at the same time.
public bool isAttacking = false;
private void OnTriggerEnter(Collider collision)
{
if (collision.GetComponent<Collider>().gameObject.layer == 7 && collision.GetComponent<Collider>().gameObject.tag != this.gameObject.tag)
{
if (!isAttacking)
{
Destroy(collision.GetComponent<Collider>().transform.parent.gameObject);
transform.parent.gameObject.GetComponent<Jump>().jump = true;
isAttacking = true;
}
}
}
void LateUpdate()
{
if (isAttacking)
{
isAttacking = false;
}
}
While it does prevent two collisions from registering I still found this solution to be insufficient, since the balloon that is destroyed is not necessarily the one closest to the character destroying it. How could I improve the collision code in order for it to only register the collision happening closer to the character?
Within one frame afaik there is no reliable order of OnTriggerEnter calls (it is somewhat based on the instanceID of objects but that won't really help you).
What you could do instead would be comparing distances, somewhat like e.g.
private readonly HashSet<GameObject> hittingObjects = new();
[SerializeField] private Jump jump;
private void Awake()
{
if(!jump) jump = GetComponentInParent<Jump>(true);
}
private void OnTriggerEnter(Collider collision)
{
if (collision.layer == 7 && !collision.CompareTag(gameObject.tag))
{
hittingObjects.Add(collision.transform.parent.gameObject);
}
}
private void LateUpdate()
{
if (hittingObjects.Count > 0)
{
var closestHit = hittingObjects.OrderBy(hit => (transform.posiion - hit.transform.position).sqrMagnitude).First();
Destroy(closestHit);
jump.jump = true;
hittingObjects.Clear();
}
}
Note: This still doesn't prevent this object from colliding with the other balloon in the very next physics update. If you wanted to track this as well you could make it slightly more complex and only allow collisions if you are newly entering the trigger => You have to exit the object again before you can hit it again.
Somewhat like maybe
private readonly HashSet<GameObject> hastoExitFirstObjects = new();
private readonly HashSet<GameObject> newHittingObjects = new();
[SerializeField] private Jump jump;
private void Awake()
{
if(!jump) jump = GetComponentInParent<Jump>(true);
}
private void OnTriggerEnter(Collider collision)
{
if (collision.layer == 7 && !collision.CompareTag(gameObject.tag))
{
var hit = collision.transform.parent.gameObject;
if(!hastoExitFirstObjects.Contains(hit))
{
newHittingObjects.Add();
}
}
}
private void OnTriggerExit(Collider collision)
{
if (collision.layer == 7 && !collision.CompareTag(gameObject.tag))
{
var hit = collision.transform.parent.gameObject;
hastoExitFirstObjects.Remove(hit);
}
}
private void LateUpdate()
{
if (newHittingObjects.Count > 0)
{
var closestHit = newHittingObjects.OrderBy(hit => (transform.posiion - hit.transform.position).sqrMagnitude).First();
newHittingObjects.Remove(closestHit);
Destroy(closestHit);
jump.jump = true;
foreach(var hit in newHittingObjects)
{
hastoExitFirstObjects.Add(hit);
}
newHittingObjects.Clear();
}
}
First, check if your OnTriggerEnter is executing for both balloons. It probably is?
Then in the moment OnTriggerEnter executes, compare the position of collision with the position of your balloons and see which one is the closest, then destroy the closest balloon and maybe set a variable isInvulnerable as true, so that if it is true, no balloon can be destroyed inside OnTriggerEnter.
I'd just enable only one balloons box collider at once, and when it gets popped enable the other balloon after 1 second delay.

Unity forcing physics engine to check collisions

I am creating a game in unity where the player can drag one object (a card) over another (an enemy). If they drag the card over the enemy I want to run some code, and if not I want to return the card to its initial position. I placed a collider on both objects but it isnt working the way it should. I am assuming this is because the object is getting moved back to its initial location before the physics engine sees the collision, but I don't know how to fix this. I am deactivating the collider on the card while moving it to avoid having it trigger collisions until the player has placed it using the onmousedown and onmouseup events. Any tips on how to fix this behavior? can I force the physics engine to check collisions with the onmouseup event?
I know the collisions are working because when I turn off the return to initial position behavior the game functions as expected.
How about useing the collider as trigger and do not use rigidbodys or anything.
Then if there is a trigger enter event set bool as true. If there trigger exit reset the bool to false.
Now if you "Release" the card check if bool is true or false.
true: Set the cards position to the player or what you want
false: Reset the cards position to the start
Now beeing a little mroe fancy you can set a lighted border around the card when bool is active (just check in update)
Example:
public class Card : MonoBehaviour {
private bool isHolding;
private bool isHovering;
public Vector3 startPos;
public void Start() {
startPos = transform.position;
}
public void Update() {
// Code where you check if the card is Clicked and Moved by the player
// If so set isHolding = true
// dont enter the check if holding blablabla when animation stuff is happening
if (doAnimationStuff) {
// do animation
// Destroy Object
return;
}
// Code to check if isHolding == false
if (!isHolding) {
if (!isHovering) {
transform.position = startPos;
} else {
doAnimationStuff = true;
}
}
}
private void OnTriggerEnter(Collider other) {
// Check if other is a player
// if so set isHovering = true
}
private void OnTriggerExit(Collider other) {
// Check if other is a player
// if so set isHovering = false
}
}

I am having issues with coding a game of tag

So I am trying to make my first game using Unity and c#. I want my game to be a simple game of tag like I used to play when I was younger. I have tried using "OnCollisionEnter" and I was able to get that to change a counter that gave a bool a label. I realized that while this may work for tagging someone it does not help with other people tagging you. And tips on how I can make my code more like a "Tag Manager"?My current progress
you can have a Taggable.cs like this, not sure if this is even correct syntax, I don't care to actually write it out and test
class Taggable : MonoBehaviour {
bool it;
private void OnCollisionEnter(Collision collision) {
var other = collision.collider.GetComponent<Taggable>();
if(other != null) {
if(it) {
other.it = true;
it = false;
}else if(other.it) {
it = true;
other.it = false;
}
}
}
}
You could implement the logic such that your script checks to see if you are the tagger using Unity's tags property. Then, you could switch the tags of both the players, once you check if the collided object is a player.
Below is the code I suggest you use. I would personally use OnTriggerEnter to have more clearer logic between collider and player. Make sure to have a collider object and a Rigidbody on all players within the scene for the function to be called, and attach your script onto every player within the scene.
private void OnTriggerEnter (Collider col) {
// if you are the tagger
if (gameObject.tag == "Tagger") {
// and if the collided object is a regular player
if (col.tag == "Player") {
// the player is now a tagger
col.tag = "Tagger";
// depending on if you want to buildup taggers or switch them around,
// the below assignment would vary
gameObject.tag = "Player";
}
}
}

How do I make it so if the player wants they can hold the animation but if they don't hold it, it completes.. (physics based)

so here is the scenario,
i want the player to be able to perform a trick, and then be able to hold the trick for a longer duration if they want to, but if they don't hold the input then they instead just continue the animation until completion as i haven't actually tried implementing too much and its not giving me the desired result i figured i'd just ask if people have already done it so i don't spend the next 2 hours down a rabbit hole, any and all help is appreciated thanks! :D
(Unity Script)
{
[Header("Trick Attributes")]
public string GroundTagName; // Tag used for all the platforms
public KeyCode stuntKey;
public float AnimationFreezeTime = 0.75f;
public SpriteAnimator anim; // Put the Sprite animator here
public Animator spriteAnimator; // Put the Animator here
private bool isGrounded;
public bool stunting = false;
private void Start()
{
}
private void Update()
{
if (Input.GetKeyDown(stuntKey) && !isGrounded)
{
anim.StartAnimation("FlyingSquirrel");
stunting = true;
Invoke("FreezeAnimation", AnimationFreezeTime);
}
if (Input.GetKeyUp(stuntKey))
{
stunting = false;
spriteAnimator.speed = 1;
}
}
void FreezeAnimation() {
spriteAnimator.speed = 0;
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == GroundTagName)
{
isGrounded = true;
}
else
{
isGrounded = false;
}
if (stunting && collision.gameObject.tag == GroundTagName)
{
Destroy(gameObject);
}
}
private void OnCollisionExit(Collision collision)
{
isGrounded = false;
}
}
FlyingSquirrel needs to be broken up into 3 different animations. This can be done in Maya, Blender, uMotion, or even Unity's animation importer:
You need 3 Animator states:
Start_FlyingSquirrel // Player moves into position
Idle_FlyingSquirrel // Player is "holding" the trick
End_FlyingSquirrel // Player let go, return to normal
When the player presses button to start the trick, play the Start animation. For the transition, use "has exit time" to proceed to the Idle State. The Idle state will be true (use a boolean Animator parameter) while the trick is "held". Uncheck "has exit time" for the transition to the End state- you want this to happen instantly.

Trigger Collider Flickering

I'm very new to unity and I'm making a simple tag game with car like players. However, I'm having problems with my trigger collider. When I tag the other car it kind of flickers the is tagged true/false. Here is my code.
public Color TaggedColor;
public Color NoTaggedColor;
public bool Tagged;
// Start is called before the first frame update
void Start()
{
Tagged = true;
GetComponent<Image>().color = TaggedColor;
}
// Update is called once per frame
void Update()
{
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "P2")
{
if (Tagged == false)
{
Tagged = true;
GetComponent<Image>().color = TaggedColor;
}
else
{
if (Tagged == true)
{
Tagged = false;
GetComponent<Image>().color = NoTaggedColor;
}
}
Debug.Log("TAG!");
}
}
void GotTagged()
{
if (Tagged == false)
{
Tagged = true;
//GetComponent<Image>().color = TaggedColor;
}
}
void TaggedOtherPlayer()
{
if (Tagged == true)
{
Tagged = false;
GetComponent<Image>().color = NoTaggedColor;
}
}
I have a Second code for P2 that the only change is the start and the tag is P1. I'm not sure if this problem is something in my code or if it's the collider it's self. If anyone has any idea why this is happening I would love to hear it!
Update: I bevile the issue is coming from the Colliders because I have an empty as a child of both players that is the trigger collider. However when I tag one the other trigger goes off as well. Should I have only one trigger? And if so how would I go about doing it?
Thanks
once you tag a player SetActive(false) the empty triggers for about 1 second or so. If you had a button that whenever its pressed it changes s value from true to false the false to true if you press and hold that button it will "flicker" back and forth between true and false. Thats what's happening with your players the trigger is constantly being pulled while you're touching so make it inactive for long enough for you to not be touching anymore. I hope that makes sense.

Categories