GENERATION - G1
EDWARD KWAN-SHU YEE JESSIE ANGUS SHIREN GENG
CA PATTERN TYPES STILL LIFE CA Ship on Long Boat
Beehive Still life
Big S Still
Long Boat Still
Loop Still
OSICILLATOR CA Figure 8
Fore and Back
Clock
Mazing
Quadpole
Beacon
Glider
Octagon 2
Test Tube
Griddle and
Coe’s 8
Table on Table
Pulsar
Toad
Unix
S C R I P T S
1 ...AIR Unity project folder CA\Assets\Scripts\CaManager.cs //CaPattern = Random.Range(1, 3); //if (CaPattern == 1) /*{ CA.addIndicieShape(pos, CaManager.CAshapes[shapes[3]], 1);
...AIR Unity project folder CA\Assets\Scripts\CaManager.cs using UnityEngine; using System.Collections;
7
...AIR Unity project folder CA\Assets\Scripts\CaManager.cs CA[x,z].sickness = 0;
13
...AIR Unity project folder CA\Assets\Scripts\CaManager.cs CA[x,z].NextValue = 100; } //CaPattern = Random.Range(1, 3); hasModifiedRules = true; else //if (CaPattern == 1) } { CA.addIndicieShape(pos, CaManager.CAshapes[shapes[2]], 2); /*{ //if the voxel is veg and is in tree area }*/ else if (CA[x,z].type == 2 && nativeVegHere [indicie] < vegLevel && nativeVegHere [indicie] != 0) CA.addIndicieShape(pos, CaManager.CAshapes[shapes[3]], 1); {
using System.Collections.Generic;
public class CaManager : MonoBehaviour { //SET UP STUFF: IGNORE! [Header("Load CSV file of CA patterns here")] public TextAsset[] CAPatternsFromCSV; public static bool hasUpdated = true; public static bool hasCleaned = true;
.CAshapes [shapes [Random.Range CA.addIndicieShape (pos, (0, shapes.Length)]], Random.Range (0, nTypes));
}
7
CA.addIndicieShape(pos, CaManager.CAshapes[shapes [CSVPattern1]], colourType1);
public static class CustomExtensions {
*** ThisVoxel > the current voxel we are working with
DeadCellRules.Add (8); //DeadCellRules.Add (4);
CA.addIndicieShape(pos, CaManager.CAshapes[shapes [CSVPattern3]], colourType3);
priceMultiAtI [tileNumber] = xyzToI.getAttributeStatic (1, tileNumber, me); CA.addIndicieShape (pos, .CAshapes [shapes [Random.Range }*/
//////////How many neighbours a cell must have to die //AliveCellRules.Add (1); //AliveCellRules.Add (3);
} }
/////////23MAY COPYME01////////////////// ("Sandbox settings")] [Header public int CSVPattern1; public int colourType1; public Vector3 position1 = new Vector3 (20, 0, 20); public int CSVPattern2; public int colourType2; public Vector3 position2 = new Vector3 (30, 0, 30); public int CSVPattern3; public int colourType3; public Vector3 position3 = new Vector3(40, 0, 40); public bool testRulesOnly;
if (definedSeed == true) { if (CSVPattern1 != 0) { //CA.addIndicieShape (new Vector3 (30, 0, 30), CaManager.CAshapes [shapes [testPattern1]], colourType1); .CAshapes [shapes CA.addIndicieShape (position1, [CSVPattern1]], colourType1);
//MAKE SURE TO delete randomSeed set up under 'CA Parameters' heading!!!!
}
public bool randomSeed; public bool definedSeed; /////////END 23MAY COPYME01//////////////////
if (CSVPattern2 != 0) { CA.addIndicieShape (position2, [CSVPattern2]], colourType2); }
2
("Value Multipliers")] [Header public int howManyAttributes; public float[] characterCompiles; bool checkedAttributes = false; bool[] calculatedMultipliers; GameObject me; int indicie;
if (CSVPattern3 != 0) { CA.addIndicieShape (position3, [CSVPattern3]], colourType3); }
coel
.CAshapes [shapes
8
.CAshapes [shapes
if (isPaperSciRoc) { PapSciRoc = 3; refreshrate = 0; }
*/
// Alive Cell rules applied (these alive cells die) else if (CA[x, z].Value > 0 && !(AliveCellRules.Contains (aliveNeighbourCount))) { CA[x, z].NextValue = 0; //NextCAvalues[x, z] = CA[x, z].Value; CA[x, z].sickness = 0;
case 2: characterCompiles = runaway; break;
public int SicknessElev; //How high can the player's sickness infect voxels?
[Header("Player's position in the CA grid")] //So we can find where the player is //player's location in indicies
}
if (CSVPattern3 != 0) { //which character value map? CA.addIndicieShape(pos, CaManager.CAshapes[shapes switch (character) CA[x,z] = CA [x, z].CAinheritance (typeFreq, valueSum, { [CSVPattern3]], colourType3); neighbourSickness, deathRate, maxValue); case 1: characterCompiles = old; }*/ } break;
[Header("CA Interacting with Player")] public int sickRadii;
public static bool canPetrify; public bool setPetrify;
14
// Regular CA Environment ///////////////////////////////////////// else { // Dead cell rules applied (these dead cells become alive) if (CA[x, z].Value <= 0 && DeadCellRules.Contains (aliveNeighbourCount)) {
old = new float[6]{0,0,0,0.5f,1,0}; runaway = new float[6]{0,0,0,0.5f,1,0}; dog = new float[6]{0,0,0,0.5f,1,0}; developor = new float[6]{0,0,0,0.5f,1,0}; environmentalist = new float[6]{0,0,0,0.5f,1,0};
case 3: } characterCompiles = dog; } break;
// Alive Cell rules applied (these alive cells continue to be alive) else if (CA[x, z].Value > 0) { CA [x, z].NextValue = CA [x, z].CAvalueSampling (typeFreq, valueSum, deathRate, maxValue); //if the there are neighbours of the same type, make this cell an average of those neighbours values, otherwise keep it the same.
//23MAY COPY ME //
public int playerIndiceX; public int playerIndiceZ; Vector3 playerPosPrev; public static Vector3 playerPos; public static int playerX; public static int playerZ; GameObject player;
case 5: characterCompiles = environmentalist; break;
if (definedSeed == true) default: { characterCompiles = old; break; } if (neighbourSickness > 0) if (CSVPattern1 != 0) { [Header("CA Parameters")] //DEBUG CA DOLLAR CODE CA[x, z].sickness++; //How quick do Voxels fall out of the sky? } } { public int deathRate; } /* } //CA.addIndicieShape (new Vector3 (30, 0, 30), //How far does the local rule modifier bubble extend? // Update is called once per frame public int ruleModifierRange = 2; void Update() CaManager.CAshapes [shapes [testPattern1]], colourType1); { /////////////// Reset //How large are vovels compared to the 1m landscape grid? values /////////////////////////////////////////// public static float grainSize; createSickness(); .CAshapes [shapes CA.addIndicieShape (position1, for (int i = 0; i < typeFreq.Length + 1; i++) testMultipliers = new float[tileManager.gridXDim * public float setGrainSize; { canPetrify = setPetrify; ...AIR Unity project folder CA\Assets\Scripts\CaManager.cs 3 [CSVPattern1]], colourType1); if (i < typeFreq.Length)
tileManager.gridZDim];
//How high can voxels go? //Voxels have a 'Value' out of 255 public int maxValue; //this value is divided by the maxYheight to produce a Y position (ie. height) for each voxel public int maxYheight = 10;
S T
}
case 4: characterCompiles = developor; break;
...AIR Unity project folder CA\Assets\Scripts\CaManager.cs grainSize = setGrainSize;
9
}
if (SpecialRulesAroundPlayer) { Invoke("returnToRegularRules", 3); }
...AIR Unity project folder CA\Assets\Scripts\CaManager.cs { typeFreq[i] = 0; valueSum[i] = 0; neighbourSickness = 0; }
15
for (int i = 0; i < (tileManager.gridXDim * tileManager.gridZDim); i++)
typePop [i] = 0; if (CSVPattern2 != 0) dollarsPerType [i] = 0; public bool localisedSpecialRules; } public bool SpecialRulesAroundPlayer; { bool hasModifiedRules = false; // Copy default rules back. { if (hasModifiedRules == true) CA.addIndicieShape (position2, .CAshapes [shapes { if (hasUpdated) //IGNORE debug stuff DeadCellRules = new HashSet<int>(mDeadCellRules); { testMultipliers [i] = setTestMultipliers; [CSVPattern2]], colourType2); AliveCellRules = new HashSet<int>(mAliveCellRules); hasUpdated = false; [Header("What Landscape attributes are we using?")] } updateCA(); public int dollarMultiplierAtt; //which attribute from the landscape team are } } } we using for the $ multiplier?
O M
//limit CA calc update to specific time intervals elapseTime += Time.deltaTime; if (elapseTime > refreshrate) {
public int specialRulesAtt; //which attribute are we choosing to base the special rules off?
hasUpdated = true;
*/
[Header("Voxel population settings")] //How many types of voxels are there? public int setNTypes; public static int nTypes;
C
}
playerPos = new Vector3(Mathf.Round(player.transform.position.x) * 1/ grainSize * 1/grainSize, 0, Mathf.Round(player.transform.position.z) * 1/ grainSize * 1/grainSize); playerX = (int)playerPos.x; playerZ = (int)playerPos.z;
//What's the population of each voxel type? public static int[] typePop; public int[] NStypePop;
}
}
public void updateCA() {
//stuff used when checking CA values for every cell int nx, nz; int[] typeFreq = new int[nTypes]; int[] valueSum = new int[nTypes]; int neighbourSickness = 0;
//updated CA public static Dictionary<string, Vector2[]> CAshapes; public static string[] shapes;
if (randomSeed == true) { //int CaPattern; [Header("Debug Stuff")] //debug these set landscape value multipliers to 1 public string[] Loadedshapes; public float[] testMultipliers; public float setTestMultipliers; [Header("Fun Stuff!")]
...AIR Unity project folder CA\Assets\Scripts\CaManager.cs public bool isPaperSciRoc; public static int PapSciRoc = 1;
4
//check entire grid for (int x = 0; x < CAgridX; x++) { for (int z = 0; z < CAgridZ; z++) { if (CA[x,z].isPetrified == false) { int aliveNeighbourCount = 0; ...AIR Unity project folder CA\Assets\Scripts\CaManager.cs
}
E
else { CA[x, z].NextValue = 0; } CA[x, z].sickness = 0;
...AIR Unity project folder CA\Assets\Scripts\CaManager.cs
16
for (int i = 0; i < 300; i++) // i < ______ is how many starting CA patterns will be seeded { Vector3 pos = new Vector3 (Random.Range (0, CAgridX), 0, Random.Range (0, CAgridZ));
A N A G
Vector2[] glider = new Vector2[] { new Vector2(0, 0), new Vector2(0, 1), new Vector2(0, 2), new Vector2(1, 2), new Vector2(2, 1) };
priceMultiAtI [indicie] = xyzToI.getAttributeStatic (1, indicie, me);
// Use this for initialization void Awake() {
for (int attributeNumber = 0; attributeNumber < howManyAttributes; attributeNumber++) { //priceMultiAtI [indicie] = priceMultiAtI [indicie] + xyzToI.getAttributeStatic (attributeNumber, indicie, me) * characterCompiles[attributeNumber]; }
grainSize = setGrainSize; CAgridX = setCAgridX; CAgridZ = setCAgridZ; CAshapes = new Dictionary<string, Vector2[]> (); CAPatternsFromCSV.loadCApattern(ref CAshapes);
// load the names of the patterns into an array shapes = new string[CAshapes.Keys.Count]; Loadedshapes = new string[CAshapes.Keys.Count]; int count =0; foreach (KeyValuePair<string, Vector2[]> keyValue in CAshapes) { shapes[count] = keyValue.Key; Loadedshapes [count] = keyValue.Key; count++; } player = gameObject.GetComponent<clampMovement> ().player; Sandbox = setSandbox;
}
R
//add this cell to the overal population figure of this type if (CA [x, z].sickness == 0 && CA[x,z].isPetrified == false) { //populate typePOp with CA cells this round typePop [CA [x, z].type]++; }
calculatedMultipliers[indicie] = true;
attAtPlayer = elevationHeightHere[CustomExtensions.convertXZtoI (playerIndiceX, playerIndiceZ)];
else if (CA[x,z].type == 2) { // Check neighbours values for (int i = 1; i <= 1; i++) //give it these rules {
void Start() { specialRulesAtt = gameObject.GetComponent<landscapeManager> ().attDisplayedOnTile; //Create a grid of trimVoxels for CA calcs CA = new trimVoxel[CAgridX, CAgridZ]; ...AIR Unity project folder CA\Assets\Scripts\CaManager.cs 5 CA.populateCAZero(); //These trimVoxels initially need all their attributes set to default values (to 0) nTypes = setNTypes; //how many types of voxels do we have? dollarsPerType = new float[nTypes + 1]; //array that stores how much money each voxel type has //regular CA rules DeadCellRules = new HashSet<int> { 3 }; AliveCellRules = new HashSet<int> { 2, 3 }; //modified CA rules mDeadCellRules = new HashSet<int>(DeadCellRules); mAliveCellRules = new HashSet<int>(AliveCellRules); //Population stuff typePop = new int[nTypes + 1]; NStypePop = new int[nTypes + 1]; NStypePop = typePop; ////////Dollar stuff //How many attributes are in the CSV? (gameObject.GetComponent<landscapeManager> ArrayList tempList = ().attributes); howManyAttributes = ((double[])tempList[0]).Length; //set up the character multiplier configurations characterCompiles = new float[howManyAttributes];
// neighbours[count] = CA[nx, nz]; // count++; if (CA[nx, nz].Value > 0) //CAvalues[nx, nz] >
//DEBUG DOLLAR CALCS /* indicie = gameObject.GetComponent<tileManager> ().convertXYZtoI (x, z);
//ACTUAL CODE
{
N
indicie = gameObject.GetComponent<landscapeManager> ().convertXYZtoI (x, z); //priceMultiAtI [indicie] = testMultipliers [indicie]; //priceMultiAtI [indicie] = gameObject.GetComponent<xyzToI> ().getAttributePlus ((dollarMultiplierAtt + 1), indicie);
// priceMultiAtI [indicie] = gameObject.GetComponent<xyzToI> ().getAttributePlus ((dollarMultiplierAtt + 1), indicie);
////////////How many neighbours a cell must have to become alive ...AIR Unity project folder CA\Assets\Scripts\CaManager.cs if (CA [x, z].sickness == 0) DeadCellRules.Add (0); { dollarsPerType [CA [x, z].type] = dollarsPerType DeadCellRules.Add (1); [CA [x, z].type] + priceMultiAtI [indicie]; } DeadCellRules.Add (2); else if (CA [x, z].sickness > 0) { //add to sickness value } DeadCellRules.Add (3); dollarsPerType [(dollarsPerType.Length 1)] = dollarsPerType [(dollarsPerType.Length 1)] + priceMultiAtI DeadCellRules.Add (4); [indicie]; } } } DeadCellRules.Add (5); } DeadCellRules.Add (6); // /////////////////////////////////////////////////// } DeadCellRules.Add (7); // REFCA02 Rules /////////////////////////////////////////// // /////////////////////////////////////////////// CA[x, z].Value = CA[x, z].NextValue; DeadCellRules.Add (8); CA [x, z].voxPosition.y = (Mathf.Round(CA[x, z].Value / //DeadCellRules.Add (4); //If the voxel is water and in flood zone maxYheight 1)); 0)
E
12
*/
///// DeadCellRules.Clear (); AliveCellRules.Clear (); if (nx < CAgridX && nx >= 0 && nz >= 0 && nz < /////// {
//CA DOLLAR CALC
dollarsPerType [CA [x, z].type] = dollarsPerType [CA [x, z].type] + 1 * priceMultiAtI [indicie];
for (int k = 1; k <= 1; k++) { if (!(i == 0 && k == 0)) { nx = x + i; //nx is the x indicie location of the neighbouring cell being checked nz = z + k; //nz is the z indicie location of the neighbouring cell being checked CAgridZ)
T
//heal a cell if it reaches a certain value if (CA[x, z].Value > SicknessElev) { CA[x, z].sickness = 0; }
} ...AIR Unity project folder CA\Assets\Scripts\CaManager.cs
aliveNeighbourCount += 1; // Alive neighbour detected, add one to count ...AIR Unity project folder CA\Assets\Scripts\CaManager.cs 11 typeFreq[CA[nx, nz].type] += 1; valueSum[CA[nx, nz].type] += CA[nx, nz].Value; neighbourSickness += CA[nx, nz].sickness; }
if (CA[x,z].type == 0 && elevationHeightHere[indicie] != 0 && elevationHeightHere [indicie] < floodLevel) {
calculatedMultipliers = new bool [landscapeManager.gridXDim * landscapeManager.gridZDim];
S I
for (int i = 0; i < calculatedMultipliers.Length; i++) { calculatedMultipliers[i] = false; }
//AliveCellRules.Add (3);
...AIR Unity project folder CA\Assets\Scripts\CaManager.cs 6 //single attribute priceMultiAtI [tileNumber] = xyzToI.getAttributeStatic (1, tileNumber, me);
} */
//multiple value attributes for (int attributeNumber = 0; attributeNumber < specialRulesHere.Length; attributeNumber++) { characterCompiles = new float [5] {1,1,1,1,1}; //priceMultiAtI [tileNumber] = gameObject.GetComponent<xyzToI> ().getAttributePlus ((dollarMultiplierAtt + 1), attributeNumber); }
if (isPaperSciRoc) { PapSciRoc = 3; refreshrate = 0; } //DEBUG CA DOLLAR CODE /* testMultipliers = new float[tileManager.gridXDim * tileManager.gridZDim]; for (int i = 0; i < (tileManager.gridXDim * tileManager.gridZDim); i++) { }
{
DeadCellRules.Clear (); AliveCellRules.Clear ();
}
CA[x,z].NextValue = 0; hasModifiedRules = true;
}
{
for (int Xsick = sickRadii; Xsick <= sickRadii; Xsick++) { for (int Zsick = sickRadii; Zsick <= sickRadii; Zsick++) { if (playerX + Xsick>= 0 && playerX + Xsick < CAgridX && playerZ + Zsick >= 0 && playerZ + Zsick < CAgridZ)
//END 23MAY SAMPLE CODE FOR RULES HERE!!! TYPE 3 ALWAYS //23MAY SAMPLE CODE FOR RULES HERE!!! TYPE 3 ALWAYS LIVES// ...AIR Unity project folder CA\Assets\Scripts\CaManager.cs ...AIR Unity project folder CA\Assets\Scripts\CaManager.cs 12 { LIVES// if (CA [playerX + Xsick, playerZ + Zsick].Value < else if (CA[x,z].type == 2) { //give it these rules
///// DeadCellRules.Clear (); AliveCellRules.Clear (); ///////
SicknessElev && CA [playerX + Xsick, playerZ + Zsick].sickness == 0 && CA [playerX + Xsick, playerZ + Zsick].Value > 0) { CA [playerX + Xsick, playerZ + Zsick].sickness++; } }
///IGNORE VEG STUFF FOR NOW } /* ////////////How many neighbours a cell must have to } become alive //if the voxel is veg and is in tree area } DeadCellRules.Add (0); } DeadCellRules.Add (1); else if (CA[x,z].type == 0 && nativeVegHere [indicie] < } DeadCellRules.Add (2); DeadCellRules.Add (3); vegLevel && nativeVegHere [indicie] != 0 && DeadCellRules.Add (4); DeadCellRules.Add (5); elevationHeightHere [indicie] > floodLevel) DeadCellRules.Add (6); { DeadCellRules.Add (7); DeadCellRules.Add (8); //DeadCellRules.Add (4);
}
CA[x,z].type = 2;
}
typeFreq would record this as typeFreq[] = {2, 3, 3}. The 0th indicie
...ty project folder CA\Assets\Scripts\CustomExtensions.cs 2 ...ty project folder CA\Assets\Scripts\CustomExtensions.cs // TYPE 1 LOOSES TO TYPE 2 public static void populateCAZero(this trimVoxel[,] CAgrid) { ______________ ACCESSING typeFreq // If this Voxel is TYPE 1 && it has a neighbour TYPE 2, make this voxel for (int i = 0; i < CAgrid.GetLength(0); i++) _____________________________________________________________________ { type 2 for (int j = 0; j < CAgrid.GetLength(1); j++) Voxel types are represented by a number, and so each voxel type is also the
if (randomSeed == true) { //int CaPattern; for (int i = 0; i < 300; i++) // i < ______ is how many starting CA patterns will be seeded { Vector3 pos = new Vector3 (Random.Range (0, CAgridX), 0, Random.Range (0, CAgridZ));
///IGNORE VEG STUFF FOR NOW /* //if the voxel is veg and is in tree area else if (CA[x,z].type == 0 && nativeVegHere [indicie] < vegLevel && nativeVegHere [indicie] != 0 && elevationHeightHere [indicie] > floodLevel) { DeadCellRules.Clear (); AliveCellRules.Clear (); CA[x,z].type = 2;
{
indicie of how many neighbours of that type.
8
CAgrid[i, j] = new trimVoxel(0, 0, i, j);
} If you would like to see how many type 1 neighbours ThisVoxel has: if (ThisVoxel.type == 1 && typeFreq[2] > 0) } typeFreq[1] = ...... (the answer is 3!) } { public static void addIndicieShape(this trimVoxel[,] CAgrid, Vector3 ThisVoxel.type = 2; indicieLocation, Vector2[] pattern, int type) ___________________________________________________________________________________ { _____________________ } ...ty project folder CA\Assets\Scripts\CustomExtensions.cs 4 for (int i = 0; i < pattern.Length; i++) { *** valueSum > sum of the values for all neighbouring voxels int xPos = (int)(indicieLocation.x + pattern[i].x); //DEFAULT CASAMPLING *** neighbourSickness > a neighbourSickness > 0 means a neighbouring voxel is int zPos = (int)(indicieLocation.z + pattern[i].y); sick /*if (ThisVoxel.type == 1 && typeFreq[4] > 0) if (xPos >= 0 && xPos < CAgrid.GetLength(0) && zPos >= 0 && zPos < // if the voxel is alive and stays alive CAgrid.GetLength(1)) __________________ METHOD { { SHORTUCTS____________________________________________________________________ public static int CAvalueSampling(this trimVoxel ThisVoxel,int[] typeFreq,int[] CAgrid[xPos, zPos].Value = type * 10 + 20; CAgrid[xPos, zPos].type = type; ThisVoxel.NextValue = ThisVoxel.NextValue + 40; You also have access to some methods (formualae) I have already written. In valueSum, int deathRate, int maxValue) { } particular: } }*/ } *** findMaxIndicie(typeFreq) > will find the most common neighbouring voxel type int cellVal = ThisVoxel.Value; *** findMinIndicie(typeFreq) > will find the rarest common neighbouring voxel public static void loadCApattern(this TextAsset[] csv, ref Dictionary<string, type /*else if (ThisVoxel.type == 1 && typeFreq[2] > 0) int averageVal = cellVal; Vector2[]> DicOut) { ie. ThisVoxel.type = typeFreq.findMaxIndicie(); sets this voxel to the most { common neighbouring type char lineSeperater = '\n'; // It defines line seperate character ThisVoxel.type = typeFreq.findMinIndicie(); sets this voxel to the least ThisVoxel.NextValue = ThisVoxel.NextValue 20; //everything in here happens when this voxel has neighbours of its same type char fieldSeperator = ','; // It defines field seperate chracter common neighbouring type }*/ if (typeFreq [ThisVoxel.type] != 0) for (int j = 0; j < csv.Length; j++) */ { { //TYPE 1 looses to TYPE 2 // Set new type int chance = Random.Range (0, 4); // create an array list to add all the attributes to as they are read int cellVal = 0; /*if (ThisVoxel.type == 1 && typeFreq[2] > 0) from the CSV file ThisVoxel.type = typeFreq.findMaxIndicie(); string keyout = ""; { List<Vector2> outArrayList = new List<Vector2>(); if (chance > 0) ////////////REFCE04//////////// // DO things per voxel type ThisVoxel.type = 2; // Separate each row with the lineSeperater character { string[] records = csv[j].text.Split(lineSeperater); switch (ThisVoxel.type) } cellVal = valueSum [ThisVoxel.type]/typeFreq[ThisVoxel.type]; { // The first row is the setup information, Key/Value pair with even indicies being strings as a key and the odd the values default: } string[] SetupRow = records[0].Split(fieldSeperator); cellVal = ThisVoxel.CAvalueSampling(typeFreq, valueSum, deathRate, //TYPE 2 looses to TYPE 0 maxValue); break; // Loop through each key in the SetupRow, this will be the even if (ThisVoxel.type == 2 && typeFreq[0] > 0) } else elements of the string array, SetupRow[i] // that is i=0,2,4 ect so in the for loop not i++ but i=i+2 //make this cell sick if neighbours are sick { { 9 ...ty project folder CA\Assets\Scripts\CustomExtensions.cs 3 ...ty project folder CA\Assets\Scripts\CustomExtensions.cs ThisVoxel.type = 0; cellVal = valueSum [ThisVoxel.type]/typeFreq[ThisVoxel.type] for (int i = 0; i < SetupRow.Length; i = i + 2) ThisVoxel.NextValue = cellVal; //NextCAvalues[x, z] = cellVal; { }*/ string key = SetupRow[i]; if (neighbourSickness > 0) deathRate /2; // On each of thoes keys if they match the following do somehting { with the value, which is i+1, the next value in the CSV startup } ThisVoxel.sickness = ThisVoxel.sickness + 1; }
}
row switch (key) { case "Name": keyout = SetupRow[i + 1]; break; default: break; }
// For the rest of the rows read each row and split it up into the different attributes storing them in an arraylist. // Remember that the first row is setup so we much check from i=1 not zero! for (int i = 1; i < records.Length; i++) { string[] fields = records[i].Split(fieldSeperator);
{
{ ThisVoxel.NextValue = ThisVoxel.NextValue 20; }*/
// error handle break; } if (!int.TryParse(fields[1], out zval)) { // error handle break; }
//dont touch /*if (ThisVoxel.type == 1 && typeFreq[2] > 0) { if (averageVal <= deathRate) ThisVoxel.type = 2; } { //TYPE 2 looses to TYPE 0 if (ThisVoxel.type == 2 && typeFreq[0] > 0) cellVal = deathRate; { ThisVoxel.type = 0; } //TYPE 1 looses to TYPE 2
xval, outArrayList.Add(new Vector2( } DicOut.Add(keyout, outArrayList.ToArray());
18
O N
}
} ////SPEND MOST OF YOUR TIME HERE! public static Vector3 fromGlobalPosToXZ(this Vector3 position) { //if a cell has no neighbours of its same type, but has more than one return position * CaManager.grainSize; } neighbours, do these.... // /////////////////////////////////////////////////////////////////// else if (typeFreq [ThisVoxel.type] > 1 && cellVal < maxValue) public static int convertXZtoI(int myX, int myZ) // REFCE03 Change the Y position { // /////////////////////////////////////////////////////////////////// { int indicie = myX * landscapeManager.gridXDim + myZ; }
return indicie;
...ty project folder CA\Assets\Scripts\CustomExtensions.cs 4 //DEFAULT CASAMPLING // if the voxel is alive and stays alive public static int CAvalueSampling(this trimVoxel ThisVoxel,int[] typeFreq,int[] valueSum, int deathRate, int maxValue) {
...ty project folder CA\Assets\Scripts\CustomExtensions.cs }
if (ThisVoxel.type == 1 && typeFreq [2] != 0) { public static void patternAtLocation (this string patternName, int deadZone, Vector3 pos, int type) ThisVoxel.type = 2; { int cellVal = ThisVoxel.Value; int myX = (int)pos.x; int averageVal = cellVal; } int myZ = (int)pos.z;
10
if (myX >= 0 && myX < landscapeManager.gridXDim && myZ >= 0 && myZ < landscapeManager.gridZDim) {
//everything in here happens when this voxel has neighbours of its same type if (typeFreq [ThisVoxel.type] != 0) { int chance = Random.Range (0, 4);
/*if (ThisVoxel.type == 1 && typeFreq [4] != 0) { if (landscapeManager.isDead [myX, myZ] == false) { if (chance > 0) // make deadzone { ThisVoxel.NextValue = ThisVoxel.NextValue + 40; for (int x = myX deadZone; x < myX + deadZone; x++) { cellVal = valueSum [ThisVoxel.type]/typeFreq[ThisVoxel.type];
for (int z = myZ deadZone; z < myZ + deadZone; z++) {
}
if (x >= 0 && x < landscapeManager.gridXDim && z >= 0 && z < landscapeManager.gridZDim) { landscapeManager.isDead [x, z] = true;
else { cellVal = valueSum [ThisVoxel.type]/typeFreq[ThisVoxel.type] deathRate /2; }
}
}
if (cellVal <= deathRate) { cellVal = deathRate; }
}
}
// spawn shape CaManager.CA.addIndicieShape (pos.fromGlobalPosToXZ (), CaManager.CAshapes [patternName], type);
/*if (ThisVoxel.type == 1 && typeFreq[2] != 0) { ThisVoxel.type = 2; }*/
landscapeManager.invokeRefreshDeadZone(myX, myZ);
}
//dont touch if (averageVal <= deathRate) { cellVal = deathRate; }
}
}
/*////////////REFCE05//////////// //Sets Voxel type 1 to least common neighbour if (ThisVoxel.type == 1) { //ThisVoxel.type = typeFreq.findMinIndicie (); }
////SPEND MOST OF YOUR TIME HERE! //if a cell has no neighbours of its same type, but has more than one neighbours, do these.... else if (typeFreq [ThisVoxel.type] > 1 && cellVal < maxValue) { if (ThisVoxel.type == 1 && typeFreq [2] != 0) { ThisVoxel.type = 2; }
if (CaManager.PapSciRoc > 1) { /////REFCE02///////// //PAPER SCISSCORS ROCK TEST
...ty project folder CA\Assets\Scripts\CustomExtensions.cs }*/
// TYPE 0 LOOSES TO TYPE 1 5
/*if (ThisVoxel.type == 1 && typeFreq[2] != 0) { cellVal = ThisVoxel.NextValue 20; }*/
...ty project folder CA\Assets\Scripts\CustomExtensions.cs 11 // If this Voxel is TYPE0 && it has a neighbour TYPE 1, make this voxel type 0 if (ThisVoxel.type == 0 && typeFreq [1] > 0) { ThisVoxel.type = 1; }
/*if (ThisVoxel.type == 2 && typeFreq[1] != 0) { cellVal = 100; }*/ //else if (ThisVoxel.type == 1 && typeFreq)
//TYPE 1 looses to TYPE 2 if (ThisVoxel.type == 1 && typeFreq [2] > 0) { ThisVoxel.type = 2; }
//type 2 voxels sink111 /*if (ThisVoxel.type == 2 && typeFreq [3] > 0) { cellVal = cellVal deathRate valueSum[3]; }
//TYPE 2 looses to TYPE 0 if (ThisVoxel.type == 2 && typeFreq [0] > 0) { ThisVoxel.type = 0; }
//if this voxel has more than 0 type two neighbours, this voxel sinks else if (typeFreq[2] != 0) { cellVal = valueSum [ThisVoxel.type]/typeFreq[ThisVoxel.type] deathRate; }*/
}
{
//add your conditions HERE /*
}
*/ //otherwise do this FAILSAFE, DON'T TOUCH else { cellVal = averageVal + Random.Range ( + 1); } }
if (typeFreq [ThisVoxel.type] != 0) { //cellVal = average of the same types of neighbours
deathRate / 2, deathRate
int chance = Random.Range (0, 10); if (chance > 8) { cellVal = valueSum [ThisVoxel.type] / typeFreq [ThisVoxel.type] + deathRate; }
//decay by deathrate else { if (ThisVoxel.type == 3) { cellVal = (int)(cellVal deathRate * 0.5f); }
if (chance <= 8) { cellVal = valueSum [ThisVoxel.type] / typeFreq [ThisVoxel.type] deathRate * 4; }
else { ...ty project folder CA\Assets\Scripts\CustomExtensions.cs cellVal = averageVal deathRate * 2; } }
6
...ty project folder CA\Assets\Scripts\CustomExtensions.cs } //CellVal does not equal or go below 0 (becomes bottom feeder) if (cellVal <= deathRate) { cellVal = deathRate; } if (cellVal > maxValue) { cellVal = maxValue; }
return cellVal; //NextCAvalues[x, z] = cellVal;
public static HashSet<int> ToHashSet<T>(this IEnumerable<int> source) { if (source == null) { throw new System.ArgumentNullException("source"); } return new HashSet<int>(source); } public static int findMaxIndicie(this int[] intArray) { int maxAmount = 0; int highestIndicie = 0; for (int i = 0; i < intArray.Length; i++) { if (intArray [i] > maxAmount) { maxAmount = intArray [i]; highestIndicie = i; } } return highestIndicie; } public static int findMinIndicie(this int[] intArray) { int minAmount = 1; int lowestIndicie = 0; for (int i = 0; i < intArray.Length; i++) { if (intArray [i] != 0 && intArray [i] <= minAmount) { minAmount = intArray [i]; lowestIndicie = i; } } return lowestIndicie;
public static int findMaxValue(this int[] intArray) { int maxAmount = 0; for (int i = 0; i < intArray.Length; i++) { if (intArray [i] >= maxAmount) { maxAmount = intArray [i];
ThisVoxel.sickness = 0;
int cellVal = ThisVoxel.Value; // Get an average of all the values
//if a cell has less than three neighbours, none of the same type, do this..
}
if (ThisVoxel.type == 1 && neighbourSickness > 0 && neighbourSickness < 5)
//EXAMPLE: TYPE ZERO SINKS public static int TypeZeroSinks (this trimVoxel ThisVoxel,int[] typeFreq,int[] valueSum, int deathRate, int maxValue) {
else if (your condition here) { your consequence here }
}
S
zval));
return ThisVoxel;
//END 23MAY SAMPLE CODE FOR RULES HERE!!! TYPE 3 ALWAYS LIVES//
// /////////////////////////////////////////////////////////////////// // REFCA01 SEEDING LANDSCAPE RANDOMLY // ///////////////////////////////////////////////////////////////////
public static void populateCARandom(this trimVoxel[,] CAgrid) { for (int i = 0; i < CAgrid.GetLength(0); i++) { for (int j = 0; j < CAgrid.GetLength(1); j++) { CAgrid[i, j] = new trimVoxel(Random.Range(0, 256), 0, i, j); } } }
indicating how many type 0 voxels neighbours are present (2 type 0 //PAPER SCISSCORS ROCK TEST neighbours ),
DeadCellRules.Clear (); AliveCellRules.Clear ();
/////// ALWAYS KEEP THIS AT END hasModifiedRules = true; //////
}
/// //////////////////////////////////////
The ME voxel would have the following neighbours: 2 type zero neighbours (A type 2 neighbour to the middleleft, a type 2 neihbour to the topright) 3 type one neighbours 3 type two neighbours
//////////How many neighbours a cell must have to die AliveCellRules.Add (1); AliveCellRules.Add (4); //AliveCellRules.Add (5); //AliveCellRules.Add (6); //AliveCellRules.Add (7); //AliveCellRules.Add (8);
testMultipliers [i] = setTestMultipliers;
*/
}
/////// ALWAYS KEEP THIS AT END } void createSickness() hasModifiedRules = true; //if voxel is water and not in flood zone { else if (CA[x,z].type == 0 && elevationHeightHere [indicie] > ////// floodLevel && CA[x,z].Value > 0) if (playerX >= 0 && playerX < CAgridX && playerZ >= 0 && playerZ < CAgridZ)
/*
//Set up special rules and price multipliers here for (int tileNumber = 0; tileNumber < priceMultiAtI.Length; tileNumber++) { //special rules are the values currently being displayed on tiles specialRulesHere[tileNumber] = xyzToI.getAttributeStatic (1, tileNumber, me);
//priceMultiAtXZ [x, z] = gameObject.GetComponent<tileManager>
CA[x,z].sickness = 0;
hasModifiedRules = true;
}
/*if (ThisVoxel.type == 1 && typeFreq [4] != 0) { ThisVoxel.NextValue = ThisVoxel.NextValue + 40;
17
//////////How many neighbours a cell must have to die ().getAttribute (1, x, z); //indicie = gameObject.GetComponent<tileManager> AliveCellRules.Add (1); DeadCellRules.Clear (); ().convertXYZtoI (x, z); AliveCellRules.Clear (); //priceMultiAtI [indicie] = AliveCellRules.Add (4); gameObject.GetComponent<tileManager> /////////////////////insert rules below////////////// ().getAttributeFromIndicie (1, indicie); //AliveCellRules.Add (5); //Set up price multipliers //How many neighbours a cell must have to become alive //dollarsPerType [CA [x, z].type] = dollarsPerType [CA [x, priceMultiAtI = new float[landscapeManager.gridXDim * //AliveCellRules.Add (6); z].type] + //(float)CA[x,z].Value; landscapeManager.gridZDim]; CA[x,z].NextValue = 100; elevationHeightHere = new float[landscapeManager.gridXDim * //AliveCellRules.Add (7); } landscapeManager.gridZDim]; //How many neighbours a cell must have to die } nativeVegHere = new float[landscapeManager.gridXDim * //AliveCellRules.Add (8); //AliveCellRules.Add (1); } landscapeManager.gridZDim];
me = gameObject;
E
}
//DO THESE THINGS ONLY ONCE if (calculatedMultipliers[indicie] == false) { elevationHeightHere [indicie] = xyzToI.getAttributeStatic(2, indicie, me); nativeVegHere [indicie] = xyzToI.getAttributeStatic(4, indicie, me);
public static int CAgridX; public static int CAgridZ;
M
//populate typePop with sick cells typePop [typePop.Length 1]++;
indicie = CustomExtensions.convertXZtoI (x, z); //specialRulesHere [indicie] = gameObject.GetComponent<xyzToI> ().getAttributePlus ((specialRulesAtt 1), indicie);
public float attAtPlayer;
X
CA[x, z].sickness++;
//the cell being checked
public static int Sandbox; public int setSandbox;
1 0 2 2 ME 1 0 1 2
}*/
//make a sick cell sicker if (CA[x, z].sickness > 0) {
10
int xPos = (int)(location.x + incriments[i].x); int zPos = (int)(location.z + incriments[i].y);
if (neighbourSickness > 0) if (xPos >= 0 && xPos < CAgrid.GetLength(0) && zPos >= 0 && zPos < CAgrid.GetLength(1)) { { Ie. 'ME' below is a voxel (ThisVoxel, the surrounding numbers indicating an CAgrid[xPos, zPos] = 255; adjacent voxel neighbour of that type): } ThisVoxel.sickness = ThisVoxel.sickness + 1;
// /////////////////////////////////////////////////////////////////// /*if (ThisVoxel.type == 1 && typeFreq[2] != 0) /*if (ThisVoxel.type == 1 && typeFreq[4] > 0) // REFCE03 Change the Y position { { int xval = 0, zval = 0; ThisVoxel.NextValue = ThisVoxel.NextValue + 40; // /////////////////////////////////////////////////////////////////// ThisVoxel.type = 2; // Loop for each attribute, parse (or convert) them from string to }*/ int of the x/z values }*/ if (!int.TryParse(fields[0], out xval)) /*else if (ThisVoxel.type == 1 && typeFreq[2] > 0)
// /////////////////////////////////////////////////////////////////// // REFCA01 SEEDING LANDSCAPE RANDOMLY // /////////////////////////////////////////////////////////////////// }
{
*** typeFreq[i] > is an array (a list) of the number of neighbouring types the Voxel has Remember, the type of voxel is represented by a number. Ie a voxel (and its neighbours) can be a Type 0 voxel, Type 1 voxel, Type 2 voxel, etc
{ ThisVoxel.type = 2; }
//new cell values replace old cell values for (int x = 0; x < CAgridX; x++) { for (int z = 0; z < CAgridZ; z++) { if (CA[x,z].isPetrified == false) { //make cells sick if (CA[x, z].Value > 0) { //kill really sick cells if (CA[x, z].sickness > 10) { if (canPetrify == true) { CA[x,z].isPetrified = true; }
int playerI = CustomExtensions.convertXZtoI (playerIndiceX, playerIndiceZ); playerVegLevel = xyzToI.getAttributeStatic(4, playerI, me);
public static void addshape(this float[,] CAgrid, Vector3 location, Vector2[] ...ty project folder CA\Assets\Scripts\CustomExtensions.cs 3 incriments) ___________________ EXPLAINATION OF typeFreq ARRAY { ________________________________________________ ThisVoxel.NextValue = cellVal; //NextCAvalues[x, z] = cellVal; for (int i = 0; i < incriments.Length; i++)
return ThisVoxel; if (cellVal <= deathRate) { //PAPER SCISSCORS ROCK TEST } cellVal = deathRate; // TYPE 1 LOOSES TO TYPE 2 // If this Voxel is TYPE 1 && it has a neighbour TYPE 2, make this voxel } type 2 } if (ThisVoxel.type == 1 && typeFreq[2] > 0)
// update the new CA values ///////////////////////////////////////////
playerIndiceX = playerX; playerIndiceZ = playerZ; playerPosPrev = playerPos;
[Header("Total $$$ each voxel type owns")] //CA DOLLAR CALCS// public int character; public float[] dollarsPerType; //Array that stores the total $$ each voxel type owns public static float[,] priceMultiAtXZ; //Array that stores the landscape value multiplier in XZ public static float[] priceMultiAtI; //Array that stores the landscape value multiplier in I //HOSTILE / FERTILE ENVIRONMENTS float[] elevationHeightHere; //array of elevationHeightsforFloodZone; float[] nativeVegHere; //array of wilderness;
A
}
elapseTime = 0;
*** ThisVoxel.type > is the voxel's type *** ThisVoxel.position > is the voxels XYZ position *** ThisVoxel.position.y > is the height of the voxel *** ThisVoxel.sickness > is how sick the voxel is. Sickness > 0 is sick. Sickness > 10 and the voxel dies
the 1st indicie how many type 1 neighbours (3), the 2nd how many type 2 neighbours (3).
...AIR Unity project folder CA\Assets\Scripts\CaManager.cs CA[c,z].type = 2; } }
//23MAY END COPY ME//
public float[] old; public float [] runaway; public float[] developor; public float [] dog; public float [] environmentalist;
U
//if the voxel is veg and has a neighbour pollution
if (CA[x,z].type == 1 && typeFreq[2]> 0) { //CA[c,z].type = 2; int chance = Random.Range(0,10); { if (chance > 2) {
[CSVPattern2]], colourType2);
} }
("Characters")]
[Header
/*
...AIR Unity project folder CA\Assets\Scripts\CaManager.cs
[Header ("Special Rule Zones")] public float floodLevel = 0.5f; public float vegLevel = 0.3f; public float playerVegLevel;
} */
} */
//multiple value attributes /*if (CSVPattern1 != 0) for (int attributeNumber = 0; attributeNumber < { CA.addIndicieShape(pos, CaManager.CAshapes[shapes specialRulesHere.Length; attributeNumber++) [CSVPattern1]], colourType1); { } characterCompiles = new float [5] {1,1,1,1,1}; //priceMultiAtI [tileNumber] = gameObject.GetComponent<xyzToI> if (CSVPattern2 != 0) { ().getAttributePlus ((dollarMultiplierAtt + 1), attributeNumber); CA.addIndicieShape(pos, CaManager.CAshapes[shapes }
...AIR Unity project folder CA\Assets\Scripts\CaManager.cs
C
hasModifiedRules = true; (0, shapes.Length)]], Random.Range (0, nTypes));
//23MAY COPY ME //
public static void populateCAZero(this float[,] CAgrid) { for (int i = 0; i < CAgrid.GetLength(0); i++) { for (int j = 0; j < CAgrid.GetLength(1); j++) { CAgrid[i, j] = 0; } } }
/* *** indicate variables you can play with!
////////////How many neighbours a cell must have to
7
public static void populateCARandom(this float[,] CAgrid) { for (int i = 0; i < CAgrid.GetLength(0); i++) { for (int j = 0; j < CAgrid.GetLength(1); j++) { CAgrid[i, j] = Random.Range(0, 256); } } }
public static trimVoxel CAinheritance(this trimVoxel ThisVoxel,int[] typeFreq,int[] valueSum, int neighbourSickness, int deathRate, int maxValue) {
become alive else DeadCellRules.Add (0); if (CSVPattern2 != 0) DeadCellRules.Add (1); { { DeadCellRules.Add (2); CA.addIndicieShape(pos, CaManager.CAshapes[shapes public static trimVoxel[,] CA; DeadCellRules.Add (3); [CSVPattern2]], colourType2); ...AIR Unity project folder CA\Assets\Scripts\CaManager.cs 6 CA.addIndicieShape(pos, CaManager.CAshapes[shapes[2]], 2); DeadCellRules.Add (4); } DeadCellRules.Add (5); ("Main CA Parameters")] [Header DeadCellRules.Add (6); if (CSVPattern3 != 0) //CA grid dimensions //single attribute }*/ DeadCellRules.Add (7);
{
...ty project folder CA\Assets\Scripts\CustomExtensions.cs } } return maxAmount; }
/////////////////////////////////////////////////////////////////// // REFCE01 Change the inheritance types // ///////////////////////////////////////////////////////////////////
HashSet<int> mDeadCellRules; HashSet<int> mAliveCellRules;
public int setCAgridX = 200; public int setCAgridZ = 200; //The length of time between CA calculation turns public float refreshrate = 0f; float elapseTime = 0;
1
using System.Collections.Generic;
DeadCellRules.Clear (); AliveCellRules.Clear (); CA[x,z].type = 2; CA[x,z].sickness = 0;
/*if (CSVPattern1 != 0) } {
HashSet<int> DeadCellRules; HashSet<int> AliveCellRules;
...ty project folder CA\Assets\Scripts\CustomExtensions.cs using UnityEngine;
return cellVal; } */ }
12
GLOBAL RULES Exploring how modifying the global rules for dead cells coming alive and alive cells dying affect voxel interaction at a global/large scale. Refer to SCRIPTS.... for what parts were changed in order to achieve different interactions.
TORUS A - 1 ORIGIN
AS VOXELS GROW OUTWARDS THE MORE DENSE THE GROWTH
INSIDE OF INTIAL GROWTH STAYS DEAD -DOESN’T GROW INTERNALLY
SPORATIC GROWTHNO STRUCTURE
TORUS B - 1 ORIGIN
DENSE BUBBLES FORMED FROM MULTI-LAYERED VOXELS
THIS TORUS GROWTH GREW RESEMBLING A BACTERIAL GROWTH
VEIN LIKE DEAD ENVIRONMENT SHOWING THROUGH
STARTING POINT
TORUS C - multiple ORIGIN RANDOM SEED -AT 200 BEGINS AT BASE SHAPE AT DIFFERENT POINTS AND GROWS FROM ALL
INSTEAD OF ONE STARTING GROWTH, THERE ARE MULTIPLE
CALL OUT
GLOBAL FLOOD GROWTH DARKENED AREAS AND SPARSE VOXELS SURROUNDING DENSE = MUTLI-DIMENSIONAL VOXELS (REACHING PLAYERS EASIER)
RIVER BASE (ORIGINAL HEIGHT) EVERYTHING OUTSIDE OF THIS DEAD ENVIRONMENT IS FLOOD
DOESN’T GROW EVENLY - MEANING PLAYERS CAN BE SUPRISED BY FLOOD
LOCAL RULES Exploring how modifying the local rules of inheritance and resilience affect voxel interaction at a local scale. Refer to SCRIPTS.... for what parts were changed in order to achieve different interactions.
Pollution eats Vegetation voxels Pollution Voxel
Vegetation Voxel
THE POLLUTION VOXEL CONSUMES THE VEGETATION VOXEL WHLIE BOTH VOXEL TYPES PERFORM REGULAR CA RULES.
pollution weakens vegetation voxels
TORUS A - 1 ORIGIN
Pollution Voxel
COMPARED TO THE PREVIOUS CONDITION, VEGETATION VOXELS SURVIVE LONG ENOUGH TO REPOPULATE WITH REGULAR CA RULES EVEN THOUGH THEY ARE WEAKENED BY POLLUTION VOXELS.
Vegetation Voxel
sunlight strengthens vegetation voxels
Sunlight Voxel
VEG VOXELS GROWH HEALTHILY AND REPOPULATE EASILY WHEN IT CONTACTS THE SUNLIGHT VOXELS.
Vegetation Voxel
section aa
section bb
overall system Using the random seed rules to populate the full landscape with a fertile environment rules and several local rules implemented.
B
A
A
B