Spawning random platforms in unity - unity3d

So in my quest to make a game like the very popular zigzag game, I am stuck at randomly generating platforms. The platforms generate randomly in X,-X,Z,-Z directions. I have written my code where it generates the platforms. I might have taken a very long approach (alternative approaches if any)
void Start ()
{
lastPos = platform.transform.position;
size = platform.transform.localScale.x;
InvokeRepeating("SpawnXZ",1f,0.2f);
}
void SpawnX()
{
Vector3 pos = lastPos;
pos.x += size;
lastPos = pos;
Instantiate(platform, pos, Quaternion.identity);
}
void SpawnZ()
{
Vector3 pos = lastPos;
pos.z += size;
lastPos = pos;
Instantiate(platform, pos, Quaternion.identity);
}
void SpawnNegX()
{
Vector3 pos = lastPos;
pos.x -= size;
lastPos = pos;
Instantiate(platform, pos, Quaternion.identity);
}
void SpawnNegZ()
{
Vector3 pos = lastPos;
pos.z -= size;
lastPos = pos;
Instantiate(platform, pos, Quaternion.identity);
}
void SpawnXZ()
{
int rand = Random.Range(0, 6);
if (rand < 3)
{
SpawnX();
}
else if(rand >= 3)
{
SpawnZ();
}
if(--counter == 0) { CancelInvoke("SpawnXZ"); };
if(counter == 0)
{
counter = 25;
int r = Random.Range(0,2);
if(r == 0)
{
InvokeRepeating("SpawnNegXZ",0f,0.2f);
}
else
{
InvokeRepeating("SpawnXNegZ",0f,0.2f);
}
}
}
void SpawnNegXZ()
{
int rand = Random.Range(0, 6);
if (rand < 3)
{
SpawnNegX();
}
else if(rand >= 3)
{
SpawnZ();
}
if(--counter == 0) { CancelInvoke("SpawnNegXZ"); };
if(counter == 0)
{
counter = 25;
int r = Random.Range(0,2);
if(r == 0)
{
InvokeRepeating("SpawnXZ",0f,0.2f);
}
else
{
InvokeRepeating("SpawnNegXNegZ",0f,0.2f);
}
}
}
void SpawnXNegZ()
{
int rand = Random.Range(0, 6);
if (rand < 3)
{
SpawnX();
}
else if(rand >= 3)
{
SpawnNegZ();
}
if(--counter == 0) { CancelInvoke("SpawnXNegZ"); };
if(counter == 0)
{
counter = 25;
int r = Random.Range(0,2);
if(r == 0)
{
InvokeRepeating("SpawnXZ",0f,0.2f);
}
else
{
InvokeRepeating("SpawnNegXNegZ",0f,0.2f);
}
}
}
void SpawnNegXNegZ()
{
int rand = Random.Range(0, 6);
if (rand < 3)
{
SpawnNegX();
}
else if(rand >= 3)
{
SpawnNegZ();
}
if(--counter == 0) { CancelInvoke("SpawnNegXNegZ"); };
if(counter == 0)
{
counter = 25;
int r = Random.Range(0,2);
if(r == 0)
{
InvokeRepeating("SpawnNegXZ",0f,0.2f);
}
else
{
InvokeRepeating("SpawnXNegZ",0f,0.2f);
}
}
}
I have clubbed xz, -xz , x -z and -x -z. I call platform spawning in X and Z direction first, then switching to -XZ or x -Z and so on. But there are 2 main issues.
PS : those small black squares are nothing but diamonds (ignore them).
They either form a 2X2 block or overlap each other.
How do I avoid these? or is there a simpler way of generating platforms that I am missing.

You need an array to indicate which tiles are occupied:
bool[,] tiles = new bool[N,N];
or a dictionary
Dictionary<XZ, bool> tiles = new Dictionary<XZ, bool>();
public struct XZ { public int X; public int Z; }
whenever a tile is spawned check the value to see if it is possible to spawn or not:
void SpawnXZ()
{
int x = (int) (lastpos.x / size);
int z = (int) (lastpos.z / size);
int rand = Random.Range(0, 6);
if (rand < 3 && !tiles[x + 1, z])
{
SpawnX();
tiles[x + 1, z] = true;
}
else if(rand >= 3 && && !tiles[x, z + 1])
{
SpawnZ();
tiles[x, z + 1] = true;
}
else
{
...
}
Note that this code will not work, and it's just a starting point for you to develop it further.

Related

Unity Destroy() doesn't delete script

Noob mistake I was only referencing the parents brain from the child's instead of copying it directly. It's a neural network that can grow in size (or shrink) through genetics. I was going to post it but it doesn't fit on this without me having to type a larger ratio of words to code oh look it works now
public class Animal1 : MonoBehaviour
{
public class Neuron1
{
public int[] children;
public float[] weights;
public float bias;
public float value;
public Neuron1()
{
children = new int[10];
for (int i = 0; i < 10; i++)
{
children[i] = -1;
}
weights = new float[10];
for (int i = 0; i < 10; i++)
{
weights[i] = 1;
}
bias = 0;
value = 0;
}
}
float sightRange = 2;
Vector2 left = new Vector2(-.4f,.6f);
Vector2 right = new Vector2(.4f, .6f);
RaycastHit2D hitLeft;
RaycastHit2D hitForward;
RaycastHit2D hitRight;
public LayerMask animalLayerMask;
[System.NonSerialized]
public int food = 0;
int foodCounter = 0;
int foodForReproduction = 3;
float noFoodCounter = 0;
int lifeWithoutFood = 20;
int maxBrainSize = 100;
[System.NonSerialized]
public Neuron1[] brain1 = new Neuron1[100]; //first three and last three are inputs and outputs and are never mutated
int childrenMaxAmount = 5;
float biasInitRange = 2;
float weightInitRange = 2;
int outputSize = 2;
int inputSize = 3;
GameObject manager;
[System.NonSerialized]
public bool firstGen = false;
[System.NonSerialized]
public GameObject parent1;
[System.NonSerialized]
public bool directCopy = false;
float maxTravelRange = 5;
Color color;
float colorMutationRate = .1f;
public GameObject animal1Prefab1;
bool debugBool = false;
void Start()
{
manager = GameObject.Find("Manager Object");
if (firstGen == true)
{
InitializeBrain(3, 2, 20);
firstGen = false;
transform.GetComponent<SpriteRenderer>().color = new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f), 1);
}
else
{
if (parent1.GetComponent<Animal1>().brain1[0].bias == 1234)
{
Debug.Log("parent passing brain after deletion");
}
Mutate(parent1, 5, 1f, .5f);
transform.GetComponent<SpriteRenderer>().color = color;
}
}
void Update()
{
if (brain1[0].bias == 1234)
{
GetComponent<SpriteRenderer>().color = Color.black;
}
//teleportation
if (transform.position.x > maxTravelRange)
{
Vector2 newPosition = new Vector2(-maxTravelRange, transform.position.y);
transform.position = newPosition;
}
if (transform.position.x < -maxTravelRange)
{
Vector2 newPosition = new Vector2(maxTravelRange, transform.position.y);
transform.position = newPosition;
}
if (transform.position.y > maxTravelRange)
{
Vector2 newPosition = new Vector2(transform.position.x, -maxTravelRange);
transform.position = newPosition;
}
if (transform.position.y < -maxTravelRange)
{
Vector2 newPosition = new Vector2(transform.position.x, maxTravelRange);
transform.position = newPosition;
}
//input
hitLeft = Physics2D.Raycast(transform.position, transform.TransformDirection(left), sightRange, ~animalLayerMask); //left
hitForward = Physics2D.Raycast(transform.position, transform.TransformDirection(Vector2.up), sightRange, ~animalLayerMask); //forward
hitRight = Physics2D.Raycast(transform.position, transform.TransformDirection(right), sightRange, ~animalLayerMask); //right
if (hitLeft)
{
brain1[0].value = 1;
}
if (hitForward)
{
brain1[1].value = 1;
}
if (hitRight)
{
brain1[2].value = 1;
}
//output
Think();
// one output for speed, another for turning
int rotDir = 1;
if (brain1[maxBrainSize - 1].value < 0)
{
rotDir = -1;
}
Vector3 eulerRotation = new Vector3(0, 0, (45 * rotDir + (transform.rotation.eulerAngles.z % 360)) % 360);
transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(eulerRotation), Mathf.Abs(brain1[maxBrainSize - 1].value) * 25 * Time.deltaTime);
if (brain1[maxBrainSize - 2].value > 0) // so they can't go backwards
{
transform.Translate(Vector2.up * (brain1[maxBrainSize - 2].value * .1f) * Time.deltaTime);
}
//reset outputs
brain1[maxBrainSize - 2].value = 0;
brain1[maxBrainSize - 1].value = 0;
// reset inputs
brain1[0].value = 0;
brain1[1].value = 0;
brain1[2].value = 0;
noFoodCounter += Time.deltaTime;
if (food > 0)
{
foodCounter++;
food = 0;
noFoodCounter = 0;
}
if (foodCounter > foodForReproduction)
{
foodCounter = 0;
Reproduce();
}
if (noFoodCounter > lifeWithoutFood/2)
{
foodCounter = 0;
}
if (noFoodCounter > lifeWithoutFood)
{
Destroy(gameObject);
}
}
void InitializeBrain(int inputs, int outputs, int sizeExcludingInputsAndOutputs)
{
for (int i = 0; i < sizeExcludingInputsAndOutputs + inputs; i++)
{
brain1[i] = new Neuron1();
}
for (int i = maxBrainSize - outputs; i < maxBrainSize; i++) // outputs
{
brain1[i] = new Neuron1();
}
// all neurons in between the inputs and outputs
for (int i = inputs; i < sizeExcludingInputsAndOutputs + inputs; i++)
{
brain1[i].bias = Random.Range(-biasInitRange, biasInitRange);
for (short j = 0; j < childrenMaxAmount -1; j++) // -1 so there is always at least one free space for a child
{
int rnd1 = Random.Range(inputs, sizeExcludingInputsAndOutputs + inputs);
bool alreadyContains = true;
int errorCounter = 0;
while (alreadyContains) // making sure none are children of themselves, and that it doesn't already have this child
{
alreadyContains = false;
for (short h = 0; h < childrenMaxAmount; h++)
{
if (brain1[i].children[h] == rnd1) // if it already has this child
{
alreadyContains = true;
rnd1 = Random.Range(inputs, sizeExcludingInputsAndOutputs + inputs);
while (rnd1 == i) // and its not itself
{
rnd1 = Random.Range(inputs, sizeExcludingInputsAndOutputs + inputs);
}
break;
}
}
errorCounter++;
if (errorCounter > 100) // so we don't get stuck in small network sizes
{
goto outside2;
}
}
brain1[i].children[j] = rnd1;
brain1[i].weights[j] = Random.Range(-weightInitRange, weightInitRange);
if (Random.Range(1, 10) > 8)
{
break; // so not every neuron has the same amount of children
}
}
outside2:
{
}
}
// assign children of inputs
for (int i = 0; i < inputs; i++)
{
for (int j = 0; j < childrenMaxAmount; j++) // assigning all max children (sometimes) to inputs, their amounts of children will never change
{
int rnd1 = Random.Range(inputs, sizeExcludingInputsAndOutputs + inputs);
bool alreadyContains = true;
int errorCounter = 0;
while (alreadyContains)
{
alreadyContains = false;
for (short h = 0; h < childrenMaxAmount; h++)
{
if (brain1[i].children[h] == rnd1)
{
alreadyContains = true;
rnd1 = Random.Range(inputs, sizeExcludingInputsAndOutputs + inputs);
}
}
errorCounter++;
if (errorCounter > 1000) // so we don't get stuck in small network sizes
{
goto outside1;
}
}
brain1[i].children[j] = rnd1;
//brain1[i].weights[j] = 100; // input weight
}
outside1:
{
}
}
RemoveDeadNeurons();
// assign parents of outputs
int brainEnd = maxBrainSize - outputs;
for (int i = brainEnd; i < maxBrainSize; i++)
{
for (short j = 0; j < childrenMaxAmount; j++) // same amount of parents as inputs have children
{
int rnd1 = Random.Range(inputs, brainEnd);
while (brain1[rnd1] == null)
{
rnd1 = Random.Range(inputs, brainEnd);
}
bool alreadyContains = true;
int errorCounter = 0;
while (alreadyContains) //making sure we dont already have this parent
{
alreadyContains = false;
for (short h = 0; h < childrenMaxAmount; h++)
{
if (brain1[rnd1].children[h] == i)
{
alreadyContains = true;
rnd1 = Random.Range(inputs, brainEnd);
while (brain1[rnd1] == null)
{
rnd1 = Random.Range(inputs, brainEnd);
}
}
}
errorCounter++;
if (errorCounter > 1000) // so we don't get stuck
{
goto outside3;
}
}
for (int h = 0; h < childrenMaxAmount; h++) //adding to next available child space of the parent
{
if (brain1[rnd1].children[h] == -1)
{
brain1[rnd1].children[h] = i;
brain1[rnd1].weights[h] = Random.Range(-weightInitRange, weightInitRange);
break;
}
}
}
outside3:
{
}
}
}
void Think()
{
int[] activatedChildrenIndexes = new int[500];
int[] workingArray = new int[500];
int workingArrayCounter = 0;
short layerCounter = 0;
for (int i = 0; i < 500; i++)
{
activatedChildrenIndexes[i] = -1;
}
//initializing inputs as first activated children layer to be calculated
activatedChildrenIndexes[0] = 0;
activatedChildrenIndexes[1] = 1;
activatedChildrenIndexes[2] = 2;
int thoughtDepth = 6; //keep this as low as possible, will change to make it a percent of the amount of neurons that already exist
for (int x = 0; x < thoughtDepth; x++)
{
for (int i = 0; i < 500; i++) // cycle through activated children and add their activated children to a list
{
int currentNodeIndex = activatedChildrenIndexes[i];
if (currentNodeIndex == -1)
{
layerCounter++;
break;
}
//activation function
if (brain1[currentNodeIndex].value <= 0)
{
brain1[currentNodeIndex].value = 0;
}
else
{
brain1[currentNodeIndex].value = 1;
}
for (int j = 0; j < childrenMaxAmount; j++)
{
if (brain1[currentNodeIndex].children[j] == -1)
{
break;
}
brain1[brain1[currentNodeIndex].children[j]].value
+= (brain1[currentNodeIndex].value * brain1[currentNodeIndex].weights[j]) + brain1[currentNodeIndex].bias;
bool activatedChildIsInNextLayer = false;
for (int h = 0; h < 500; h++)
{
if (brain1[currentNodeIndex].children[j] == activatedChildrenIndexes[h])
{
activatedChildIsInNextLayer = true;
}
}
if (brain1[brain1[currentNodeIndex].children[j]].value > 0
|| layerCounter == 0
|| brain1[currentNodeIndex].children[j] > maxBrainSize - outputSize)
{
if (!activatedChildIsInNextLayer)
{
workingArray[workingArrayCounter] = brain1[currentNodeIndex].children[j];
if (workingArrayCounter < 499)//to prevent out of bounds indexing
{
workingArrayCounter++;
}
}
}
if (brain1[brain1[currentNodeIndex].children[j]].value < 0 && brain1[currentNodeIndex].children[j] < maxBrainSize - outputSize)
{
brain1[brain1[currentNodeIndex].children[j]].value = 0; //resetting negative nodes that didn't get added to next layer
}
}
brain1[currentNodeIndex].value = 0; // resetting value after passing to children
}
for (int i = workingArrayCounter; i < 500; i++)
{
workingArray[i] = -1;
}
workingArrayCounter = 0;
for (int i = 0; i < 500; i++)
{
activatedChildrenIndexes[i] = workingArray[i];
}
}
}
void Mutate(GameObject parent, float mutationRate, float weightsMutate, float biasMutate)
{
color = parent.GetComponent<SpriteRenderer>().color;
for (int i = 0; i < maxBrainSize; i++) // initialized to its parent's brain
{
if (parent.GetComponent<Animal1>().brain1[i] != null)
{
brain1[i] = new Neuron1();
brain1[i].bias = parent.GetComponent<Animal1>().brain1[i].bias;
for (int j = 0; j < childrenMaxAmount; j++)
{
brain1[i].children[j] = parent.GetComponent<Animal1>().brain1[i].children[j];
brain1[i].weights[j] = parent.GetComponent<Animal1>().brain1[i].weights[j];
}
}
}
for (int i = inputSize; i < maxBrainSize - outputSize; i++)
{
if (brain1[i] != null)
{
if (Random.Range(0, 100) < mutationRate) // it will be mutated
{
switch (Random.Range(1, 5))
{
case 1: //change one of its weights
int weightCounter = 0;
for (int k = 0; k < childrenMaxAmount; k++) // counting its weights
{
if (brain1[i].children[k] != -1)
{
weightCounter++;
}
else
{
break;
}
}
brain1[i].weights[Random.Range(0, weightCounter)] += Random.Range(-weightsMutate, weightsMutate);
color.r += Random.Range(-colorMutationRate, colorMutationRate);
color.g += Random.Range(-colorMutationRate, colorMutationRate);
color.b += Random.Range(-colorMutationRate, colorMutationRate);
break;
case 2: //change its bias
brain1[i].bias += Random.Range(-biasMutate, biasMutate);
color.r += Random.Range(-colorMutationRate, colorMutationRate);
color.g += Random.Range(-colorMutationRate, colorMutationRate);
color.b += Random.Range(-colorMutationRate, colorMutationRate);
break;
case 3: //break a connection/ remove neuron
int childrenCounter = 0;
for (int k = 0; k < childrenMaxAmount; k++) // counting its children
{
if (brain1[i].children[k] != -1)
{
childrenCounter++;
}
else
{
break;
}
}
int rndChild = Random.Range(0, childrenCounter);
for (int s = rndChild; s < childrenMaxAmount - 1; s++) // shift children list down starting from rndChild and to the second to last element
{
brain1[i].children[s] = brain1[i].children[s + 1];
brain1[i].weights[s] = brain1[i].weights[s + 1];
}
brain1[i].children[childrenMaxAmount - 1] = -1; // removing the last child after shifting the list down one
brain1[i].weights[childrenMaxAmount - 1] = 0;
RemoveDeadNeurons();
color.r += Random.Range(-colorMutationRate, colorMutationRate);
color.g += Random.Range(-colorMutationRate, colorMutationRate);
color.b += Random.Range(-colorMutationRate, colorMutationRate);
break;
case 4: //add a new child if possible
int childrenCounter2 = 0;
for (int k = 0; k < childrenMaxAmount; k++) // counting its children
{
if (brain1[i].children[k] != -1)
{
childrenCounter2++;
}
else
{
break;
}
}
if (childrenCounter2 < childrenMaxAmount) // if we have room for another child
{
int newChild = Random.Range(inputSize, maxBrainSize);
while (brain1[newChild] == null)
{
newChild = Random.Range(inputSize, maxBrainSize);
}
brain1[i].children[childrenCounter2] = newChild;
brain1[i].weights[childrenCounter2] = Random.Range(-weightInitRange, weightInitRange);
color.r += Random.Range(-colorMutationRate, colorMutationRate);
color.g += Random.Range(-colorMutationRate, colorMutationRate);
color.b += Random.Range(-colorMutationRate, colorMutationRate);
}
break;
}
}
}
}
if (Random.Range(0, 100) < 10) // create a new neuron if space is available for one
{
for (int i = inputSize; i < maxBrainSize - outputSize; i++)
{
if (brain1[i] == null) // the first available neuron
{
brain1[i] = new Neuron1();
int rndParent = Random.Range(0, maxBrainSize - outputSize);
int childrenCounter3 = 0;
if (brain1[rndParent] != null)
{
for (int k = 0; k < childrenMaxAmount; k++) // counting its children
{
if (brain1[rndParent].children[k] != -1)
{
childrenCounter3++;
}
else
{
break;
}
}
}
while (brain1[rndParent] == null || childrenCounter3 == childrenMaxAmount) // making sure it is both an existing neuron and that it has room for another child
{
childrenCounter3 = 0;
rndParent = Random.Range(0, maxBrainSize - outputSize);
if (brain1[rndParent] != null)
{
for (int k = 0; k < childrenMaxAmount; k++) // counting its children
{
if (brain1[rndParent].children[k] != -1)
{
childrenCounter3++;
}
else
{
break;
}
}
}
}
brain1[rndParent].children[childrenCounter3] = i; //giving the neuron a parent
brain1[rndParent].weights[childrenCounter3] = Random.Range(-weightInitRange, weightInitRange);
int rndChild = Random.Range(inputSize, maxBrainSize);
while(brain1[rndChild] == null)
{
rndChild = Random.Range(inputSize, maxBrainSize);
}
brain1[i].children[0] = rndChild; // giving the new neuron a child, a weight, and its bias
brain1[i].weights[0] = Random.Range(-weightInitRange, weightInitRange);
brain1[i].bias = Random.Range(-biasInitRange, biasInitRange);
color.r += Random.Range(-colorMutationRate, colorMutationRate);
color.g += Random.Range(-colorMutationRate, colorMutationRate);
color.b += Random.Range(-colorMutationRate, colorMutationRate);
break;
}
}
}
}
void RemoveDeadNeurons()
{
bool allGood = false;
while (!allGood)
{
for (int i = inputSize; i < maxBrainSize - outputSize; i++) // for every hidden layer neuron
{
if (brain1[i] != null) // if it's a neuron
{
if (brain1[i].children[0] == -1) // if it has no children
{
brain1[i] = null; // deleting neuron
for (int h = 0; h < maxBrainSize - outputSize; h++) //remove from other neurons children list, including from the input layer
{
if (brain1[h] != null)
{
for (int g = 0; g < childrenMaxAmount; g++)
{
if (brain1[h].children[g] == i) // if brain[h] has the removed neuron as a child
{
for (int s = g; s < childrenMaxAmount - 1; s++) // shift children list down
{
brain1[h].children[s] = brain1[h].children[s + 1];
brain1[h].weights[s] = brain1[h].weights[s + 1];
}
brain1[h].children[childrenMaxAmount - 1] = -1; // removing the last child in the list after shifting it down one
brain1[h].weights[childrenMaxAmount - 1] = 0;
}
}
}
}
goto outsideRDNLoop; // break out of for loop and recheck the brain
}
bool parentless = true;
for (int h = 0; h < maxBrainSize - outputSize; h++) // check if it is parentless
{
if (brain1[h] != null)
{
for (int g = 0; g < childrenMaxAmount; g++)
{
if (brain1[h].children[g] == i) // if it is a child of brain[h]
{
parentless = false;
}
}
}
}
if (parentless)
{
brain1[i] = null; //deleting neuron
goto outsideRDNLoop;
}
}
if (i == (maxBrainSize - outputSize) - 1) // if we reached the end of the for loop and this line, we know the brain was allGood
{
allGood = true;
}
}
outsideRDNLoop:
{
}
}
}
void Reproduce()
{
GameObject offspring = Instantiate(animal1Prefab1, new Vector2(transform.position.x + 1, transform.position.y + 1), Quaternion.identity);
offspring.GetComponent<Animal1>().parent1 = gameObject;
offspring.name = "animal1";
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawRay(transform.position, transform.TransformDirection(left) * sightRange);
Gizmos.DrawRay(transform.position, transform.TransformDirection(Vector2.up) * sightRange);
Gizmos.DrawRay(transform.position, transform.TransformDirection(right) * sightRange);
}
}
I've not run your code, just looked at it, but this looks suspicious if you are having problems with the contents of brain1 being overwritten elsewhere:
void Mutate(GameObject parent, float mutationRate, float weightsMutate, float biasMutate)
{
color = parent.GetComponent<SpriteRenderer>().color;
// This line here is suspicious:
brain1 = parent.GetComponent<Animal1>().brain1; // initialized to its parent's brain
What you are doing here is replacing the reference to the child's brain with the parent's - so if you are starting with just one parent initially, every single entity will be sharing the same brain.
I think perhaps you meant to deep copy the contents from parent's brain into the child's brain? What your assignment here is doing is just taking the reference to the parent's brain and using it as the child brain as well.
Example Deep copy:
Updated Neuron1 class:
public class Neuron1
{
public int[] children;
public float[] weights;
public float bias;
public float value;
public Neuron1()
{
children = new int[10];
for (int i = 0; i < 10; i++)
{
children[i] = -1; // to stop looping when reaching -1
}
weights = new float[10];
for (int i = 0; i < 10; i++)
{
weights[i] = 1;
}
bias = 0;
value = 0;
}
// Added clone function:
public Neuron1 Clone()
{
Neuron1 clone = new Neuron1();
for (int i = 0; i < clone.children.Length; i++)
{
clone.children[i] = this.children[i];
}
for (int i = 0; i < clone.weights.Length; i++)
{
clone.weights[i] = this.weights[i];
}
clone.bias = this.bias;
clone.value = this.value;
return clone;
}
}
Updated start of Mutate function.
void Mutate(GameObject parent, float mutationRate, float weightsMutate, float biasMutate)
{
color = parent.GetComponent<SpriteRenderer>().color;
Neuron1[] parentBrain = parent.GetComponent<Animal1>().brain1; // initialized to its parent's brain
for (int i = 0; i < brain1.Length; ++i)
{
brain1[i] = parentBrain[i].Clone();
}
Well, I have a demo scene here. In it I created an empty game object. It has a script attached to it (CSharp.cs), like this:
In my Update method I wrote
And as soon as I start the game, the game object including the script is deleted.
But if I replace transform.gameObject wit just this then only the script disappears and the game object remains.
DestoryImmediate() is not recommended to be used, instead use Destory()
Destroy() will set the object to null at the end of the frame and whereas DestroyImmediate() function immediately set object reference to null.
DestoryImmediate can also delete prefabs/scenes/art in your project outside of playmode which is another reason you should not use it.

2D procedural dungeon generation game

I am currently messing around with a procedural 2D game in unity. Below are the scripts i am using to generate the dungeon and wanted to know if there was anyway of specifying a standard starting room. I have prefab room built but would like to have a single prefab room players always start in.
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class DungeonGeneration : MonoBehaviour {
[SerializeField]
private int numberOfRooms;
[SerializeField]
private int numberOfObstacles;
[SerializeField]
private Vector2Int[] possibleObstacleSizes;
[SerializeField]
private int numberOfEnemies;
[SerializeField]
private GameObject[] possibleEnemies;
[SerializeField]
private GameObject goalPrefab;
[SerializeField]
private TileBase obstacleTile;
private Room[,] rooms;
private Room currentRoom;
private static DungeonGeneration instance = null;
void Awake () {
if (instance == null) {
DontDestroyOnLoad (this.gameObject);
instance = this;
this.currentRoom = GenerateDungeon ();
} else {
string roomPrefabName = instance.currentRoom.PrefabName ();
GameObject roomObject = (GameObject) Instantiate (Resources.Load (roomPrefabName));
Tilemap tilemap = roomObject.GetComponentInChildren<Tilemap> ();
instance.currentRoom.AddPopulationToTilemap (tilemap, instance.obstacleTile);
Destroy (this.gameObject);
}
}
void Start () {
string roomPrefabName = this.currentRoom.PrefabName ();
GameObject roomObject = (GameObject) Instantiate (Resources.Load (roomPrefabName));
Tilemap tilemap = roomObject.GetComponentInChildren<Tilemap> ();
this.currentRoom.AddPopulationToTilemap (tilemap, this.obstacleTile);
}
private Room GenerateDungeon() {
int gridSize = 3 * numberOfRooms;
rooms = new Room[gridSize, gridSize];
Vector2Int initialRoomCoordinate = new Vector2Int ((gridSize / 2) - 1, (gridSize / 2) - 1);
Queue<Room> roomsToCreate = new Queue<Room> ();
roomsToCreate.Enqueue (new Room(initialRoomCoordinate.x, initialRoomCoordinate.y));
List<Room> createdRooms = new List<Room> ();
while (roomsToCreate.Count > 0 && createdRooms.Count < numberOfRooms) {
Room currentRoom = roomsToCreate.Dequeue ();
this.rooms [currentRoom.roomCoordinate.x, currentRoom.roomCoordinate.y] = currentRoom;
createdRooms.Add (currentRoom);
AddNeighbors (currentRoom, roomsToCreate);
}
int maximumDistanceToInitialRoom = 0;
Room finalRoom = null;
foreach (Room room in createdRooms) {
List<Vector2Int> neighborCoordinates = room.NeighborCoordinates ();
foreach (Vector2Int coordinate in neighborCoordinates) {
Room neighbor = this.rooms [coordinate.x, coordinate.y];
if (neighbor != null) {
room.Connect (neighbor);
}
}
room.PopulateObstacles (this.numberOfObstacles, this.possibleObstacleSizes);
room.PopulatePrefabs (this.numberOfEnemies, this.possibleEnemies);
int distanceToInitialRoom = Mathf.Abs (room.roomCoordinate.x - initialRoomCoordinate.x) + Mathf.Abs(room.roomCoordinate.y - initialRoomCoordinate.y);
if (distanceToInitialRoom > maximumDistanceToInitialRoom) {
maximumDistanceToInitialRoom = distanceToInitialRoom;
finalRoom = room;
}
}
GameObject[] goalPrefabs = { this.goalPrefab };
finalRoom.PopulatePrefabs(1, goalPrefabs);
return this.rooms [initialRoomCoordinate.x, initialRoomCoordinate.y];
}
private void AddNeighbors(Room currentRoom, Queue<Room> roomsToCreate) {
List<Vector2Int> neighborCoordinates = currentRoom.NeighborCoordinates ();
List<Vector2Int> availableNeighbors = new List<Vector2Int> ();
foreach (Vector2Int coordinate in neighborCoordinates) {
if (this.rooms[coordinate.x, coordinate.y] == null) {
availableNeighbors.Add (coordinate);
}
}
int numberOfNeighbors = (int)Random.Range (1, availableNeighbors.Count);
for (int neighborIndex = 0; neighborIndex < numberOfNeighbors; neighborIndex++) {
float randomNumber = Random.value;
float roomFrac = 1f / (float)availableNeighbors.Count;
Vector2Int chosenNeighbor = new Vector2Int(0, 0);
foreach (Vector2Int coordinate in availableNeighbors) {
if (randomNumber < roomFrac) {
chosenNeighbor = coordinate;
break;
} else {
roomFrac += 1f / (float)availableNeighbors.Count;
}
}
roomsToCreate.Enqueue (new Room(chosenNeighbor));
availableNeighbors.Remove (chosenNeighbor);
}
}
private void PrintGrid() {
for (int rowIndex = 0; rowIndex < this.rooms.GetLength (1); rowIndex++) {
string row = "";
for (int columnIndex = 0; columnIndex < this.rooms.GetLength (0); columnIndex++) {
if (this.rooms [columnIndex, rowIndex] == null) {
row += "X";
} else {
row += "R";
}
}
Debug.Log (row);
}
}
public void MoveToRoom(Room room) {
this.currentRoom = room;
}
public Room CurrentRoom() {
return this.currentRoom;
}
public void ResetDungeon() {
this.currentRoom = GenerateDungeon ();
}
}
and
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class Room
{
public Vector2Int roomCoordinate;
public Dictionary<string, Room> neighbors;
private string[,] population;
private Dictionary<string, GameObject> name2Prefab;
public Room (int xCoordinate, int yCoordinate)
{
this.roomCoordinate = new Vector2Int (xCoordinate, yCoordinate);
this.neighbors = new Dictionary<string, Room> ();
this.population = new string[18, 10];
for (int xIndex = 0; xIndex < 18; xIndex += 1) {
for (int yIndex = 0; yIndex < 10; yIndex += 1) {
this.population [xIndex, yIndex] = "";
}
}
this.population [8, 5] = "Player";
this.name2Prefab = new Dictionary<string, GameObject> ();
}
public Room (Vector2Int roomCoordinate)
{
this.roomCoordinate = roomCoordinate;
this.neighbors = new Dictionary<string, Room> ();
this.population = new string[18, 10];
for (int xIndex = 0; xIndex < 18; xIndex += 1) {
for (int yIndex = 0; yIndex < 10; yIndex += 1) {
this.population [xIndex, yIndex] = "";
}
}
this.population [8, 5] = "Player";
this.name2Prefab = new Dictionary<string, GameObject> ();
}
public List<Vector2Int> NeighborCoordinates () {
List<Vector2Int> neighborCoordinates = new List<Vector2Int> ();
neighborCoordinates.Add (new Vector2Int(this.roomCoordinate.x, this.roomCoordinate.y - 1));
neighborCoordinates.Add (new Vector2Int(this.roomCoordinate.x + 1, this.roomCoordinate.y));
neighborCoordinates.Add (new Vector2Int(this.roomCoordinate.x, this.roomCoordinate.y + 1));
neighborCoordinates.Add (new Vector2Int(this.roomCoordinate.x - 1, this.roomCoordinate.y));
return neighborCoordinates;
}
public void Connect (Room neighbor) {
string direction = "";
if (neighbor.roomCoordinate.y < this.roomCoordinate.y) {
direction = "N";
}
if (neighbor.roomCoordinate.x > this.roomCoordinate.x) {
direction = "E";
}
if (neighbor.roomCoordinate.y > this.roomCoordinate.y) {
direction = "S";
}
if (neighbor.roomCoordinate.x < this.roomCoordinate.x) {
direction = "W";
}
this.neighbors.Add (direction, neighbor);
}
public string PrefabName () {
string name = "Room_";
foreach (KeyValuePair<string, Room> neighborPair in neighbors) {
name += neighborPair.Key;
}
return name;
}
public Room Neighbor (string direction) {
return this.neighbors [direction];
}
public void PopulateObstacles (int numberOfObstacles, Vector2Int[] possibleSizes) {
for (int obstacleIndex = 0; obstacleIndex < numberOfObstacles; obstacleIndex += 1) {
int sizeIndex = Random.Range (0, possibleSizes.Length);
Vector2Int regionSize = possibleSizes [sizeIndex];
List<Vector2Int> region = FindFreeRegion (regionSize);
foreach (Vector2Int coordinate in region) {
this.population [coordinate.x, coordinate.y] = "Obstacle";
}
}
}
public void PopulatePrefabs (int numberOfPrefabs, GameObject[] possiblePrefabs) {
for (int prefabIndex = 0; prefabIndex < numberOfPrefabs; prefabIndex += 1) {
int choiceIndex = Random.Range (0, possiblePrefabs.Length);
GameObject prefab = possiblePrefabs [choiceIndex];
List<Vector2Int> region = FindFreeRegion (new Vector2Int(1, 1));
this.population [region[0].x, region[0].y] = prefab.name;
this.name2Prefab [prefab.name] = prefab;
}
}
private List<Vector2Int> FindFreeRegion (Vector2Int sizeInTiles) {
List<Vector2Int> region = new List<Vector2Int>();
do {
region.Clear();
Vector2Int centerTile = new Vector2Int(UnityEngine.Random.Range(2, 18 - 3), UnityEngine.Random.Range(2, 10 - 3));
region.Add(centerTile);
int initialXCoordinate = (centerTile.x - (int)Mathf.Floor(sizeInTiles.x / 2));
int initialYCoordinate = (centerTile.y - (int)Mathf.Floor(sizeInTiles.y / 2));
for (int xCoordinate = initialXCoordinate; xCoordinate < initialXCoordinate + sizeInTiles.x; xCoordinate += 1) {
for (int yCoordinate = initialYCoordinate; yCoordinate < initialYCoordinate + sizeInTiles.y; yCoordinate += 1) {
region.Add(new Vector2Int(xCoordinate, yCoordinate));
}
}
} while(!IsFree (region));
return region;
}
private bool IsFree (List<Vector2Int> region) {
foreach (Vector2Int tile in region) {
if (this.population [tile.x, tile.y] != "") {
return false;
}
}
return true;
}
public void AddPopulationToTilemap (Tilemap tilemap, TileBase obstacleTile) {
for (int xIndex = 0; xIndex < 18; xIndex += 1) {
for (int yIndex = 0; yIndex < 10; yIndex += 1) {
if (this.population [xIndex, yIndex] == "Obstacle") {
tilemap.SetTile (new Vector3Int (xIndex - 9, yIndex - 5, 0), obstacleTile);
} else if (this.population [xIndex, yIndex] != "" && this.population [xIndex, yIndex] != "Player") {
GameObject prefab = GameObject.Instantiate (this.name2Prefab[this.population [xIndex, yIndex]]);
prefab.transform.position = new Vector2 (xIndex - 9 + 0.5f, yIndex - 5 + 0.5f);
}
}
}
}
}
any help would be awesome even if you can point me in the direction to a how to.
Nice procedural dungeon generator! Just as a suggestion, could you cache the first room at the beginning when you are generating the dungeon? Then you can grab the initialRoomForPlayerSpawn coordinates/ position as a reference point for the character placement.
Room initialRoomForPlayerSpawn = null;
while (roomsToCreate.Count > 0 && createdRooms.Count < numberOfRooms) {
Room currentRoom = roomsToCreate.Dequeue ();
this.rooms [currentRoom.roomCoordinate.x, currentRoom.roomCoordinate.y] = currentRoom;
createdRooms.Add (currentRoom);
AddNeighbors (currentRoom, roomsToCreate);
/* Cache First Room */
if(createdRooms != null && createdRooms.Count <= 1) {
initialRoomForPlayerSpawn = currentRoom;
}
}

Unity3D : How to hide touchscreen keyboard when i select inputfile and inputfield still focus

I've had this problem for a long time. I want to hide touchscreen keyboard when I select inputfile and inputfield still focus. I don't need touchscreen keyboard but I need carretpostion and focus on inputfield(application like calculator).
Thank you everyone for the answer. I solved the problem by custom inputfield. I disable touchscreen keyboard and get carretpostion by OnPointerUp .
code :
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class InputFieldWithOutKeyboard : InputField
{
protected override void Start()
{
keyboardType = (TouchScreenKeyboardType)(-1);
}
public override void OnPointerDown(UnityEngine.EventSystems.PointerEventData eventData)
{
base.OnPointerDown(eventData);
}
public override void OnPointerUp(PointerEventData eventData)
{
Vector2 mPos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(textComponent.rectTransform, eventData.position, eventData.pressEventCamera, out mPos);
Vector2 cPos = GetLocalCaretPosition();
int pos = GetCharacterIndexFromPosition(mPos);
Debug.Log("pos = " + pos);
GameObject.FindWithTag("canvas").GetComponent<Calculator>().carretPostion = pos;
GameObject.FindWithTag("canvas").GetComponent<Calculator>().carretVector = mPos;
base.OnPointerUp(eventData);
}
public Vector2 GetLocalCaretPosition()
{
// if (isFocused)
// {
TextGenerator gen = m_TextComponent.cachedTextGenerator;
UICharInfo charInfo = gen.characters[caretPosition];
float x = (charInfo.cursorPos.x + charInfo.charWidth) / m_TextComponent.pixelsPerUnit;
float y = (charInfo.cursorPos.y) / m_TextComponent.pixelsPerUnit;
Debug.Log("x=" + x + "y=" + y);
return new Vector2(x, y);
// }
// else
// return new Vector2(0f, 0f);
}
private int GetCharacterIndexFromPosition(Vector2 pos)
{
TextGenerator gen = m_TextComponent.cachedTextGenerator;
if (gen.lineCount == 0)
return 0;
int line = GetUnclampedCharacterLineFromPosition(pos, gen);
if (line < 0)
return 0;
if (line >= gen.lineCount)
return gen.characterCountVisible;
int startCharIndex = gen.lines[line].startCharIdx;
int endCharIndex = GetLineEndPosition(gen, line);
for (int i = startCharIndex; i < endCharIndex; i++)
{
if (i >= gen.characterCountVisible)
break;
UICharInfo charInfo = gen.characters[i];
Vector2 charPos = charInfo.cursorPos / m_TextComponent.pixelsPerUnit;
float distToCharStart = pos.x - charPos.x;
float distToCharEnd = charPos.x + (charInfo.charWidth / m_TextComponent.pixelsPerUnit) - pos.x;
if (distToCharStart < distToCharEnd)
return i;
}
return endCharIndex;
}
private int GetUnclampedCharacterLineFromPosition(Vector2 pos, TextGenerator generator)
{
// transform y to local scale
float y = pos.y * m_TextComponent.pixelsPerUnit;
float lastBottomY = 0.0f;
for (int i = 0; i < generator.lineCount; ++i)
{
float topY = generator.lines[i].topY;
float bottomY = topY - generator.lines[i].height;
// pos is somewhere in the leading above this line
if (y > topY)
{
// determine which line we're closer to
float leading = topY - lastBottomY;
if (y > topY - 0.5f * leading)
return i - 1;
else
return i;
}
if (y > bottomY)
return i;
lastBottomY = bottomY;
}
// Position is after last line.
return generator.lineCount;
}
private static int GetLineEndPosition(TextGenerator gen, int line)
{
line = Mathf.Max(line, 0);
if (line + 1 < gen.lines.Count)
return gen.lines[line + 1].startCharIdx - 1;
return gen.characterCountVisible;
}
}
You can use something like this
TouchScreenKeyboard keyboard;
void Update()
{
if (keyboard != null)
{
if (Input.deviceOrientation == DeviceOrientation.FaceDown)
keyboard.active = false;
if (Input.deviceOrientation == DeviceOrientation.FaceUp)
keyboard.active = true;
}
}
it will retrieve the TouchScreenKeyboard and after that, you can active or deactive it as you want.

Unity stops responding upon hitting play only when I uncomment a method

When I uncomment the line "ConnectMaze(maze)" in the Start() method, Unity instantly stops responding when I hit play. None of the Debug.Log statements show up in the console. If I comment out that specific line, I am able to see the Debug.Log statements in the console and Unity does respond. I am thinking that there could be an infinite loop in the ConnectMaze while loop, however wouldn't the Debug.Log statements prior to the loop still show up in the console? Below is the code that is causing the issue.
using UnityEngine;
using System.Collections;
public class MazeBase : MonoBehaviour {
public const int mazeLength = 11;
private int[,] maze = new int[mazeLength,mazeLength];
private int numWalls;
// Use this for initialization
void Start () {
Debug.Log ("Initialize Start");
InitializeMaze (maze);
Debug.Log ("Initialize End");
Debug.Log ("Connectivity Start");
ConnectMaze (maze);
Debug.Log ("Connectivity End");
MazeGenerator.Generate (transform,maze);
}
// Update is called once per frame
void Update () {
}
private void CreateMazeBlock(){
Vector3 mousePos = Input.mousePosition;
mousePos.z = 10;
Vector3 cameraPos = Camera.main.ScreenToWorldPoint (mousePos);
int cameraPosX = (int)Mathf.Round (cameraPos.x);
int cameraPosZ = (int)Mathf.Round (cameraPos.z);
if (maze [cameraPosX, cameraPosZ] != 1) {
maze [cameraPosX, cameraPosZ] = 1;
MazeGenerator.GenerateSingleBlock (transform, cameraPosX, cameraPosZ);
}
}
private void DeleteMazeBlock(){
Vector3 mousePos = Input.mousePosition;
mousePos.z = 10;
Vector3 cameraPos = Camera.main.ScreenToWorldPoint (mousePos);
int cameraPosX = (int)Mathf.Round (cameraPos.x);
int cameraPosZ = (int)Mathf.Round (cameraPos.z);
if (maze [cameraPosX, cameraPosZ] == 1) {
maze [cameraPosX, cameraPosZ] = 0;
MazeGenerator.DeleteSingleBlock (cameraPosX, cameraPosZ);
}
}
private void InitializeMaze(int[,] maze){
for (int i = 0; i < mazeLength; i++) {
for (int j = 0; j < mazeLength; j++) {
if (i == 0 || i == mazeLength - 1 || j == 0 || j == mazeLength - 1) {
maze [i, j] = -1;
numWalls++;
} else if (Random.Range (0, 100) < 50) {
bool createWall = true;
//Following if statements prevent a 2x2 square of walls
if (IsWall (maze, i - 1, j - 1) && IsWall (maze, i - 1, j) && IsWall (maze, i, j - 1)) {
createWall = false;
}else if (IsWall (maze, i - 1, j + 1) && IsWall (maze, i - 1, j) && IsWall (maze, i, j + 1)) {
createWall = false;
}else if (IsWall (maze, i + 1, j - 1) && IsWall (maze, i + 1, j) && IsWall (maze, i, j - 1)) {
createWall = false;
}else if (IsWall (maze, i + 1, j + 1) && IsWall (maze, i + 1, j) && IsWall (maze, i, j + 1)) {
createWall = false;
}
if(createWall){
maze [i, j] = -1;
numWalls++;
}
}
}
}
}
private bool IsWall(int[,] maze, int i, int j){
return maze [i, j] < 0;
}
private void ConnectMaze(int[,] maze){
Debug.Log ("GetNextTile Start");
ArrayList startTile = GetNextTile (maze,0);
Debug.Log ("GetNextTile End");
int startX = (int)startTile[0];
int startZ = (int)startTile[1];
int numberOfFloods = 1;
Debug.Log ("Flood Fill 1 Start");
int numFound = FloodFill(maze,startX,startZ,numberOfFloods);
Debug.Log ("Flood Fill 1 End");
while (numFound != (mazeLength * mazeLength) - numWalls) {
ArrayList nextWallTile = GetNextTile (maze, 1);
int wallX = (int)nextWallTile[0];
int wallZ = (int)nextWallTile[1];
maze [wallX, wallZ] = 0;
numWalls--;
numberOfFloods++;
int numFound2 = FloodFill(maze,startX,startZ,numberOfFloods);
if(numFound2 == (mazeLength*mazeLength)-numWalls){
break;
}
if (numFound2 - numFound > 1) {
numFound = numFound2;
} else {
maze [wallX, wallZ] = 2;
numWalls++;
}
int temp = (mazeLength * mazeLength) - numWalls;
Debug.Log ("Number of empty tiles: " + temp);
Debug.Log ("Number of tiles found: " + numFound);
}
}
private int FloodFill(int[,] maze, int x, int z,int value){
int numEmptyTilesFound = 0;
if (x < 0 || z < 0 || x >= mazeLength || z >= mazeLength) {
return 0;
}
if (maze [x, z] == -1 || maze [x, z] == value) {
return 0;
}
maze [x, z] = value;
numEmptyTilesFound++;
numEmptyTilesFound += FloodFill (maze, x - 1, z, value);
numEmptyTilesFound += FloodFill (maze, x + 1, z, value);
numEmptyTilesFound += FloodFill (maze, x, z - 1, value);
numEmptyTilesFound += FloodFill (maze, x, z + 1, value);
return numEmptyTilesFound;
}
private ArrayList GetNextTile(int[,] maze,int value){
int startX = 0;
int startZ = 0;
bool search = true;
for (int i = 0; i < mazeLength; i++) {
for (int j = 0; j < mazeLength; j++) {
if (maze [i, j] == value) {
startX = i;
startZ = j;
search = false;
}
if(!search){
break;
}
}
if(!search){
break;
}
}
ArrayList startingPoint = new ArrayList ();
startingPoint.Add (startX);
startingPoint.Add (startZ);
return startingPoint;
}
}

Unity - Change cube color before placement

So, I am making a Minecraft-like game, and you basically move around on a pre-generated floor and place blocks. My problem is that I need to get the ability for the player to change the block color by hitting a numberpad key, ex: 1 for red, 2 for blue, and so on.
Here is the script that generates the floor, and handles block placement.
var range : float = Mathf.Infinity;
var hit : RaycastHit;
for (var y = -4; y < 50; ++y)
for (var x = -4; x < 50; ++x) {
var block : GameObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
block.transform.position = transform.position + Vector3(x, -3, y);
}
function Update () {
if (Input.GetMouseButtonDown(0) && Hit()) {
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = hit.transform.position + hit.normal;
}
if (Input.GetMouseButtonDown(1) && Hit())
Destroy(hit.transform.gameObject);
if (Input.GetKeyDown(KeyCode.Keypad1)) {
cube.renderer.material.color = Color.red;
}
if (Input.GetKeyDown(KeyCode.Keypad2)) {
cube.renderer.material.color = Color.blue;
}
if (Input.GetKeyDown(KeyCode.Keypad3)) {
cube.renderer.material.color = Color.yellow;
}
if (Input.GetKeyDown(KeyCode.Keypad4)) {
cube.renderer.material.color = Color.green;
}
if (Input.GetKeyDown(KeyCode.Keypad5)) {
cube.renderer.material.color = Color.magenta;
}
}
function Hit() : boolean {
return Physics.Raycast(transform.position, transform.forward, hit, range, 1);
}