I have an array of gameObjects which I can deactivate easily with a loop. However I do not want to deactivate one gameObject from the lot. So I am providing an int value which is the position of the gameObject in that array. How do I deactivate others except for this particular object?
public GameObject[] myObjs;
int exceptionObj;
void Start()
{
exceptionObj = 2; //Position of object in the array
for(int i = 0; i<myObjs.Length; i++)
{
myObjs[i].SetActive(false);
}
}
public GameObject[] myObjs;
int exceptionObj;
void Start()
{
exceptionObj = 2; //Position of object in the array
for(int i = 0; i<myObjs.Length; i++)
{
if(exceptionObj != i)
myObjs[i].SetActive(false);
}
}
Or;
public GameObject[] myObjs;
int exceptionObj;
void Start()
{
exceptionObj = 2; //Position of object in the array
for(int i = 0; i<myObjs.Length; i++)
{
if(exceptionObj == i)
continue;
myObjs[i].SetActive(false);
}
}
Or perhaps even by simply reactivating at the end;
public GameObject[] myObjs;
int exceptionObj;
void Start()
{
exceptionObj = 2; //Position of object in the array
for(int i = 0; i<myObjs.Length; i++)
{
myObjs[i].SetActive(false);
}
myObjs[exceptionObj].SetActive(true);
}
Two ways:
With an if:
exceptionObj = 2; //Position of object in the array
for(int i = 0; i<myObjs.Length; i++)
{
if (i != exceptionObj) // If not the exception ID
myObjs[i].SetActive(false);
}
Or with two loops:
exceptionObj = 2; //Position of object in the array
for(int i = 0; i<exceptionObj; i++)
{
myObjs[i].SetActive(false);
}
for(int i = exceptionObj+1; i<myObjs.Length; i++)
{
myObjs[i].SetActive(false);
}
Related
I have some code that is supposed to create a grid of voxels, and then rooms out of those voxels. However, a lot of the rooms still overlap, even when I wrote code specifically to prevent this from happening. Would anybody be able to tell me what's going?
I'm using an out variable for the first time, and I think that's part of the issues.
Basically, the code is supposed to create a list of voxels to turn into a room, turn them into a room, and repeat for the total number of rooms. If a voxel in the list is found to already be a room, it should clear the list and not create a room.
All the relevant code is below, you should be able to plug this into a new Unity project and see for yourself everything, complete with Gizmos.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum VoxelType{
Undefined = 0,
OpenRoom,
OpenHall,
Wall,
Buffer,
}
[System.Serializable]
public class Voxel {
public Vector3 position;
public VoxelType voxelType;
public int voxelX;
public int voxelY;
public Voxel(Vector3 newPosition, int x, int y, VoxelType newType = 0){
position = newPosition;
voxelType = newType;
voxelX = x;
voxelY = y;
}
}
public class VoxelManager : MonoBehaviour
{
public Vector2 mapSize;
public float voxelSize;
public int rooms;
public int maxRoomHeight;
public int minRoomHeight;
public int maxRoomWidth;
public int minRoomWidth;
List<Voxel> voxels = new List<Voxel>();
void OnDrawGizmosSelected(){
foreach(Voxel voxel in voxels){
if (voxel.voxelType == VoxelType.OpenRoom){
Gizmos.color = Color.red;
} else {
Gizmos.color = Color.blue;
}
switch (voxel.voxelType){
case VoxelType.Undefined:
Gizmos.color = Color.blue;
break;
case VoxelType.Wall:
Gizmos.color = Color.magenta;
break;
case VoxelType.OpenRoom:
Gizmos.color = Color.red;
break;
}
Gizmos.DrawCube(voxel.position, Vector3.one * voxelSize *.995f);
}
}
void Start(){
voxelSpawn = prefab;
for(int i = 0; i < mapSize.x; i++){
for (int j = 0; j < mapSize.y; j++){
float xLocation = voxelSize * i;
float zLocation = voxelSize * j;
float centerXLocation = (xLocation - (mapSize.x * voxelSize) / 2f) + voxelSize / 2f;
float centerZLocation = (zLocation - (mapSize.y * voxelSize) / 2f) + voxelSize / 2f;
string voxelName = i + "x" + j;
Vector3 center = new Vector3(centerXLocation, voxelSize / 2, centerZLocation);
voxels.Add(new Voxel(center, i, j));
}
}
for (int i = 0; i < rooms; i++){
List<Voxel> roomVoxels = new List<Voxel>();
int generatedHeight = Random.Range(minRoomHeight, maxRoomHeight);
int generatedWidth = Random.Range(minRoomWidth, maxRoomWidth);
int horizontalRoomIndex = Random.Range(0, ((int)mapSize.x));
int verticalRoomIndex = Random.Range(0, ((int)mapSize.y));
bool occupied = false;
foreach(Voxel voxel in voxels){
if(voxel.voxelX == horizontalRoomIndex && voxel.voxelY == verticalRoomIndex){
for (int j = 0; j < generatedHeight; j++){
for (int k = 0; k < generatedWidth; k++){
roomVoxels.Add(GetVoxelAtPosition(horizontalRoomIndex + j, verticalRoomIndex + k, out occupied));
}
}
}
}
if(occupied == true){
Debug.Log("Room occupied; unable to create! Clearing the current list to be turned into a room!");
roomVoxels.Clear();
i--;
} else {
Debug.Log("Making a room!");
foreach(Voxel roomVoxel in roomVoxels){
roomVoxel.voxelType = VoxelType.OpenRoom;
}
}
}
}
Voxel GetVoxelAtPosition(int x, int y, out bool occupied){
foreach(Voxel voxel in voxels){
if(voxel.voxelX == x && voxel.voxelY == y){
if (voxel.voxelType == VoxelType.Undefined){
occupied = false;
return voxel;
} else {
Debug.Log("Voxel occupied!");
occupied = true;
return voxels[0];
}
}
}
occupied = true;
return voxels[0];
}
}
I have a List<GameObject> and I need to remove doubles that have the same position.y and position.x (position.z is irrelevant).
I'm thinking that I need to compare all elements in a list and go through the previous elements of the same list and compare if they have the same positions and then, if not, populate the new List<GameObject>().
I don't really know how to do this as I'm not an experienced programmer.
If you wish to just remove the duplicates from an existing list, you don't necessarily have to create a new one. You can iterate over the list and use the RemoveAt method to get rid of the undesired elements.
Example
using System.Collections.Generic;
using UnityEngine;
public class TestScript : MonoBehaviour
{
public List<GameObject> collection = new List<GameObject>();
private void Start()
{
RemoveDuplicatesFrom(collection);
}
private void RemoveDuplicatesFrom(List<GameObject> collection)
{
for (int i = 0; i < collection.Count; i++)
{
for (int j = i + 1; j < collection.Count; j++)
{
if (!Match(collection[i], collection[j]))
continue;
collection.RemoveAt(j);
j--;
}
}
}
private bool Match(GameObject object1, GameObject object2)
{
return
object1.transform.position.x == object2.transform.position.x &&
object1.transform.position.y == object2.transform.position.y;
}
}
The function below should work just fine
public static List<GameObject> Delete_Doubles(List<GameObject> gameobjects){
List<Vector2> occupied_coord = new List<Vector2>();
List<GameObject> gameobjects_after = new List<GameObjects>();
Vector2 t_vector = new Vector2();
Vector3 pos = new Vector3();
pos = gameobjects[0].Transform.position;
t_vector.x = pos.x;
t_vector.y = pos.y;
gameobjects_after.Add(gameobjects[0]);
occupied_coord.Add(t_vector);
for(int i = 1; i < gameobjects.Count; i++)
{
pos = gameobjects[i].Transform.position;
t_vector.x = pos.x;
t_vector.y = pos.y;
if (!occupied_coord.Contains(t_vector))
{
gameobjects_after.Add(gameobjects[i]);
occupied_coord.Add(t_vector);
}
}
return gameobjects_after;
}
I need Help, I'm doing a smaller puzzle game but I have trouble getting the playing field to the center.
Playing field is still on the bottom/left
I tried to fix it using the forum but nothing happened.
Thanks for your help.
Problem
GameBoard.cs
using UnityEngine;
using System.Collections;
public class GameBoard : MonoBehaviour {
public int m_size;
public GameObject m_puzzlePiece;
public GameObject buttonNext;
private PuzzleSection[,] m_puzzle;
private PuzzleSection m_puzzleSelection;
public int m_randomPasses = 12;
void Start()
{
GameObject temp;
m_puzzle = new PuzzleSection[m_size, m_size];
for (int i=0; i< m_size; i++)
{
for (int j=0; j< m_size; j++)
{
temp = (GameObject)Instantiate(m_puzzlePiece,
new Vector2(i*700/m_size, j*700/m_size), Quaternion.identity);
temp.transform.SetParent(transform);
m_puzzle[i, j] = (PuzzleSection)temp.GetComponent<PuzzleSection>();
m_puzzle[i, j].CreatePuzzlePiece(m_size);
}
}
SetupBoard();
RandomizePlacement();
}
void RandomizePlacement()
{
VectorInt2[] puzzleLocation = new VectorInt2[2];
Vector2[] puzzleOffset = new Vector2[2];
do
{
for (int i = 0; i < m_randomPasses; i++)
{
puzzleLocation[0].x = Random.Range(0, m_size);
puzzleLocation[0].y = Random.Range(0, m_size);
puzzleLocation[1].x = Random.Range(0, m_size);
puzzleLocation[1].y = Random.Range(0, m_size);
puzzleOffset[0] = m_puzzle[puzzleLocation[0].x, puzzleLocation[0].y].GetImageOffset();
puzzleOffset[1] = m_puzzle[puzzleLocation[1].x, puzzleLocation[1].y].GetImageOffset();
m_puzzle[puzzleLocation[0].x, puzzleLocation[0].y].AssignImage(puzzleOffset[1]);
m_puzzle[puzzleLocation[1].x, puzzleLocation[1].y].AssignImage(puzzleOffset[0]);
}
} while (CheckBoard() == true);
}
void SetupBoard()
{
Vector2 offset;
Vector2 m_scale = new Vector2(1f / m_size, 1f / m_size);
for (int i=0; i< m_size; i++)
{
for (int j=0; j< m_size; j++)
{
offset = new Vector2(i * (1f / m_size), j * (1f / m_size));
m_puzzle[i, j].AssignImage(m_scale, offset);
}
}
}
public PuzzleSection GetSelection()
{
return m_puzzleSelection;
}
public void SetSelection(PuzzleSection selection)
{
m_puzzleSelection = selection;
}
public bool CheckBoard()
{
for (int i=0; i<m_size; i++)
{
for(int j=0; j< m_size; j++)
{
if (m_puzzle[i, j].CheckGoodPlacement() == false)
return false;
}
}
return true;
}
public void Win()
{
buttonNext.SetActive(true);
}
}
PuzzleSection.cs
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class PuzzleSection : MonoBehaviour {
Vector2 m_goodOffset;
Vector2 m_offset;
Vector2 m_scale;
GameBoard m_gameBoard;
void Start()
{
m_gameBoard = (GameBoard)GameObject.FindObjectOfType<Canvas>()
.GetComponentInChildren<GameBoard>();
}
public void CreatePuzzlePiece(int size)
{
transform.localScale = new Vector3(1.0f * transform.localScale.x / size,
1.0f * transform.localScale.z / size, 1);
}
public void AssignImage(Vector2 scale, Vector2 offset)
{
m_goodOffset = offset;
m_scale = scale;
AssignImage(offset);
}
public void AssignImage(Vector2 offset)
{
m_offset = offset;
GetComponent<RawImage>().uvRect = new Rect(offset.x, offset.y, m_scale.x, m_scale.y);
}
public void OnClick()
{
PuzzleSection previousSelection = m_gameBoard.GetSelection();
if (previousSelection != null)
{
previousSelection.GetComponent<RawImage>().color = Color.white;
Vector2 tempOffset = previousSelection.GetImageOffset();
previousSelection.AssignImage(m_offset);
AssignImage(tempOffset);
m_gameBoard.SetSelection(null);
if (m_gameBoard.CheckBoard() == true)
m_gameBoard.Win();
} else
{
GetComponent<RawImage>().color = Color.gray;
m_gameBoard.SetSelection(this);
}
}
public Vector2 GetImageOffset()
{
return m_offset;
}
public bool CheckGoodPlacement()
{
return (m_goodOffset == m_offset);
}
}
Hey guys, I need Help, I'm doing a smaller puzzle game but I have trouble getting the playing field to the center.
Playing field is still on the bottom/left
I tried to fix it using the forum but nothing happened.
Thanks for your help.
As i gather from the picture your gameboard gets drawn inside a Panel ui control.
You could set the position of this panel to the centre, so that all its children will be centred alongside it:
MyPanel.transform.position = new Vector3 (Screen.width * 0.5f, Screen.height * 0.5f, 0);
I've been making this enemy generator, which is called on Start() and it freezes most of the time. Sometimes it let's to play once but as soon as I hit play second time, it freezes, unity needs to be restarted. Standalone version doesn't fix the problem. Logs last lines:
UnityEngine.DebugLogHandler:Internal_Log(LogType, LogOption, String, Object)
UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
UnityEngine.Logger:Log(LogType, Object)
UnityEngine.Debug:Log(Object)
EnemyGenerator:Start() (at Assets\Scripts\Utils\EnemyGenerator.cs:23)
(Filename: Assets/Scripts/Utils/EnemyGenerator.cs Line: 23)
Here is my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyGenerator : MonoBehaviour
{
public List<GameObject> camps;
public List<GameObject> enemies;
int threshold;
public List<GameObject> campAreas;
public List<GameObject> enemyAreas;
public int campsToSpawn;
public int enemiesPerAreaMin;
public int enemiesPerAreaMax;
void Start()
{
for (int i = 0; i < campsToSpawn; i++)
{
threshold = Random.Range(0, camps.Count - 1);
Debug.Log(threshold);
var campPlace = Random.Range(0, campAreas.Count - 1);
var camp = Instantiate(camps[threshold], campAreas[campPlace].transform.position, Quaternion.identity);
if (camp != null)
{
campAreas.RemoveAt(campPlace);
}
}
Debug.Break();
bool canSpawn = true;
for (int i = 0; i < enemyAreas.Count; i++)
{
threshold = Random.Range(0, enemies.Count - 1);
List<GameObject> enemiesSpawned = new List<GameObject>();
var enemyCount = Random.Range(enemiesPerAreaMin, enemiesPerAreaMax);
for (int j = 0; j < enemyCount; j++)
{
var pos = new Vector3(Random.Range(enemyAreas[i].GetComponent<BoxCollider>().bounds.min.x, enemyAreas[i].GetComponent<BoxCollider>().bounds.max.x), enemyAreas[i].transform.position.y,
Random.Range(enemyAreas[i].GetComponent<BoxCollider>().bounds.min.z, enemyAreas[i].GetComponent<BoxCollider>().bounds.max.z));
if (enemiesSpawned.Count == 0)
{
GameObject en = null;
enemiesSpawned.Add(en = Instantiate(enemies[threshold], pos, Quaternion.identity));
}
else
{
for (int x = 0; x < enemiesSpawned.Count; x++)
{
if (Vector3.Distance(enemiesSpawned[x].transform.position, pos) < 3f)
{
canSpawn = false;
}
}
if (!canSpawn)
{
j--;
}
else
{
enemiesSpawned.Add(Instantiate(enemies[threshold], pos, Quaternion.identity));
}
}
}
Debug.Break();
}
}
}
I tried to find something that would actually loop forever, but I don't think that's the problem. Wondering if it could be performance leak?
Thank you in advance.
Sry I though it was an issue with Debug.Break();
this is probably the problem
{
for (int x = 0; x < enemiesSpawned.Count; x++)
{
if (Vector3.Distance(enemiesSpawned[x].transform.position, pos) < 3f)
{
canSpawn = false;
}
}
if (!canSpawn)
{
j--;
}
else
{
enemiesSpawned.Add(Instantiate(enemies[threshold], pos, Quaternion.identity));
}
}
You getting a random position inside a certain bounds. If the position is too close u don't spawn and --j; to retry a new position. So if for some reason the bounds are wrong or barely engouth you might be running that function for a very long time.
A quick test is to add a counter before your j for loop.
int debugCounter = 0;
for (int j = 0; j < enemyCount; j++)
{
//at the very top
++debugCounter;
if(debugCounter > 100)//or a bigger number
{
Debug.Log("Too many attemps");
break;
}
...
I am making infinity road game. I am using object pooling for roads and enemy objects. roads is working well but I have problem with enemy objects, I can add enemy from pool but I cant return back enemy objects to pool.
public void CreateEnemy( EnemyPool pool, int roadLenght, Vector3 startPos , int numberOfEnemies, int enemyType )
{
enemy = new Transform[numberOfEnemies];
enemyIndex = new int[numberOfEnemies];
currentRoadLenght = roadLenght;
//I add enemies along the length of the path. Path Lenght is randomly generated.
currentEnemyNumber = numberOfEnemies;
int arrayedEnemyObject = 0;
for( int i = 0; i < roadLenght; i++ )
{
Vector3 pos = startPos + new Vector3(0, 1, i * 15);
for( int j = 0; j < numberOfEnemies; j++ )
{
Transform obj = pool.PullEnemyFromPool(enemyType);
obj.position = pos;
obj.gameObject.SetActive(true);
enemy[j] = obj;
enemyIndex[j] = enemyType;
Debug.Log(j);
pos.z += 3;
arrayedEnemyObject++;
}
if( arrayedEnemyObject == numberOfEnemies )
{
arrayedEnemyObject = 0;
i += enemyObjectDistance;
}
}
}
public void DestroyEnemy( EnemyPool objectPooler )
{
if (enemy != null)
{
int destroyedObj = 0;
for( int i = 0; i < currentRoadLenght; i++ )
{
for( int j = 0; j < currentEnemyNumber; j++ )
{
Transform obj = enemy[j];
obj.gameObject.SetActive( false );
objectPooler.AddEnemyToPool( enemyIndex[j], obj );
destroyedObj++;
}
if( destroyedObj == currentEnemyNumber )
{
destroyedObj = 0;
i += enemyObjectDistance;
}
}
enemy = null;
}
}
My EnemyPoolScript
public class EnemyPool : MonoBehaviour
{
private GameObject[] enemyObjects;
private List<Transform>[] enemyObjectsPool;
public void FillPool( GameObject[] enemyObjects , int size )
{
this.enemyObjects = enemyObjects;
Vector3 pos = Vector3.zero;
Quaternion tilt = Quaternion.identity;
GameObject obj;
enemyObjectsPool = new List<Transform>[enemyObjects.Length];
for ( int i = 0; i < enemyObjects.Length; i++ )
{
enemyObjectsPool[i] = new List<Transform>();
for( int j = 0; j < size; j++ )
{
obj = Instantiate( enemyObjects[i], pos, tilt ) as GameObject;
obj.SetActive( false );
enemyObjectsPool[i].Add( obj.transform );
}
}
}
public void AddEnemyToPool( int index, Transform obj )
{
enemyObjectsPool[index].Add (obj);
}
public Transform PullEnemyFromPool( int index )
{
Transform obj;
if( enemyObjectsPool[index].Count <= 0 )
{
obj = ( Instantiate( enemyObjects[index], Vector3.zero, Quaternion.identity ) as GameObject ).transform;
}
else
{
obj = enemyObjectsPool[index][0];
enemyObjectsPool[index].RemoveAt (0);
}
return obj;
}
}
Why are you itterating over road length in your adds and deletes. that's probably where your problem lies. you're setting the same item in your array multiple times. you are pulling an item out of your pool for every road, and putting it in the same slot.
for (int i = 0; i < roadCount; i++)
enemy[j] = pullObject;
the outer loop is probably the culprit.
Also, in your pool, it might help to use a queue instead of a list. queues are specifically used for removing items from the front, which will be more efficient than RemoveAt(0)
Edit:
okay... it's a bit hard to explain, but your outerloop probably isn't doing what you think it's doing. all your outer loop is doing is making sure you repeat your inner loop roudcount number of times. lets pretend you have a road length of 3, and a number of enemies of 2.
This is what your program is doing:
pos = startPos + new Vector3(0,1,0);
obj.position = pos;
enemy[0] = obj;
pos.z += 3;
arrayedEnemeyObject++;
obj.position = pos;
enemy[1] = obj;
pos.z += 3;
arrayedEnemeyObject++;
arrayedEnemeyObject = 0;
i += enemyObjectDistance;
pos = startPos + new Vector3(0,1,15);
obj.position = pos;
enemy[0] = obj;
pos.z += 3;
arrayedEnemeyObject++;
obj.position = pos;
enemy[1] = obj;
pos.z += 3;
Notice how enemy[0] gets set twice. i still don't know what roaddistance is meant to do, because your outerloop isn't doing anything. i'm... guessing, this is what you want... but i really don't know
enemy[,] = new Transform[roadCount, numberOfEnemies];
enemyIndex[,] = new int[roadCount, numberOfEnemies];
then in your inner loop:
enemy[i,j] = obj;