- Home /
Randomly Choosing two objects from an array and switching their positions
I have a 6x9 grid of tiles, I want it so every 2-5 seconds two random tiles switch positions, I have the array set up and the invokerepear method but I do not know how to randomly select two objects from the array in the grid and switch their positions.
This is what I have far
public GameObject _indicator;//The indicator to know the selected tile
public GameObject[,] _arrayOfShapes;//The main array that contain all games tiles
private GameObject _currentIndicator;//The current indicator to replace and destroy each time the player change the selection
private GameObject _FirstObject;//The first object selected
private GameObject _SecondObject;//The second object selected
public GameObject [] _listOfGems;//The list of tiles we can see in the game
public int _gridWidth;//the grid number of cell horizontally
public int _gridHeight;//the grid number of cell vertically
// Use this for initialization
void Start () {
//Initializing the array with _gridWidth and _gridHeight passed in parameter
_arrayOfShapes = new GameObject[_gridWidth, _gridHeight];
//Creating the gems from the list of gems passed in parameter
for ( int i = 0; i <= _gridWidth-1; i++){
for ( int j = 0; j <= _gridHeight-1; j++){
var gameObject = GameObject.Instantiate(_listOfGems[Random.Range(0, _listOfGems.Length)] as GameObject, new Vector3(i, j, 0), transform.rotation) as GameObject;
_arrayOfShapes[i,j]= gameObject;
}
}
//Adding the star effect to the gems and call the DoShapeEffect continuously
InvokeRepeating("DoShapeEffect", 1f, 0.21F);
}
void Shuffle ()
{
}
// Update is called once per frame
void Update () {
InvokeRepeating ("Shuffle", 2, Random.Range(2,5));
By switching position,do you mean to switch the transform.position of the object in the array to each other or the location of the object in the array...?
Answer by calebheale · Jul 24, 2014 at 06:50 AM
// to pick random elements
int x1, y1, x2, y2;
x1 = Random.Range(0, _arrayOfShapes.GetLength(0));
x2 = Random.Range(0, _arrayOfShapes.GetLength(0));
y1 = Random.Range(0, _arrayOfShapes.GetLength(1));
y2 = Random.Range(0, _arrayOfShapes.GetLength(1));
// to swap array positions
GameObject temp = _arrayOfShapes[x1, y1];
_arrayOfShapes[x1, y1] = _arrayOfShapes[x2, y2];
_arrayOfShapes[x2, y2] = temp;
// OR to swap physical locations
Vector3 temp = _arrayOfShapes[x1, y1].transform.position;
_arrayOfShapes[x1, y1].transform.position = _arrayOfShapes[x2, y2].transform.position;
_arrayOfShapes[x2, y2].transform.position = temp;
$$anonymous$$eep in $$anonymous$$d that this has a possibility of choosing the same element for both. This shouldn't cause any exceptions or other issues other than the fact that every once in a while it will just appear that nothing switched. If you want to insure that it will never pick the same element you could do:
int x1, y1, x2, y2;
x1 = Random.Range(0, _arrayOfShapes.GetLength(0));
y1 = Random.Range(0, _arrayOfShapes.GetLength(1));
do {
x2 = Random.Range(0, _arrayOfShapes.GetLength(0));
y2 = Random.Range(0, _arrayOfShapes.GetLength(1));
} while(x1 == x2 && y1 == y2);
Both are valid solutions. Just depends on exactly what functionality you are going for.
So the tiles now randomly switch however, my game is a $$anonymous$$atch-3 game, so while it looks like the tiles swap positions they don't actually swap positions, it still thinks that the tile is in its original position, is there a way to fix this? I've been looking over my entire script and I can't think of a way to fix
If you are checking for matches by iterating through the array you may need to use both the swap for the positions in the array AND the physical positions. Is that what you are doing? If that doesn't help you please post some code.
I thought to do that but was not sure how exactly to combine them together and I posted some more code in another comment due the character limit and thanks for all the help again!
i also get this error while I'm playing the game
The object of type 'GameObject' has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object.
Answer by smallbit · Jul 24, 2014 at 06:50 AM
Little code like this, not tested but should work:
void Shuffle()
{
//get random coordinates for both elements
int x1 = Random.Range(0,_arrayOfShapes.GetLength(0)-1);
int y1 = Random.Range(0,_arrayOfShapes.GetLength(1)-1);
int x2 = Random.Range(0,_arrayOfShapes.GetLength(0)-1);
int y2 = Random.Range(0,_arrayOfShapes.GetLength(1)-1);
//if by any luck the point to the same element start over
if(_arrayOfShapes[x1,y1] == _arrayOfShapes[x2,y2])
{
Shuffle();
}
else
{
//if they are different swap
//create tmp gameobject and save first element there
GameObject tmp = _arrayOfShapes[x1,y1];
//replace first element by seconds
_arrayOfShapes[x1,y1] = _arrayOfShapes[x2,y2];
//copy first elemtn tmp to second
_arrayOfShapes[x2,y2] = tmp;
}
} // Update is called once per fr
If you want to swap (move the gameobjects) you might do something like this
//if they are different swap
//create tmp gameobject and save first element there
Vector3 tmp = _arrayOfShapes[x1,y1].transform.position;
//replace first element by seconds
_arrayOfShapes[x1,y1].transform.position = _arrayOfShapes[x2,y2].transform.position;
//copy first elemtn tmp to second
_arrayOfShapes[x2,y2].transform.position = tmp;
Wow. We posted almost the exact same solution at almost the exact same time... eerie.
Also, I don't think you want the (-1)'s on the range because the upper bounds is already exclusive.
all your guys answers worked great thanks!! wish I could pick all of them
Answer by RNVitter · Jul 25, 2014 at 04:47 AM
Here is the next part of the code after the part I've already posted
void Shuffle ()
{
x1 = Random.Range(0, _arrayOfShapes.GetLength(0));
x2 = Random.Range(0, _arrayOfShapes.GetLength(0));
y1 = Random.Range(0, _arrayOfShapes.GetLength(1));
y2 = Random.Range(0, _arrayOfShapes.GetLength(1));
Vector3 temp = _arrayOfShapes[x1, y1].transform.position;
_arrayOfShapes[x1, y1].transform.position = _arrayOfShapes[x2, y2].transform.position;
_arrayOfShapes[x2, y2].transform.position = temp;
}
// Update is called once per frame
void Update () {
bool shouldTransit = false;
//Detecting if the player clicked on the left mouse button and also if there is no animation playing
if (Input.GetButtonDown ("Fire1") && HOTween.GetTweenInfos()==null) {
Destroy(_currentIndicator);
//The 3 following lines is to get the clicked GameObject and getting the RaycastHit2D that will help us know the clicked object
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
if (hit.transform!=null)
{ //To know if the user already selected a tile or not yet
if ( _FirstObject == null ) _FirstObject = hit.transform.gameObject;
else {_SecondObject= hit.transform.gameObject;
shouldTransit= true ; }
_currentIndicator = GameObject.Instantiate (_indicator,new Vector3( hit.transform.gameObject.transform.position.x,hit.transform.gameObject.transform.position.y,-1), transform.rotation) as GameObject ;
//If the user select the second tile we will swap the two tile and animate them
if (shouldTransit)
{
//Getting the position between the 2 tiles
var distance = _FirstObject.transform.position - _SecondObject.transform.position;
//Testing if the 2 tiles are next to each others otherwise we will not swap them
if (Mathf.Abs(distance.x) <= 1 && Mathf.Abs(distance.y) <= 1)
{ //If we dont want the player to swap diagonally
if (!_canTransitDiagonally )
{
if (distance.x != 0 && distance.y != 0)
{
Destroy(_currentIndicator);
_FirstObject = null;
_SecondObject = null;
return;
}
}
//Animate the transition
DoSwapMotion(_FirstObject.transform, _SecondObject.transform);
//Swap the object in array
DoSwapTile(_FirstObject, _SecondObject, ref _arrayOfShapes);
}
else
{
_FirstObject = null;
_SecondObject = null;
}
Destroy(_currentIndicator);
}
}
}
}
// Find Match-3 Tile
private ArrayList FindMatch(GameObject[,] cells)
{//creating an arraylist to store the matching tiles
ArrayList stack = new ArrayList();
//Checking the vertical tiles
for (var x = 0; x <= cells.GetUpperBound(0); x++)
{
for (var y = 0; y <= cells.GetUpperBound(1); y++)
{
var thiscell = cells[x, y];
//If it's an empty tile continue
if (thiscell.name == "Empty(Clone)") continue;
int matchCount = 0;
int y2 = cells.GetUpperBound(1);
int y1;
//Getting the number of tiles of the same kind
for (y1 = y + 1; y1 <= y2; y1++)
{
if (cells[x, y1].name == "Empty(Clone)" || thiscell.name != cells[x, y1].name) break;
matchCount++;
}
//If we found more than 2 tiles close we add them in the array of matching tiles
if (matchCount >= 2)
{
y1 = Mathf.Min(cells.GetUpperBound(1) , y1 - 1);
for (var y3 = y; y3 <= y1; y3++)
{
if (!stack.Contains(cells[x, y3]))
{
stack.Add(cells[x, y3]);
}
}
}
}
}
//Checking the horizontal tiles , in the following loops we will use the same concept as the previous ones
for (var y = 0; y < cells.GetUpperBound(1) + 1; y++)
{
for (var x = 0; x < cells.GetUpperBound(0) + 1; x++)
{
var thiscell = cells[x, y];
if (thiscell.name == "Empty(Clone)") continue;
int matchCount = 0;
int x2 = cells.GetUpperBound(0);
int x1;
for (x1 = x + 1; x1 <= x2; x1++)
{
if (cells[x1, y].name == "Empty(Clone)" || thiscell.name != cells[x1, y].name) break;
matchCount++;
}
if (matchCount >= 2)
{
x1 = Mathf.Min(cells.GetUpperBound(0), x1 - 1);
for (var x3 = x; x3 <= x1; x3++)
{
if (!stack.Contains(cells[x3, y]))
{
stack.Add(cells[x3, y]);
}
}
}
}
}
return stack;
}
// Swap Motion Animation, to animate the switching arrays
void DoSwapMotion(Transform a, Transform b)
{
Vector3 posA = a.localPosition;
Vector3 posB = b.localPosition;
TweenParms parms = new TweenParms().Prop("localPosition", posB).Ease(EaseType.EaseOutQuart);
HOTween.To(a, 0.25f, parms).WaitForCompletion();
parms = new TweenParms().Prop("localPosition", posA).Ease(EaseType.EaseOutQuart);
HOTween.To(b, 0.25f, parms).WaitForCompletion();
}
// Swap Two Tile, it swaps the position of two objects in the grid array
void DoSwapTile(GameObject a, GameObject b, ref GameObject[,] cells)
{
GameObject cell = cells[(int)a.transform.position.x, (int)a.transform.position.y];
cells[(int)a.transform.position.x, (int)a.transform.position.y] = cells[(int)b.transform.position.x, (int)b.transform.position.y];
cells[(int)b.transform.position.x, (int)b.transform.position.y] = cell;
}
I don't fully understand exactly what you are doing (honestly, I'm being a bit lazy because it is a lot of code). It does look like you are iterating the array to find matches though, which means my previous guess should be correct, in that you need to swap both the array positions and physical positions. I would also highly recommend that you leave out any animation logic until you get the basics working. It makes it much too difficult to debug.
I don't understand what the need is for _currentIndicator but since that is the only thing that I can see that you are destroying, I'm guessing that is where the other error is co$$anonymous$$g from.
Were you not able to append this to your original question? It is typically frowned upon to post something that isn't an answer as an answer and you could likely get downvotes from it.
found a different way to swap array and physical position now I just have to figure out why random tiles get deleted. Thanks for the help!
Those nested If statements are pretty dicey...I feel like some of that should be unpacked into functions calls so it's easier to read, that is probably half the problem...as far as debugging the deleted object thing, use Debug.log to trace what is going on with those nested if's.