I have several objects with the same tag, and I want to check if they are moving or not, to call a function when they're not moving. So I used the code bellow, but the aremoving is always false even when some objects still moving! Do you know what's wrong in my code?
Script:
bool aremoving;
void LateUpdate()
{
GameObject[] Cubes = GameObject.FindGameObjectsWithTag("Cube");
foreach (GameObject Cube in Cubes)
{
if (Cube.GetComponent<Rigidbody>() == null)
{
continue;
}
if (Cube.GetComponent<Rigidbody>().velocity.magnitude > 0.01)
{
aremoving = true;
}
if (Cube.GetComponent<Rigidbody>().velocity.magnitude <= 0.01)
{
aremoving = false;
}
}
Debug.Log("Cubes moving: " + aremoving);
}
Write the code like this
bool aremoving;
void LateUpdate()
{
GameObject[] Cubes = GameObject.FindGameObjectsWithTag("Cube");
foreach (GameObject Cube in Cubes)
{
if (Cube.GetComponent<Rigidbody>() == null)
{
continue;
}
if (Cube.GetComponent<Rigidbody>().velocity.magnitude > 0.01f)
{
aremoving = true;
}
Debug.Log("Cubes moving: " + aremoving);
aremoving = false;
}
Related
I have written a script that detects when something collides with my game object. When something collides with it, the collision may last 1 - 2 seconds but I only want one game object to spawn. When I run the scene and collide with it hundreds of game objects spawn instantly and everything crashes.
I have tried using Thread.Sleep() and IEnumerator waitor() but no luck so far.
Any ideas would be appreciated, I will attach the code below
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
public class ColliderHit : MonoBehaviour
{
public GameObject topLevelMenu;
public GameObject sublevel;
public GameObject topMenuItem;
public GameObject menuItemTouched;
public GameObject itemToSpawn;
public bool topLevelItem;
void OnTriggerEnter(Collider col)
{
if (col.gameObject.name != "" || col.gameObject.name == "RightHandVisual" || col.gameObject.name == "OculusHand_R" || col.gameObject.name == "HandGrabInteractor" || col.gameObject.name == "OVRHandPrefab")
{
if (topLevelItem)
{
topLevelMenu.SetActive(false);
sublevel.SetActive(true);
sublevel.transform.position = topMenuItem.transform.position;
sublevel.transform.rotation = topMenuItem.transform.rotation;
}
else
{
StartCoroutine(waiter());
var itemsPos = menuItemTouched.transform.position;
var itemsRot = menuItemTouched.transform.rotation;
var itemsSca = menuItemTouched.transform.localScale;
GameObject spawned = Instantiate(itemToSpawn);
spawned.transform.rotation = itemsRot;
spawned.transform.localScale = itemsSca;
var zpos = itemsPos.z - (0.1f);
spawned.transform.position = new Vector3(itemsPos.x, itemsPos.y, zpos);
}
}
}
IEnumerator waiter()
{
//Wait for 4 seconds
yield return new WaitForSeconds(4);;
}
}
Solution to fix your code as is
That's not how Co-routines work. The code that needs to be await needs to be within the coroutine:
bool isOnCollideCooldown = false;
void OnTriggerEnter(Collider col)
{
if (col.gameObject.name != "" || col.gameObject.name == "RightHandVisual" || col.gameObject.name == "OculusHand_R" || col.gameObject.name == "HandGrabInteractor" || col.gameObject.name == "OVRHandPrefab")
{
if (topLevelItem)
{
topLevelMenu.SetActive(false);
sublevel.SetActive(true);
sublevel.transform.position = topMenuItem.transform.position;
sublevel.transform.rotation = topMenuItem.transform.rotation;
}
else
{
// Return if it is instantiated
if (isOnCollideCooldown) return;
// Otherwise spawn and wait
StartCoroutine(waiter());
}
}
}
IEnumerator waiter()
{
// Go onto cooldown
isOnCollideCooldown = true;
// Spawn the object
var itemsPos = menuItemTouched.transform.position;
var itemsRot = menuItemTouched.transform.rotation;
var itemsSca = menuItemTouched.transform.localScale;
GameObject spawned = Instantiate(itemToSpawn);
spawned.transform.rotation = itemsRot;
spawned.transform.localScale = itemsSca;
var zpos = itemsPos.z - (0.1f);
spawned.transform.position = new Vector3(itemsPos.x, itemsPos.y, zpos);
//Wait for 4 seconds
yield return new WaitForSeconds(4);
// Go off cooldown
isOnCollideCooldown = false;
}
Additional Solution
The issue is that when you spawn the object, it instantly collides with the other objects. So on the script with the object that spawns you can use the following:
Collider col;
public float noCollisionTime = 1;
void Awake() {
col.enabled = false;
StartCoroutine(EnableCollider());
}
IEnumerator EnableCollider()
{
yield return new WaitForSeconds(noCollisionTime);
col.enabled = true;
}
You could try declaring a
bool isInstantiated = false;
and a method like this:
void ResetInstantiation()
{
isInstantiated = false;
}
then, check if it's already been instantiated:
else
{
StartCoroutine(waiter());
var itemsPos = menuItemTouched.transform.position;
var itemsRot = menuItemTouched.transform.rotation;
var itemsSca = menuItemTouched.transform.localScale;
if (isInstantiated) return;
GameObject spawned = Instantiate(itemToSpawn);
spawned.transform.rotation = itemsRot;
spawned.transform.localScale = itemsSca;
var zpos = itemsPos.z - (0.1f);
spawned.transform.position = new Vector3(itemsPos.x, itemsPos.y, zpos);
isInstatiated = true;
Invoke("ResetInstantiation", 4.0f);
}
This way, you set the value to true with stops the instantiation and reset the flag after 4 seconds. (or however many you wish)
I been trying to create an AI for the enemy to patrol between some points and, when spot player in a certain range, the enemy stop the patrol and follows the player.
The thing is, if I only have the enemy to follow the player, works perfectly the same happens with just the patrol, but both together doesn't seem to work. The enemy acts in a weird way.
My code:
public void Start()
{
_navMeshAgent = this.GetComponent<NavMeshAgent>();
anim = GetComponent<Animator>();
if (_navMeshAgent == null)
{
Debug.LogError("not attached to " + gameObject.name);
}
else
{
if (_patrolPoints != null && _patrolPoints.Count >= 2)
{
_currentPatrolIndex = 0;
anim.SetBool("idle", true);
SetDestination();
}
else
{
Debug.Log("Insufficient patrol points.");
}
}
}
void Update()
{
if (player == null)
{
player = GameObject.Find("Player Character").GetComponent<Transform>();
}
if (Vector3.Distance(player.transform.position, this.transform.position) < 10)
{
chacePlayer();
}
else
{
patrol();
}
bool patrol()
{
Debug.Log("patrolling");
//Check if we're close to the destination.
if (_travelling && _navMeshAgent.remainingDistance <= 1.0f)
{
_travelling = false;
anim.SetBool("idle", false);
anim.SetBool("move", true);
//If we're going to wait, then wait dumbass!
if (_patrolWaiting)
{
_waiting = true;
_waitTimer = 0f;
anim.SetBool("idle", true);
anim.SetBool("move", false);
}
else
{
ChangePatrolPoint();
SetDestination();
}
}
//Instead if we're waiting...
if (_waiting)
{
_waitTimer += Time.deltaTime;
if (_waitTimer >= _totalWaitingTime)
{
_waiting = false;
anim.SetBool("move", true);
anim.SetBool("idle", false);
ChangePatrolPoint();
SetDestination();
}
}
return true;
}
}
private void SetDestination()
{
if (_patrolPoints != null)
{
Vector3 targetVector = _patrolPoints[_currentPatrolIndex].transform.position;
_navMeshAgent.SetDestination(targetVector);
_travelling = true;
////anim.SetBool("idle", false);
////anim.SetBool("move", true);
}
}
//Selects a new patrol point in the available list, but
//also with a small probability allows for us to move forward or backwards.
private void ChangePatrolPoint()
{
//Unity generate random number between 0 and 1
if (UnityEngine.Random.Range(0f, 1f) <= _switchProbability)
{
//decides if go forward or backwards: whatever the value, make the oposite
_patrolForward = !_patrolForward;
}
if (_patrolForward)
{
//if the patrolpoint exceedes patrolpoints.count, go backs to zero
_currentPatrolIndex = (_currentPatrolIndex + 1) % _patrolPoints.Count;
}
else
{
if (--_currentPatrolIndex < 0)
{
_currentPatrolIndex = _patrolPoints.Count - 1;
}
}
}
void chacePlayer()
{
Vector3 direction = player.transform.position - this.transform.position;
this.transform.rotation = Quaternion.Slerp(this.transform.rotation,
Quaternion.LookRotation(direction), 0.1f);
direction.y = 0;
if (direction.magnitude > 2)
{
this.transform.Translate(0, 0, 0.05f);
Debug.Log("chacing");
}
}
At first I thought it was because the code was running both together so I put a Debug to see if it was that, but the debug of the patrol stops every time the enemy is following the player.
Can someone please help me?
I have a 3D board game in Unity. I would like to move my character without having to press a key, but most importantly I would like to show a dynamic panel in canvas for whatever square the character lands on. So far I have the dice rolling and the character moving (after pressing a key) the correct amount of squares, but I am unable to figure out how to activate the panel based on the square color. Any help would be appreciated.
Here is my CharacterScript:
public class CharacterScript : MonoBehaviour
{
public Path currentPath;
public int squarePosition;
public int squares;
bool isMoving;
public GameObject PinkSquarePanel = GameObject.FindGameObjectWithTag("PinkSquare");
public GameObject CyanSquarePanel = GameObject.FindGameObjectWithTag("CyanSquare");
public GameObject WhiteSquarePanel = GameObject.FindGameObjectWithTag("WhiteSquare");
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape) && !isMoving)
{
squares = DiceNumberTextScript.diceNumber;
}
StartCoroutine(Move());
if (squares == 0)
{
ActivateSquarePanel();
}
}
IEnumerator Move()
{
if (isMoving)
{
yield break;
}
isMoving = true;
while (squares > 0)
{
Vector3 nextPosition = currentPath.squareList[squarePosition + 1].position;
while (MoveToNextSquare(nextPosition))
{
yield return null;
}
yield return new WaitForSeconds(0.1f);
squares--;
squarePosition++;
}
isMoving = false;
}
bool MoveToNextSquare(Vector3 goal)
{
return goal != (transform.position = Vector3.MoveTowards(transform.position, goal, 4f * Time.deltaTime));
}
void ActivateSquarePanel()
{
if (squarePosition.Equals(PinkSquarePanel))
{
PinkSquarePanel.GetComponent<CanvasGroup>().alpha = 1;
}
else if (squarePosition.Equals(CyanSquarePanel))
{
CyanSquarePanel.GetComponent<CanvasGroup>().alpha = 1;
}
else if (squarePosition.Equals(WhiteSquarePanel))
{
WhiteSquarePanel.GetComponent<CanvasGroup>().alpha = 1;
}
}
}
And here is my PathScript:
public class Path : MonoBehaviour
{
Transform[] squareObjects;
public List<Transform> squareList = new List<Transform>();
GameObject[] PinkSquares = GameObject.FindGameObjectsWithTag("PinkSquare");
PinkSquare[] pinkList = new PinkSquare[1];
GameObject[] CyanSquares = GameObject.FindGameObjectsWithTag("CyanSquare");
CyanSquare[] cyanList = new CyanSquare[1];
GameObject[] WhiteSquares = GameObject.FindGameObjectsWithTag("WhiteSquare");
WhiteSquare[] whiteList = new WhiteSquare[1];
private void OnDrawGizmos()
{
Gizmos.color = Color.black;
FillSquares();
for (int i = 0; i < squareList.Count; i++)
{
Vector3 currentPosition = squareList[i].position;
if (i > 0)
{
Vector3 previousPosition = squareList[i - 1].position;
Gizmos.DrawLine(previousPosition, currentPosition);
if(currentPosition.Equals(PinkSquares))
{
pinkList[i] = new PinkSquare();
}
else if (currentPosition.Equals(CyanSquares))
{
cyanList[i] = new CyanSquare();
}
else if (currentPosition.Equals(WhiteSquares))
{
whiteList[i] = new WhiteSquare();
}
}
}
}
void FillSquares()
{
squareList.Clear();
squareObjects = GetComponentsInChildren<Transform>();
foreach (Transform square in squareObjects)
{
if (square != this.transform)
{
squareList.Add(square);
}
}
}
}
I believe your issue is in your comparisons, you are trying to use an Equals to compare your currentPosition which is a Vector3 type to a GameObject[] which is an array of gameObjects. As I mentioned in my comments, this comparison will always fail as an array of gameObjects can not be equal to a vector.
Instead of using these lines, try this line:
if(squareList[i].gameObject.tag.CompareTag("PinkSquare")
The full snippet of if else would look like
if(squareList[i].gameObject.tag.CompareTag("PinkSquare")
{
pinkList[i] = new PinkSquare();
}
else if(squareList[i].gameObject.tag.CompareTag("CyanSquare")
{
cyanList[i] = new CyanSquare();
}
else if(squareList[i].gameObject.tag.CompareTag("WhiteSquare")
{
whiteList[i] = new WhiteSquare();
}
Your CharacterScript is going to need to get the gameObject or Transform from the Path script as it is only keeping track of indexes. Your issue in this script is you are comparing an integer to a GameObject which would never be true. I would also recommend not using OnDrawGizmos() as it is an editor only script and should only be used to render editor debugging tools. The only reference to a Gizmo I see in the function is Gizmos.color = Color.black; which does nothing as you are not rendering a gizmo anywhere. I would move this code to a different function and call it from your CharacterScript. Have the return type be GameObject or Transform of the square you are on, so the CharacterSCript can check which color it lands on. Using an Integer nor Vector3 to compare to a GameObject[] will never work.
I am not sure if there are issues elsewhere in the code, but as this comparison would always fail, none of these statements would get broken into. What this means is your panels would never have the chance to get their alpha set nor get created.
As you can see, I started with an object in a scene and attached a script to it along with other components. https://imgur.com/z9Tooh9
It looks barren due to there not actually being a model in there. However, when the game is started, it is created by another script in an object in the hierarchy. https://imgur.com/guQQlJO
You can also see that the script works as expected and detects all the skinned mesh renderers and allows you to adjust the colors accordingly.
However, this is where the problem comes in.
When I duplicate this object the first object does what is expected of it but, the second one doesn't.
As you can see, there are no skinned mesh renderers in the list for the second object. https://imgur.com/zTRHL9F
Naturally, I put debug logs at the point where it detects the skinned mesh renderers to see what the issue is:
void OnMouseEnter()
{
Debug.Log("Mouse Entered");
foreach (SkinnedMeshRenderer element in skinnedMeshRenderersScan) //For
every object it finds
{
Debug.Log("Detected: " + element);
Debug.Log("Detected Color: " + selectedColor);
element.material.color = selectedColor;
}
}
void OnMouseExit()
{
Debug.Log("Mouse Left");
foreach (SkinnedMeshRenderer element in skinnedMeshRenderersScan) //For
every object it finds
{
//Debug.Log("Detected: " + element);
//Debug.Log("Detected Color: " + deselectedColor);
element.material.color = deselectedColor;
}
}
The first object notes that they're detected. https://imgur.com/fBhXjKj
The second one simply pretends as if the debug log is not even there. https://imgur.com/alE76aY
I'm more than happy to elaborate in the event that you don't quite understand what it is I'm asking.
Many thanks in advance and sorry if my formatting is terrible I'm not the best at it.
I've tried searching for answers online but, I could not locate a solution to my rather unique problem.
The whole script is as follows:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TankController : MonoBehaviour
{
Vector3 targetPosition;
Vector3 lookAtTarget;
public Vector4 selectedColor;
public Vector4 deselectedColor;
Quaternion playerRot;
float rotSpeed = 2;
float speed = 3;
bool moving = false;
public bool Building = false;
public bool selected = false;
public bool CoolingDown = false;
public double CoolDown = .2;
public double original = .2;
MeshRenderer RenderMesh;
MeshRenderer RenderMeshParent;
SkinnedMeshRenderer[] skinnedMeshRenderersScan;
public List<SkinnedMeshRenderer> skinnedMeshRenderersList = new
List<SkinnedMeshRenderer>();
// Use this for initialization
void Start()
{
RenderMesh = GetComponentInChildren<MeshRenderer>();
RenderMeshParent = GetComponentInParent<MeshRenderer>();
skinnedMeshRenderersScan = GetComponentsInChildren<SkinnedMeshRenderer> ();
foreach (SkinnedMeshRenderer element in skinnedMeshRenderersScan) //For every object it finds
{
if (!skinnedMeshRenderersList.Contains(element)) //If it isn't already in this list
{
skinnedMeshRenderersList.Add(element); //Add to the list
}
}
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButton(0))
{
if (CoolingDown == false) //If not cooling down
{
SetTargetPosition();
CoolingDown = true; //Set cooling down to true
}
}
if (CoolingDown == true)
{
CoolDown -= Time.deltaTime; //Takes some time away
if (CoolDown <= 0) //Checks if the cooldown is done yet
{
CoolingDown = false; //Sets cooling down to false
CoolDown = original; //Cooldown timer is reset by equalling its original value
}
}
if (moving)
Move();
}
void SetTargetPosition()
{
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, Mathf.Infinity))
{
if (hit.collider.CompareTag("Hittable") == true && selected == true)
{
targetPosition = hit.point;
lookAtTarget = new Vector3(targetPosition.x - transform.position.x,
transform.position.y,
targetPosition.z - transform.position.z);
playerRot = Quaternion.LookRotation(lookAtTarget);
moving = true;
}
if (hit.collider.CompareTag("Unit") == true)
{
Fighting self = GetComponentInChildren<Fighting>();
Fighting other = hit.collider.gameObject.GetComponentInChildren<Fighting>();
PlayerMaster playcheck = GetComponent<PlayerMaster>();
if (CoolingDown == false) //If not cooling down
{
if (gameObject.name == hit.collider.name)
{
if (selected == false)
{
selected = true;
RenderMesh.enabled = !RenderMesh.enabled;
}
else if (selected == true)
{
selected = false;
RenderMesh.enabled = !RenderMesh.enabled;
}
}
CoolingDown = true; //Set cooling down to true
}
}
}
}
}
void Move()
{
if (Building == false)
{
transform.rotation = Quaternion.Slerp(transform.rotation,
playerRot,
rotSpeed * Time.deltaTime);
transform.position = Vector3.MoveTowards(transform.position,
targetPosition,
speed * Time.deltaTime);
if (transform.position == targetPosition)
moving = false;
}
}
void OnMouseEnter()
{
Debug.Log("Mouse Entered");
foreach (SkinnedMeshRenderer element in skinnedMeshRenderersScan) //For every object it finds
{
Debug.Log("Detected: " + element);
Debug.Log("Detected Color: " + selectedColor);
element.material.color = selectedColor;
}
}
void OnMouseExit()
{
Debug.Log("Mouse Left");
foreach (SkinnedMeshRenderer element in skinnedMeshRenderersScan) //For every object it finds
{
//Debug.Log("Detected: " + element);
//Debug.Log("Detected Color: " + deselectedColor);
element.material.color = deselectedColor;
}
}
}
To recap, the expected result is that the second object (Or more) would work the same way the first object does.
In practice, it does not.
I was able to fix this issue by putting the scans in the awake() method.
I am trying to detect if colors are matched (2x2) in Unity2D, but it doesn't fully work. I have 16 tiles with 4 different colors.
I am detecting if the colors are matched with a script, which is attached to each collider which collides with 4 tiles around it. In front of each colider is a button, which rotates the 4 tiles around that button (collider) to the right. The scripts of the colliders have a list called childTiles. The list contains the 4 tiles around that collider, to detect if there are 4 tiles of the same color in one list. It looks like this. (GIF) https://gyazo.com/a2a5c8a5051e937338807fb5ecfaa4ec
This script is attached to each collider. There are 9 colliders in total (each one behind a button).
public GameObject GameManager;
public List<GameObject> ChildTiles = new List<GameObject>();
public GameObject[] ParentPositions;
//public GameObject Tiles;
public bool canTurn = true;
private TileController parentPositions;
private float _rotationDegrees;
private GameManager gameManager;
public Color Green;
public Color Red;
public Color Blue;
public Color Yellow;
public bool greenComplete = false;
public bool redComplete = false;
public bool blueComplete = false;
public bool yellowComplete = false;
public GameObject Topleft; //colliders (only these colliders are necessary out of the 9)
public GameObject Topright;
public GameObject Bottomleft;
public GameObject Bottomright;
public GameObject tileGreen1;
public GameObject tileRed1;
public GameObject tileBlue1;
public GameObject tileYellow1;
void Awake()
{
if (gameObject.name == "Top-left" || gameObject.name == "Top-right" || gameObject.name == "Bottom-left" || gameObject.name == "Bottom-right")
{
Green = tileGreen1.GetComponent<SpriteRenderer> ().color;
Red = tileRed1.GetComponent<SpriteRenderer> ().color;
Blue = tileBlue1.GetComponent<SpriteRenderer> ().color;
Yellow = tileYellow1.GetComponent<SpriteRenderer> ().color;
}
GameManager = GameObject.Find ("GameManager");
//Tiles = GameObject.Find ("Tiles");
ParentPositions = GameObject.FindGameObjectsWithTag ("Position");
}
void Update()
{
greenComplete = parentPositions.greenComplete;
redComplete = parentPositions.redComplete;
blueComplete = parentPositions.blueComplete;
yellowComplete = parentPositions.yellowComplete;
}
void Start()
{
gameManager = GameManager.GetComponent<GameManager> ();
_rotationDegrees = 0f;
foreach (GameObject go in ParentPositions)
{
parentPositions = go.GetComponent<TileController> ();
}
}
public void SquareClicked()
{
if (parentPositions.canTurn == true && gameManager.turns > 0f)
{
gameManager.turns -= 1;
gameManager.turnsText.text = "Turns: " + gameManager.turns;
foreach(GameObject go in ParentPositions)
{
parentPositions = go.GetComponent<TileController> ();
parentPositions.canTurn = false;
}
foreach(GameObject tile in ChildTiles)
{
tile.transform.parent = gameObject.transform;
}
StartCoroutine(Rotate()); //this is where you do the rotation of the parent object.
if (gameManager.turns == 0f)
{
gameManager.turnsText.text = "No turns left";
}
}
}
IEnumerator Rotate()
{
LeanTween.rotateZ (gameObject, _rotationDegrees - 90f, 0.5f);
_rotationDegrees -= 90f;
if (_rotationDegrees == -360f)
{
_rotationDegrees = 0f;
}
yield return new WaitForSeconds (0.5f);
parentPositions.canTurn = true;
yield return new WaitForSeconds (0.5f);
if (parentPositions.greenComplete == false)
{
parentPositions.greenComplete = parentPositions.ChildTiles.All (t => t.GetComponent<SpriteRenderer> ().color == Green);
}
if (parentPositions.redComplete == false)
{
parentPositions.redComplete = parentPositions.ChildTiles.All (t => t.GetComponent<SpriteRenderer> ().color == Red);
}
if (parentPositions.blueComplete == false)
{
parentPositions.blueComplete = parentPositions.ChildTiles.All (t => t.GetComponent<SpriteRenderer> ().color == Blue);
}
if (parentPositions.yellowComplete == false)
{
parentPositions.yellowComplete = parentPositions.ChildTiles.All (t => t.GetComponent<SpriteRenderer> ().color == Yellow);
}
Debug.Log ("_greenComplete " + parentPositions.greenComplete);
Debug.Log ("_redComplete " + parentPositions.redComplete);
Debug.Log ("_blueComplete " + parentPositions.blueComplete);
Debug.Log ("_yellowComplete " + parentPositions.yellowComplete);
if (parentPositions.greenComplete && parentPositions.redComplete && parentPositions.blueComplete && parentPositions.yellowComplete)
{
Debug.Log ("Level Complete");
}
}
void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject.tag == "Tile")
{
ChildTiles.Add (col.gameObject);
}
}
void OnTriggerExit2D(Collider2D col)
{
if (col.gameObject.tag == "Tile")
{
ChildTiles.Remove (col.gameObject);
}
}
As you can see in the GIF, there is a problem. The problem is that when there are 4 colors matched, it doesn't return True. It only returns True if you click a button with 4 tiles of the same color around it. Only then it returns True. So you match 4 colors, it doesn't return True, you click the button with those 4 colors around it, it returns True. How do I make it so that it immediately returns True, if 4 colors are matched? As you can see I only use the top-left, top-right, bottom-left and bottom-right collider, as these are the only possible colliders to have 4 tiles with the same color in them at the same time.