Hey all, I think I’m being really stupid here, I need some help. Tried trawling the forums but just got more confused!
I have one hundred prefabs with a grey border.
I have objects that you can drag and drop in a layer above these prefabs.
If the object collides with any of the prefabs it turns the outline of that prefab red by referencing a function attached to the script OF THE PREFAB.
After you pick up an object the prefabs run the check again and turn their outlines back to green if there’s nothing on top of them.
When trying to drop an object, the object’s own code checks for any red outlined prefabs below it and if they are detected it doesn’t let you drop it.
This code works beautifully! Here’s my problem:
I tried to do what I thought was super simple, instead of changing the colour of the outline, I created a public variable in the script attached to the prefab to set a bool
ean to true
or false
instead of setting the outline to red or green. HOWEVER, when the script inside my moveable object tries to check this variable through .GetComponent<CellManager>().Cell_Occupied == true)
it always returns false, even when the value is actually true. Note if I instead use the same code, but with .GetComponent<Outline>().effectColor == Color.red)
instead of the above, it works every time. What am I doing wrong?
I’m sure I’m screwing up something really simple with the way I’m trying to look up the variable or the syntax I’m using. Please can you help a noob out?
This is the first bit of code, inside my CellManager
this script is attached to all 100 prefabs
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using UnityEngine;
using UnityEngine.UI;
public class CellManager : MonoBehaviour
{
[SerializeField] public bool Cell_Occupied;
// Start is called before the first frame update
void Start()
{
for (int i = 1; i < 101; i++)
{
CellStatusSetter("Cell1 (" + i + ")");
}
}
//Identify whether cell is free and turn outline green or red accordingly
public void CellStatusSetter(string myString)
{
GameObject myCell = GameObject.Find(myString);
Collider2D _collider = myCell.GetComponent<Collider2D>();
ContactFilter2D _filter = new ContactFilter2D().NoFilter();
List<Collider2D> _results = new List<Collider2D>();
Physics2D.OverlapCollider(_collider, _filter, _results);
if (Physics2D.OverlapCollider(_collider, _filter, _results) > 0)
{
//only used for debugging// myCell.GetComponent<Outline>().effectColor = Color.red;
Cell_Occupied = true;
Debug.Log("Cell set to occupied:" + myCell.name);
}
else
{
//only used for debugging// myCell.GetComponent<Outline>().effectColor = Color.green; // only used for debugging
Cell_Occupied = false;
Debug.Log("Cell set to free:" + myCell.name);
}
}
}
This is the second script. It’s attached to my moveable objects, sorry, I know there’s probably loads wrong with it - it’s my first attempt at unity / C#! Note you can search for the part where it says ‘color’ to find the places where I switch out my ‘true/false’ check for an ‘outline.color’ check. if I comment out the true false check and uncomment the ‘outline.color’ check, the code works just as intended…
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Security;
using Unity.VisualScripting;
using UnityEditor;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityEngine.UIElements;
using static Unity.IO.LowLevel.Unsafe.AsyncReadManagerMetrics;
public class DraggableItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
Transform parentAfterDrag;
Vector2 originalLocation;
int originalOrientation = 1;
string _startingCellName = "Cell1 (1)";
string _desiredCellName = "Cell1 (1)";
public CellManager cellManager;
public List<Collider2D> _objectStartingCells = new List<Collider2D>();
float _objxSize = 0;
float _objySize = 0;
int _objSize = 0;
int x_adjustor = 0;
int y_adjustor = 0;
int thisCellNum = 0;
[SerializeField] int _objRotation = 1;
//Set an identifier to store if an object is currently selected by the user
bool objSelected = false;
//Begin dragging item on click
public void OnBeginDrag(PointerEventData eventData)
{
//Mark object as currently selected
objSelected = true;
//Save original location & orientation
originalLocation = transform.position;
originalOrientation = _objRotation;
//store names of all collided cells before moving
Collider2D _objectCollider = GetComponent<Collider2D>();
ContactFilter2D _objectFilter = new ContactFilter2D().NoFilter();
Physics2D.OverlapCollider(_objectCollider, _objectFilter, _objectStartingCells);
//Start dragging
parentAfterDrag = transform.parent;
transform.SetParent(transform.root);
transform.SetAsLastSibling();
//Pick up object
transform.position = Input.mousePosition;
//Mark originally occupied cells as free
_objSize = _objectStartingCells.Count;
for (int i = 0; i < _objSize; i++)
{
// only used for debugging// _objectStartingCells[i].GetComponent<Outline>().effectColor = Color.green;
_objectStartingCells[i].GetComponent<CellManager>().Cell_Occupied = false;
}
}
//Drag object and rotate if q or e is pressed
public void OnDrag(PointerEventData eventData)
{
transform.position = Input.mousePosition;
}
//Place object
public void OnEndDrag(PointerEventData eventData)
{
//Unmark object as selected
objSelected = false;
string _flagResetPos = "not set";
transform.SetParent(parentAfterDrag);
//Align object with cells
//Get cells currently overlapping
int _gridSizex = 10;
int _gridSizey = 10;
Collider2D _objectCollider = GetComponent<Collider2D>();
ContactFilter2D _objectFilter = new ContactFilter2D().NoFilter();
List<Collider2D> _objectResults = new List<Collider2D>();
Physics2D.OverlapCollider(_objectCollider, _objectFilter, _objectResults);
//Create a coroutine to check cells (but only trigger it after an object has been moved
IEnumerator ResetCells()
{
//trigger collider on object to register which cells it's collided with
Collider2D _objCollider = GetComponent<Collider2D>();
ContactFilter2D _objFilter = new ContactFilter2D().NoFilter();
List<Collider2D> _objResults = new List<Collider2D>();
Physics2D.OverlapCollider(_objCollider, _objFilter, _objResults);
int indexer = 0;
foreach (Collider2D col in _objResults)
{
if (col.tag == "Inv_Cell")
{
cellManager.CellStatusSetter(col.name);
}
indexer += 1;
}
yield return new WaitForSeconds(0.1f);
}
//Create coroutine to revert back to original location and then reset cells after moving
IEnumerator BasicReset()
{
transform.position = originalLocation;
//if object has been rotated, rotate it back
if (_objRotation != originalOrientation)
{
transform.Rotate(Vector3.forward * 90 * _objRotation);
//Flip the identifier to show object is now back to original orientation
_objRotation = -_objRotation;
}
yield return new WaitForSeconds(0.1f);
yield return StartCoroutine(ResetCells());
}
if (Physics2D.OverlapCollider(_objectCollider, _objectFilter, _objectResults) > 0)
{
int noOfcollisions = _objectResults.Count;
//store positions of all collided cells
float _shortestDistance = 1000;
Vector2 _desiredLocation = originalLocation;
//Get standard cell size for scaling
float stdCellSize = GameObject.Find("Cell1 (1)").GetComponent<BoxCollider2D>().size.x;
//Get raw width and height of object, note these are swapped if object is rotated.
if (_objRotation == 1)
{
_objxSize = GetComponent<BoxCollider2D>().size.x;
_objySize = GetComponent<BoxCollider2D>().size.y;
}
else
{
_objxSize = GetComponent<BoxCollider2D>().size.y;
_objySize = GetComponent<BoxCollider2D>().size.x;
}
//Scale these values based on cell dimensions
int _scaledObjxSize = Mathf.RoundToInt(_objxSize / stdCellSize);
int _scaledObjySize = Mathf.RoundToInt(_objySize / stdCellSize);
//Create 2 arrays to hold references to the x and y offsets of each cell in the object
int[] arr_xAxisComponents = new int[_scaledObjxSize];
int[] arr_yAxisComponents = new int[_scaledObjySize];
for (int i = 0; i < _scaledObjxSize; i++)
{
arr_xAxisComponents[i] = i;
}
for (int i = 0; i < _scaledObjySize; i++)
{
arr_yAxisComponents[i] = i;
}
StartCoroutine(doMove());
IEnumerator doMove()
{
yield return setObjectMoveFlags();
}
IEnumerator setObjectMoveFlags()
{
for (int i = 0; i < noOfcollisions; i++)
{
//set a flag that allows us to move on to next iteration if an issue is found
bool breakflag = false;
Debug.Log("Checking collision with: " +_objectResults[i].name);
if (_objectResults[i].tag == "Inv_Cell")
{
Debug.Log(_objectResults[i].name + " is occupied? " + GameObject.Find(_objectResults[i].name).GetComponent<CellManager>().Cell_Occupied);
Debug.Log("Let's check " +_objectResults[i].name + " a different way! " + GameObject.Find(_objectResults[i].name).GetComponent<CellManager>().Cell_Occupied);
}
//If colliding with any object other than a cell set a reset flag unless another empty cell can be found
if (_objectResults[i].tag != "Inv_Cell")
{
if (_flagResetPos == "not set")
{
breakflag = true;
_flagResetPos = "reset";
}
}
//Only consider cell if it is free
//only used for debugging// else if (GameObject.Find(_objectResults[i].name).GetComponent<Outline>().effectColor == Color.green)
else if (GameObject.Find(_objectResults[i].name).GetComponent<CellManager>().Cell_Occupied == false)
{
Debug.Log(_objectResults[i].name +" found to be unoccupied");
//Calculate distance from cell position to centre of object
float _xDistance = Mathf.Abs(transform.position.x) - Mathf.Abs(_objectResults[i].transform.position.x);
float _yDistance = transform.position.y - _objectResults[i].transform.position.y;
float _objectDistance = Mathf.Sqrt(Mathf.Pow(_xDistance, 2) + Mathf.Pow(_yDistance, 2));
//Calculate distance from mouse pointer to the cell to find the closest cell that is also free
if (_objectDistance < _shortestDistance)
{
//Work out which direction we're moving - this will be used for object snapping later
if (_xDistance < 0)
{
x_adjustor = -1; //Original value for 10x10 grid = -1
}
else
{
x_adjustor = 1; //Original value for 10x10 grid = 1
}
if (_yDistance < 0)
{
y_adjustor = _gridSizex; //Original value for 10x10 grid = 10
}
else
{
y_adjustor = -_gridSizex; //Original value for 10x10 grid = -10
}
StartCoroutine(checkMoveandSetLoc());
IEnumerator checkMoveandSetLoc()
{
yield return checkObjectMoveisValid();
}
IEnumerator checkObjectMoveisValid()
{
//if object is larger than 1 cell, check surrounding cells to make sure they are free before continuing
if (_scaledObjxSize > 1 || _scaledObjySize > 1)
{ //start troubleshooting sensitive 3x2 in top left corner here.
//Debug.Log("i = " + i +" Inspected cell = " +_objectResults[i].name);
//Get number of target cell so we can easily check surrounding cells
string[] arr_thisCellName = _objectResults[i].name.Split("(");
string thisCellNumString = arr_thisCellName[1];
string[] arr_thisCellNumString = thisCellNumString.Split(")");
thisCellNum = int.Parse(arr_thisCellNumString[0]);
//Check if cell is close to left border (automatically discount if target cell is rightmost cell)
if (thisCellNum % _gridSizey != 0 && (thisCellNum % _gridSizey) <= Mathf.FloorToInt(_scaledObjxSize / 2))
{
//If cell is close to left border, now do a specific check, based on x_adjustor, to see whether object would overlap border. Flip to each side of centerpoint of object to check both sides.
for (int j = 0; j < _scaledObjxSize; j++)
{
//formula if on an even iteration
if (j % 2 == 0)
{
if (((thisCellNum % _gridSizey) + (x_adjustor * Mathf.FloorToInt(((j + 1) / 2)))) < 1)
{
Debug.Log("Object cannot be placed in cell " + thisCellNum + " because of a collision with the left border");
_flagResetPos = "reset";
breakflag = true;
}
}
//formula if on an odd iteration
else
{
if (((thisCellNum % _gridSizey) + (-1*x_adjustor * Mathf.FloorToInt(((j + 1) / 2)))) < 1)
{
Debug.Log("Object cannot be placed in cell " + thisCellNum + " because of a collision with the left border");
_flagResetPos = "reset";
breakflag = true;
}
}
}
}
//check if cell is close to right border
if (thisCellNum % _gridSizey + Mathf.FloorToInt(_scaledObjxSize / 2) > _gridSizex || thisCellNum % _gridSizex == 0)
{
//If cell is close to right border, now do a specific check, based on x_adjustor, to see whether object would overlap border. Flip to each side of centerpoint of object to check both sides.
for (int j = 0; j < _scaledObjxSize; j++)
{
int _thisCellx = (thisCellNum % _gridSizey);
//if target cell is right on the border replace remainder of zero with max value.
if (thisCellNum % _gridSizey == 0)
{
_thisCellx = _gridSizey;
}
//formula if on an even iteration
if (j % 2 == 0)
{
if ((_thisCellx + (-1 * x_adjustor * Mathf.FloorToInt((j+1) / 2))) > _gridSizex)
{
Debug.Log("Object cannot be placed in cell " + thisCellNum + " because of a collision with the right border");
_flagResetPos = "reset";
breakflag = true;
}
}
//formula if on an odd iteration
else
{
if ((_thisCellx + (x_adjustor * Mathf.FloorToInt((j + 1) / 2))) > _gridSizex)
{
Debug.Log("Object cannot be placed in cell " + thisCellNum + " because of a collision with the right border");
_flagResetPos = "reset";
breakflag = true;
}
}
}
}
//Check if cell is close to top border
if (((float)thisCellNum / (float)_gridSizex) <= Mathf.FloorToInt(_scaledObjySize / 2))
{
//If cell is close to top border, now do a specific check, based on y_adjustor, to see whether object would overlap border. Flip to each side of centerpoint of object to check both sides.
for (int j = 0; j < _scaledObjySize; j++)
{
//formula if on an even iteration
if (j % 2 == 0)
{
Debug.Log("Object cannot be placed in cell " + thisCellNum + " because of a collision with the top border");
if ((((float)thisCellNum / (float)_gridSizex) + (1 * y_adjustor * Mathf.FloorToInt(((j + 1) / 2)))) < 1)
{
_flagResetPos = "reset";
breakflag = true;
}
}
//formula if on an odd iteration
else
{
Debug.Log("Object cannot be placed in cell " + thisCellNum + " because of a collision with the top border");
if ((((float)thisCellNum / (float)_gridSizex) + (-y_adjustor * Mathf.FloorToInt(((j + 1) / 2)))) > _gridSizex)
{
_flagResetPos = "reset";
breakflag = true;
}
}
}
}
//Check if cell is close to bottom border
if ((_gridSizey - Mathf.CeilToInt((float)thisCellNum / (float)_gridSizex)) < Mathf.FloorToInt(_scaledObjySize / 2))
{
//If cell is close to bottom border, now do a specific check, based on y_adjustor, to see whether object would overlap border. Flip to each side of centerpoint of object to check both sides.
for (int j = 0; j < _scaledObjySize; j++)
{
//formula if on an even iteration
if (j % 2 == 0)
{
if ((((float)thisCellNum / (float)_gridSizex) + (-1 * y_adjustor * Mathf.FloorToInt((j + 1) / 2))) > _gridSizey)
{
Debug.Log("Object cannot be placed in cell " + thisCellNum + " because of a collision with the bottom border");
_flagResetPos = "reset";
breakflag = true;
}
}
//formula if on an odd iteration
else
{
if ((((float)thisCellNum / (float)_gridSizex) + (y_adjustor * Mathf.FloorToInt((j + 1) / 2))) > _gridSizey)
{
Debug.Log("Object cannot be placed in cell " + thisCellNum + " because of a collision with the bottom border");
_flagResetPos = "reset";
breakflag = true;
}
}
}
}
//Now check if object collides with any taken cells
foreach (int j in arr_xAxisComponents)
{
//Break out of this loop too if break flag is set
if (breakflag == true)
{
break;
}
foreach (int k in arr_yAxisComponents)
{
//Identify the cell to be checked next
//if on an odd iteration of the x or y value, flip the direction you are checking on (to check either side of the centre of the object) - note when both are zero, this is only checking the target cell
if (j % 2 != 0)
{
//Formula if on an even x & y coordinates
if (k % 2 != 0)
{
GameObject nextCell = GameObject.Find("Cell1 (" + (thisCellNum + (x_adjustor * j) + (y_adjustor * k)) + ")");
//Check if overlapping cell is taken
//only used for debugging// if (nextCell.GetComponent<CellManager>().Cell_Occupied == true)
if (nextCell.GetComponent<Outline>().effectColor == Color.red)
{
Debug.Log("Object cannot be placed in cell " + thisCellNum + " because of a collision with cell: " + ((x_adjustor * j) + (y_adjustor * k)));
//set a break flag to escape loop if finding a clash
breakflag = true;
_flagResetPos = "reset";
break;
}
}
//Formula if on an even x cooordinate and an odd y cooordinate
else
{
GameObject nextCell = GameObject.Find("Cell1 (" + (thisCellNum + (x_adjustor * j) + (y_adjustor * (k / -2))) + ")");
//Check if overlapping cell is taken
//only used for debugging// if (nextCell.GetComponent<Outline>().effectColor == Color.red)
if (nextCell.GetComponent<CellManager>().Cell_Occupied == true)
{
Debug.Log("Object cannot be placed in cell (x even y odd) " + thisCellNum + " because of a collision with cell: " + (thisCellNum + (x_adjustor * j) + (y_adjustor * (k / -2))) +" height that I think the object is: " +_scaledObjySize);
Debug.Log("Cell in checking array = " + _objectResults[i].name +" j = " + j +" k = " +k);
//set a break flag to escape loop if finding a clash
breakflag = true;
_flagResetPos = "reset";
break;
}
}
}
else
{
//formula if on an odd x cooordinate and an even y coordinate
if (k % 2 != 0)
{
GameObject nextCell = GameObject.Find("Cell1 (" + (thisCellNum + (x_adjustor * (j / -2)) + (y_adjustor * k)) + ")");
//only used for debugging// if (nextCell.GetComponent<Outline>().effectColor == Color.red)
if (nextCell.GetComponent<CellManager>().Cell_Occupied == true)
{
Debug.Log("Object cannot be placed in cell (x odd y even) " + thisCellNum + " because of a collision with cell: " + (thisCellNum + (x_adjustor * (j / -2)) + (y_adjustor * k)) + " height that I think the object is: " + _scaledObjySize);
Debug.Log("Cell in checking array = " + _objectResults[i].name + " j = " + j + " k = " + k);
//set a break flag to escape loop if finding a clash
breakflag = true;
_flagResetPos = "reset";
break;
}
}
//formula if on odd x & y cooordinates
else
{
GameObject nextCell = GameObject.Find("Cell1 (" + (thisCellNum + (x_adjustor * (j / -2)) + (y_adjustor * (k / -2))) + ")");
//only used for debugging// if (nextCell.GetComponent<Outline>().effectColor == Color.red)
if (nextCell.GetComponent<CellManager>().Cell_Occupied == true)
{
Debug.Log("Object cannot be placed in cell (odd x & y) " + thisCellNum + " because of a collision with cell: " + (thisCellNum + (x_adjustor * (j / -2)) + (y_adjustor * (k / -2))));
//set a break flag to escape loop if finding a clash
breakflag = true;
_flagResetPos = "reset";
break;
}
}
}
}
}
}
yield return setDesiredLocation();
}
IEnumerator setDesiredLocation()
{
if (breakflag == false)
{
_flagResetPos = "moved";
_shortestDistance = _objectDistance;
_desiredLocation = _objectResults[i].transform.position;
_desiredCellName = _objectResults[i].name;
}
yield return null;
}
}
}
// if object doesn't collide with any cell, reset position
else
{
if (_flagResetPos == "not set")
{
Debug.Log("No collisions detected");
_flagResetPos = "reset";
}
}
}
yield return moveObject();
}
IEnumerator moveObject()
{
//If destination cell is not free return back to original location
if (_flagResetPos == "reset" || _flagResetPos == "not set")
{
StartCoroutine(BasicReset());
}
//If destination is free, then proceed with snapping
else
{
//Get number of desired cell
string[] arr_thisCellName = _desiredCellName.Split("(");
string thisCellNumString = arr_thisCellName[1];
string[] arr_thisCellNumString = thisCellNumString.Split(")");
thisCellNum = int.Parse(arr_thisCellNumString[0]);
Debug.Log("Agreed to land on:" +_desiredCellName);
//handle snapping of objects of even width
if (_scaledObjxSize % 2 == 0)
{
int nextCellNum = thisCellNum + x_adjustor;
float cellgapx = GameObject.Find("Cell1 (" + nextCellNum + ")").transform.position.x - GameObject.Find("Cell1 (" + thisCellNum + ")").transform.position.x;
float midpointx = GameObject.Find("Cell1 (" + nextCellNum + ")").transform.position.x - (cellgapx / 2);
_desiredLocation.x = midpointx;
}
//handle snapping of objects of even height
if (_scaledObjySize % 2 == 0)
{
int nextCellNum = thisCellNum + y_adjustor;
float cellgapy = GameObject.Find("Cell1 (" + nextCellNum + ")").transform.position.y - GameObject.Find("Cell1 (" + thisCellNum + ")").transform.position.y;
float midpointy = GameObject.Find("Cell1 (" + nextCellNum + ")").transform.position.y - (cellgapy / 2);
_desiredLocation.y = midpointy;
}
//Set up coroutine to make sure object moves before cells are checked
StartCoroutine(MoveAndUpdate());
IEnumerator MoveAndUpdate()
{
//Move object to desired location
yield return StartCoroutine(Move());
}
IEnumerator Move()
{
//Move object to desired location
transform.position = _desiredLocation;
//wait before launching cell check
yield return new WaitForSeconds(0.1f);
yield return StartCoroutine(ResetCells());
}
}
yield return null;
}
}
//if no collisions are detected it means the object was not dropped out of bounds so reset position
else
{
StartCoroutine(BasicReset());
}
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//Only trigger if user presses Q or E AND the object is marked as selected
if ((Input.GetKeyDown(KeyCode.Q) || Input.GetKeyDown(KeyCode.E)) && objSelected)
{
//Work out if mouse is within bounds of object
float _objxLowerBound = transform.position.x - (GetComponent<BoxCollider2D>().size.x / 2);
float _objxUpperBound = transform.position.x + (GetComponent<BoxCollider2D>().size.x / 2);
float _objyLowerBound = transform.position.y - (GetComponent<BoxCollider2D>().size.y / 2);
float _objyUpperBound = transform.position.y + (GetComponent<BoxCollider2D>().size.y / 2);
// if object is already rotated, swap x and y dimensions
if (_objRotation == -1)
{
_objxLowerBound = transform.position.x - (GetComponent<BoxCollider2D>().size.y / 2);
_objxUpperBound = transform.position.x + (GetComponent<BoxCollider2D>().size.y / 2);
_objyLowerBound = transform.position.y - (GetComponent<BoxCollider2D>().size.x / 2);
_objyUpperBound = transform.position.y + (GetComponent<BoxCollider2D>().size.x / 2);
}
//Check mouse is over the object before running
if (Input.GetKey(KeyCode.Mouse0) && _objxLowerBound < Input.mousePosition.x && Input.mousePosition.x < _objxUpperBound && _objyLowerBound < Input.mousePosition.y && Input.mousePosition.y < _objyUpperBound)
{
//Rotate object to alternate orientation
transform.Rotate(Vector3.forward * 90 * _objRotation);
//Flip the identifier showing whether object is in original rotation or rotated 90 degrees
_objRotation = -_objRotation;
}
}
}
}