public void ShouldParseTheParameterToCorrectTypeEvenIfInputIsNotOfSameType() { GeneratorParameterCollection coll = new GeneratorParameterCollection(); var gp1 = new GeneratorParameter("Date", DateTime.Now.ToString(), GeneratorParameterParser.DateTimeParser); var gp2 = new GeneratorParameter("Decimal", 1000, GeneratorParameterParser.DecimalParser); coll.Add(gp1); coll.Add(gp2); Decimal dec = coll.GetValueOf <Decimal>("Decimal"); DateTime date = coll.GetValueOf <DateTime>("Date"); }
public void ShouldNotChangeValueWhenTryingToSetValueOfWrongDataType() { DateTime d = DateTime.Now; GeneratorParameter p = new GeneratorParameter("date", d, dateTimeParser); Assert.That(d, Is.EqualTo(p.Value)); // Try to Set value to wrong datatype p.Value = 10; Assert.That(d, Is.EqualTo(p.Value)); }
public void ShouldGetParameterFromCollection() { GeneratorParameterCollection coll = new GeneratorParameterCollection(); var gp1 = new GeneratorParameter("Date", DateTime.Now, GeneratorParameterParser.DateTimeParser); var gp2 = new GeneratorParameter("Decimal", new Decimal(10), GeneratorParameterParser.DecimalParser); coll.Add(gp1); coll.Add(gp2); Decimal got = coll.GetValueOf <Decimal>("Decimal"); DateTime got2 = coll.GetValueOf <DateTime>("Date"); }
public void ShouldBeEqualIfSameName() { GeneratorParameter withOtherValue = new GeneratorParameter("peter", 10, GeneratorParameterParser.IntegerParser); GeneratorParameter withOtherName = new GeneratorParameter("Generator", 1, GeneratorParameterParser.IntegerParser); GeneratorParameter withOtherParser = new GeneratorParameter("peter", 1, GeneratorParameterParser.DecimalParser); GeneratorParameter withAllPropertiesChanged = new GeneratorParameter("generator", "streng", GeneratorParameterParser.StringParser); Assert.That(p1, Is.Not.EqualTo(nullGenParam)); Assert.That(p1, Is.EqualTo(withOtherValue)); Assert.That(p1, Is.Not.EqualTo(withOtherName)); Assert.That(p1, Is.EqualTo(withOtherParser)); Assert.That(p1, Is.Not.EqualTo(withAllPropertiesChanged)); }
public override void Initialize() { Debug.WriteLine("Init"); XmlDocument tilesetXml = new XmlDocument(); tilesetXml.Load("Content/tilesDef.xml"); tileset = new Tileset(tilesetXml.SelectSingleNode("tiles"), Content); Sprite bikeNorth = new Sprite(Content.Load <Texture2D>("tiles"), new Rectangle(64, 384, 64, 48)); Sprite bikeWest = new Sprite(Content.Load <Texture2D>("tiles"), new Rectangle(0, 384, 64, 48)); Sprite bikeEast = new Sprite(Content.Load <Texture2D>("tiles"), new Rectangle(128, 384, 64, 48)); Sprite bikeSouth = new Sprite(Content.Load <Texture2D>("tiles"), new Rectangle(128 + 64, 384, 64, 48)); bikeSprites = new Sprite[] { bikeNorth, bikeEast, bikeSouth, bikeWest }; var mapParameter = new GeneratorParameter() { size = new Point(128, 128), baseHeight = 1, minHeight = 8, maxHeight = 16, waterMinDiff = 4, forestSize = 0.3f, resourceSize = 0.5f, citiesNumber = 0.4f, citySize = 7.5f, citySizeRandomOffset = 2.5f, hasCities = true, hasWater = true, hasCityConnections = true, hasRivers = false, tileset = tileset, randomSeed = 869719833//615228352//1571703035 //123456789 //189370585 //1621216522 //123456789 //1571703035 }; map = new Map(mapParameter, camera, Content, GraphicsDevice, Config.Resolution); renderer = new IsoRenderer(map, tileset, Content.Load <SpriteFont>("Fonts/Xolonium_18")); simulator = new Simulator(0, map, CreateAgent, RemoveAgentFromScene); CreateUI(); CameraInput.Initialize(); }
public override void Initialize() { XmlDocument tilesetXml = new XmlDocument(); tilesetXml.Load("Content/tilesDef.xml"); tileset = new Tileset(tilesetXml.SelectSingleNode("tiles"), Content); mapParameter = new GeneratorParameter() { size = new Point(128, 128), baseHeight = 1, minHeight = 8, maxHeight = 16, waterMinDiff = 4, forestSize = 0.3f, resourceSize = 0.5f, citiesNumber = 0.4f, citySize = 7.5f, citySizeRandomOffset = 2.5f, hasCities = true, hasWater = true, hasCityConnections = true, hasRivers = false, tileset = tileset, randomSeed = 869719833//615228352//1571703035 //123456789 //189370585 //1621216522 //123456789 //1571703035 }; cities = new List <City>(64); map = new Map(mapParameter, camera, Content, GraphicsDevice, Config.Resolution); foreach (World.Generation.Room r in map.cityRooms) { cities.Add(new City(map.tiles, r)); } renderer = new IsoRenderer(map, tileset, cityFont); CreateUI(); SetCameraBounds(); CameraInput.Initialize(); }
public void ShouldGetExceptionWhenTryingToGetWrongDataTypeFromParameterCollection() { GeneratorParameterCollection coll = new GeneratorParameterCollection(); var gp1 = new GeneratorParameter("Date", DateTime.Now, GeneratorParameterParser.DateTimeParser); var gp2 = new GeneratorParameter("Decimal", "peter", GeneratorParameterParser.StringParser); coll.Add(gp1); coll.Add(gp2); bool gotException = false; try { Decimal got = coll.GetValueOf <Decimal>("Decimal"); } catch (Exception) { gotException = true; } Assert.That(gotException, Is.True); }
public void Apply(GeneratorParameter param, Tile[,] tiles) { if (param.citiesNumber == 0f) { return; } this.param = param; this.tiles = tiles; int numCities = GetNumberOfCities(); //TODO: Propably adjust non placeable. int notPlaceableCities = 0; List <CityPlacementInfo> cityPlacementInfo = GetCityPlacementInfo(numCities, ref notPlaceableCities); foreach (CityPlacementInfo info in cityPlacementInfo) { Room room = GrowCity(info); if (room != null && room.Tiles.Count > 5) { cities.Add(room); } } MergeOverlapingCities(); int totalSize = 0; foreach (Room r in cities) { totalSize += r.Tiles.Count; } float avgSize = (float)totalSize / cities.Count; foreach (Room cityRoom in cities) { MakeCityDistricts(cityRoom, avgSize); } Debug.WriteLine($"Number of cities: {numCities}. Not placeable were: {notPlaceableCities}. Avg. city size: {avgSize}"); }
private void SmoothHeight(GeneratorParameter param, Tile[,] tiles) { for (int x = 0; x < param.size.X; x++) { for (int y = 0; y < param.size.Y; y++) { int h = tiles[x, y].GetMaxHeight(); int smallerNeighbours = 0; int biggerNeighbours = 0; foreach (Point p in IterateNeighboursEightDir(x, y)) { int nh = tiles[p.X, p.Y].GetMaxHeight(); if (nh < h) { smallerNeighbours++; } else if (nh > h) { biggerNeighbours++; } } if (smallerNeighbours > 5) { h -= 1; tiles[x, y].height = new int[] { h, h, h, h }; } else if (biggerNeighbours > 5) { h += 1; tiles[x, y].height = new int[] { h, h, h, h }; } } } }
void OnGUI() { //Still developing the mouseover interface for ERAs, I believe this is necessary to force an update when the mouse position changes. if (!wantsMouseMove) { wantsMouseMove = true; } if (eranalyser == null) { eranalyser = new ERAnalyser(); } //This probably needs to be called on wake SetupStyles(); GUILayout.Space(15); /* * HEADER SECTION * * This includes the 'Click here to load a new generator!' and 'Load metrics!' section with Monobehaviour selector. * In future this area may include the tabbing environment for switching between user modes. */ GUILayout.BeginHorizontal(); GUILayout.BeginVertical(); GUILayout.BeginHorizontal(GUILayout.Width(300)); GUILayout.FlexibleSpace(); GUILayout.Label("Metrics:", rightAlignText, GUILayout.Width(75)); analyser = (MonoBehaviour)EditorGUILayout.ObjectField("", analyser, typeof(MonoBehaviour), true); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(GUILayout.Width(300)); GUILayout.FlexibleSpace(); DrawOnGUISprite(scientistSprite); if (analyser == null) { GUILayout.Label("Please select a MonoBehaviour with metrics to load"); } else if (GUILayout.Button("Load Metrics", buttonStyle, GUILayout.Width(150))) { SetupMetrics(analyser); } DrawOnGUISprite(scientistSprite); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.EndVertical(); GUILayout.BeginVertical(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); GUILayout.Label("Generator:", rightAlignText, GUILayout.Width(75)); generator = (MonoBehaviour)EditorGUILayout.ObjectField("", generator, typeof(MonoBehaviour), true, GUILayout.Width(300)); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); DrawOnGUISprite(botSprite); if (generator == null) { GUILayout.Label("Please select a generator to instrument."); } else { if (GUILayout.Button("Setup Generator", buttonStyle, GUILayout.Width(150))) { SetupGenerator(); } } DrawOnGUISprite(botSprite); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.EndVertical(); GUILayout.BeginHorizontal(GUILayout.Width(300)); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.EndHorizontal(); GUILayout.Space(10); /* * MAIN EDITOR SPACE * * Currently this area is split into three regions: the left-hand bar contains metrics and auto-tuning, * the central pane contains the main visual content (either the generator output or the ERA analysis), * and the right-hand bar contains discovered parameters + settings menu, and the ERA interface. */ GUILayout.BeginHorizontal(); GUILayout.BeginVertical(GUILayout.Width(10)); GUILayout.Space(10); GUILayout.EndVertical(); /* * METRICS * * For each discovered metric, display its current value here and its name. This is updated whenever a new * piece of content is generated. */ GUILayout.BeginVertical(GUILayout.Width(300)); GUILayout.BeginVertical(); GUILayout.Label("Metrics", centerAlignText); GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1)); GUILayout.Space(20); if (metricList != null) { for (int i = 0; i < metricList.Count; i++) { GeneratorMetric m = metricList[i]; GUILayout.BeginHorizontal(); GUILayout.Label(m.name, leftAlignText); GUILayout.FlexibleSpace(); if (Double.IsNaN(m.currentValue)) { m.currentValue = 0; } GUILayout.Label(Math.Round((Decimal)(float)m.currentValue, 3, MidpointRounding.AwayFromZero) + "", rightAlignText); GUILayout.EndHorizontal(); GUILayout.Space(10); } } GUILayout.EndVertical(); GUILayout.FlexibleSpace(); /* * AUTO-TUNING * * Auto-tuning allows Danesh to automatically discover parameter configuraitons to achieve a certain average metric value. * The user can select which parameters to change by checking boxes, and then check metrics to target and input values for them. */ GUILayout.BeginVertical(); GUILayout.Label("Auto-Tuning", centerAlignText); GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1)); GUILayout.Space(20); GUILayout.Label("Targeted Parameters", centerAlignSubtext); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); GUILayout.Box("", GUILayout.Width(125), GUILayout.Height(1)); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(10); if (parameterList != null) { for (int i = 0; i < parameterList.Count; i++) { GeneratorParameter p = parameterList[i]; if (p.locked) { continue; } GUILayout.BeginHorizontal(); p.activated = GUILayout.Toggle(p.activated, "", GUILayout.Width(20)); GUILayout.Space(10); if (p.activated) { GUILayout.Label(p.name, leftAlignText, GUILayout.Width(200)); } else { GUILayout.Label(p.name, leftAlignTextGhost, GUILayout.Width(200)); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(5); } } GUILayout.Space(20); GUILayout.Label("Targeted Metrics", centerAlignSubtext); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); GUILayout.Box("", GUILayout.Width(125), GUILayout.Height(1)); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(10); if (metricList != null && metricTargets != null && metricInputs != null) { for (int i = 0; i < metricList.Count; i++) { GeneratorMetric m = metricList[i]; GUILayout.BeginHorizontal(); m.targeted = GUILayout.Toggle(m.targeted, "", GUILayout.Width(20)); GUILayout.Space(10); if (m.targeted) { GUILayout.Label(m.name, leftAlignText); } else { GUILayout.Label(m.name, leftAlignTextGhost); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (m.targeted) { GUILayout.Label("Target Value:", rightAlignText); } else { GUILayout.Label("Target Value:", rightAlignTextGhost); } GUILayout.Space(10); if (metricInputs != null) { metricInputs[i] = GUILayout.TextField(metricInputs[i], 25, GUILayout.Width(50)); } float res = 0f; if (float.TryParse(metricInputs[i], out res)) { metricTargets[i] = res; } GUILayout.EndHorizontal(); GUILayout.Space(10); } } GUILayout.Space(20); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Start Auto-Tuning", buttonStyle, GUILayout.Width(150))) { DaneshAutoTuner at = new DaneshAutoTuner(); //Construct the list of parameters List <GeneratorParameter> tuningParams = new List <GeneratorParameter>(); foreach (GeneratorParameter p in parameterList) { if (p.activated) { tuningParams.Add(p); } } List <GeneratorMetric> tuningMetrics = new List <GeneratorMetric>(); List <float> tuningTargets = new List <float>(); for (int i = 0; i < metricList.Count; i++) { GeneratorMetric m = metricList[i]; if (m.targeted) { tuningTargets.Add(metricTargets[i]); tuningMetrics.Add(m); } } at.Tune(this, tuningParams, tuningMetrics, tuningTargets); } if (!showATTooltip && GUILayout.Button("?", GUILayout.Width(25))) { showATTooltip = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); if (showATTooltip) { GUILayout.Space(10); GUILayout.BeginVertical(); GUILayout.Label("Tick the parameters you want to modify, and set the metric values you would like the generated content to have. When you click Auto-Tune, Danesh will try to find parameter values that make the generator produce content close to the target metrics.", tooltipStyle, GUILayout.Width(300)); GUILayout.Space(10); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Close", GUILayout.Width(100))) { showATTooltip = false; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.EndVertical(); GUILayout.Space(10); } else { GUILayout.Space(20); } GUILayout.EndVertical(); GUILayout.EndVertical(); /* * MAIN PANE * * We display a lot of information here. At the moment, what we show is based on the MainTab enum value. I'm going to change the way this is rendered eventually * and break some of it out into other files or parts of this file. I get the feeling that Unity UIs are supposed to be a bit clunky but they shouldn't be this * cluttered, I don't think. */ GUILayout.BeginVertical(); //Display the output of the generator, using the textureToBeDisplayed variable. if (MainTab == Tabs.OUTPUT) { GUILayout.Label("Generator Output", centerAlignText); GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1)); GUILayout.Space(20); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (hasDisplay) { GUILayout.Label(textureToBeDisplayed); } else if (noGeneratorFound) { GUILayout.Label("Danesh couldn't find a generation method. Did you use the [MapGenerator] attribute?", errorTextStyle); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (generator != null && !noGeneratorFound && GUILayout.Button("Generate Content", buttonStyle, GUILayout.Width(150))) { GenerateMap(); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } //Display the output of the ERA/RERA here, with selectors to change the axes. //TODO: Draw axes on/near the image to show the metric values for X/Y else if (MainTab == Tabs.ERA) { GUILayout.Label("Expressive Range Histogram", centerAlignText); GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1)); GUILayout.Space(20); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (hasDisplay) { GUILayout.Label(textureToBeDisplayed); if (Event.current.type == EventType.Repaint) { eraRect = GUILayoutUtility.GetLastRect(); } } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(30); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); GUILayout.Label("Metric 1 (X-Axis):"); int prior_x = x_axis_era; x_axis_era = EditorGUILayout.Popup(x_axis_era, axis_options); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); GUILayout.Label("Metric 2 (Y-Axis):"); int prior_y = y_axis_era; y_axis_era = EditorGUILayout.Popup(y_axis_era, axis_options); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(30); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Back To Generator", buttonStyle)) { SwitchToOutputMode(); GenerateMap(); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); if (prior_x != x_axis_era || prior_y != y_axis_era) { //Change DisplayTexture(eranalyser.GenerateGraphForAxes(x_axis_era, y_axis_era)); } } GUILayout.EndVertical(); /* * RIGHT COLUMN * * Parameters and the ERA/RERA setup interface. */ GUILayout.BeginVertical(GUILayout.Width(300)); GUILayout.Label("Generator Parameters", centerAlignText); GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1)); GUILayout.Space(20); /* * PARAMETERS * * Parameters are displayed with a slider that lets you change their value. The textbox shows their current value * but it's slightly misleading because it can't be edited at the moment. I might change that but there's feedback * issues in updating all the UI stuff at once. It's a nice feature but not a priority. * * If the Parameter is 'locked' this means it was discovered by Danesh but does not have all the information it needs * yet. It prompts the user to add in information (min/max values) and then lock or discard the parameter. */ if (parameterList != null) { for (int i = 0; i < parameterList.Count; i++) { GeneratorParameter p = parameterList[i]; GUILayout.BeginHorizontal(); if (!p.locked) { GUILayout.Label(p.name, rightAlignText); } else if (p.locked) { GUILayout.Label("New Parameter: " + p.name, leftAlignText); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (!p.locked) { if (p.type == "float") { object newVal = (object)GUILayout.HorizontalSlider((float)p.currentValue, (float)p.minValue, (float)p.maxValue); if (newVal != p.currentValue) { //Change in the generator p.field.SetValue(generator, newVal); } p.currentValue = newVal; GUILayout.TextField(Math.Round((Decimal)(float)p.currentValue, 3, MidpointRounding.AwayFromZero) + "", 20, GUILayout.Width(50)); } if (p.type == "int") { object newVal = (object)(int)GUILayout.HorizontalSlider(Convert.ToInt32(p.currentValue), Convert.ToInt32(p.minValue), Convert.ToInt32(p.maxValue)); if (newVal != p.currentValue) { //Change in the generator p.field.SetValue(generator, newVal); } p.currentValue = newVal; GUILayout.TextField(Convert.ToInt32(p.currentValue) + "", 20, GUILayout.Width(50)); } if (p.type == "bool") { GUILayout.FlexibleSpace(); bool cval = (bool)p.currentValue; cval = (bool)GUILayout.Toggle(cval, "", GUILayout.Width(20)); p.field.SetValue(generator, (object)cval); p.currentValue = (object)cval; } } else { if (p.type == "float") { GUILayout.Label("Min: ", rightAlignText); string mnv = GUILayout.TextField((Decimal)(float)(p.minValue) + "", 20, GUILayout.Width(40)); GUILayout.Label("Max: ", rightAlignText); string mxv = GUILayout.TextField((Decimal)(float)(p.maxValue) + "", 20, GUILayout.Width(40)); if (GUILayout.Button("\u2713", buttonStyle, GUILayout.Width(30))) { p.ParseSetMinValue(mnv); p.ParseSetMaxValue(mxv); p.locked = false; } if (GUILayout.Button("\u00D7", buttonStyle, GUILayout.Width(30))) { parameterList.RemoveAt(i); } GUILayout.TextField(Math.Round((Decimal)(float)p.currentValue, 3, MidpointRounding.AwayFromZero) + "", 20, GUILayout.Width(50)); } if (p.type == "int") { GUILayout.Label("Min: ", rightAlignText); string mnv = GUILayout.TextField(Convert.ToInt32(p.minValue) + "", 20, GUILayout.Width(40)); p.ParseSetMinValue(mnv); GUILayout.Label("Max: ", rightAlignText); string mxv = GUILayout.TextField(Convert.ToInt32(p.maxValue) + "", 20, GUILayout.Width(40)); p.ParseSetMaxValue(mxv); if (GUILayout.Button("\u2713", buttonStyle, GUILayout.Width(30))) { p.ParseSetMinValue(mnv); p.ParseSetMaxValue(mxv); p.locked = false; } if (GUILayout.Button("\u00D7", buttonStyle, GUILayout.Width(30))) { parameterList.RemoveAt(i); } GUILayout.TextField(Convert.ToInt32(p.currentValue) + "", 20, GUILayout.Width(50)); } if (p.type == "bool") { bool cval = (bool)p.currentValue; GUILayout.FlexibleSpace(); p.currentValue = (bool)GUILayout.Toggle(cval, "", GUILayout.Width(20)); if (GUILayout.Button("\u2713", buttonStyle, GUILayout.Width(30))) { p.locked = false; } if (GUILayout.Button("\u00D7", buttonStyle, GUILayout.Width(30))) { parameterList.RemoveAt(i); } } } //p.currentValue = (object) GUILayout.HorizontalSlider((bool) p.currentValue, 0.0F, 10.0F); // GUILayout.TextField(Math.Round((Decimal)(float)p.currentValue, 3, MidpointRounding.AwayFromZero)+"", 20, GUILayout.Width(50)); GUILayout.EndHorizontal(); GUILayout.Space(15); } } GUILayout.Space(10); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (parameterList != null && metricList != null && GUILayout.Button("Search For Parameters", buttonStyle, GUILayout.Width(200))) { ParameterFinder pf = new ParameterFinder(); List <GeneratorParameter> ps = pf.FindParameters(this, generator); foreach (GeneratorParameter p in ps) { parameterList.Add(p); } } if (!showParamSearchTooltip && GUILayout.Button("!", GUILayout.Width(25))) { showParamSearchTooltip = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); if (showParamSearchTooltip) { GUILayout.BeginVertical(); GUILayout.Label("Warning: This is an experimental feature and can change the internal workings of your generator. Back up before using this!", warningTTStyle, GUILayout.Width(300)); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Close", GUILayout.Width(100))) { showParamSearchTooltip = false; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.EndVertical(); } /* * RESET/SAVE/LOAD * * Avoiding side effects in the generator is a really important objective for Danesh. We can't avoid all side effects without * knowing what the generator code does, of course, but we do our best. One piece of functionality is the reset button which restores * parameter values to what they were on load. It does not undo other unseen changes. * * Saving and loading serialises to text files. This is basic and there are no safety catches, meaning it's possible to load a config * for a different generator. We can secure this later by connecting the monobehaviour id to it or something. */ GUILayout.Space(10); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (parameterList != null && !reallyReset && GUILayout.Button("Reset Generator", buttonStyle, GUILayout.Width(150))) { reallyReset = true; } else if (reallyReset) { GUILayout.Label("Really Reset?"); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Yes", buttonStyle, GUILayout.Width(50))) { foreach (GeneratorParameter p in parameterList) { p.field.SetValue(generator, p.originalValue); p.currentValue = p.originalValue; } reallyReset = false; } GUILayout.FlexibleSpace(); if (GUILayout.Button("No", buttonStyle, GUILayout.Width(50))) { reallyReset = false; } } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(10); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (parameterList != null && !beginSave && GUILayout.Button("Save Configuration", buttonStyle, GUILayout.Width(150))) { beginSave = true; beginLoad = false; saveName = GetRandomConfigName(); } else if (beginSave) { GUILayout.Label("Config. Name:"); saveName = GUILayout.TextField(saveName, 20, GUILayout.Width(200)); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Save", buttonStyle, GUILayout.Width(100))) { //Save the configuration if (File.Exists(saveName + ".param")) { Debug.Log("File '" + saveName + "'' already exists."); return; } var sr = File.CreateText(saveName + ".param"); foreach (GeneratorParameter p in parameterList) { sr.WriteLine(p.field.Name + ":" + p.type + ":" + p.currentValue); } sr.Close(); beginSave = false; } GUILayout.FlexibleSpace(); if (GUILayout.Button("Cancel", buttonStyle, GUILayout.Width(100))) { beginSave = false; } } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(10); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (parameterList != null && !beginLoad && GUILayout.Button("Load Configuration", buttonStyle, GUILayout.Width(150))) { beginSave = false; beginLoad = true; possibleLoadFiles = new List <string>(); DirectoryInfo root = new DirectoryInfo("."); FileInfo[] infos = root.GetFiles(); // Debug.Log(infos.Length+" files found"); foreach (FileInfo f in infos) { // Debug.Log(f.Name); if (f.Name.EndsWith(".param")) { possibleLoadFiles.Add(f.Name); } } selectedFile = 0; } else if (beginLoad) { if (possibleLoadFiles.Count == 0) { GUILayout.Label("Found no files to load!"); if (GUILayout.Button("Cancel", buttonStyle, GUILayout.Width(100))) { beginLoad = false; } } else { GUILayout.BeginVertical(); GUILayout.Label("Select a file", centerAlignSubtext); selectedFile = EditorGUILayout.Popup("", selectedFile, possibleLoadFiles.ToArray(), GUILayout.Width(250)); GUILayout.EndVertical(); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(10); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Load", buttonStyle, GUILayout.Width(100))) { //Load the configuration string line; StreamReader theReader = new StreamReader(possibleLoadFiles[selectedFile]); using (theReader){ do { line = theReader.ReadLine(); if (line != null) { //Parse the line string[] parts = line.Split(':'); foreach (GeneratorParameter p in parameterList) { if (p.field.Name == parts[0]) { p.ParseAndSetValue(parts[2]); } } } }while (line != null); } theReader.Close(); beginLoad = false; } GUILayout.FlexibleSpace(); if (GUILayout.Button("Cancel", buttonStyle, GUILayout.Width(100))) { beginLoad = false; } } } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.FlexibleSpace(); /* * EXPRESSIVE RANGE * * See the details on danesh.procjam.com for more information about what expressive range analysis consists of. * This runs the RERA and ERA functions and updates the main context pane with the histogram results when done. */ GUILayout.BeginVertical(); GUILayout.Label("Expressive Range", centerAlignText); GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1)); GUILayout.Space(20); GUILayout.Space(20); numberOfERARuns = EditorGUILayout.IntField("Sample Size (ERA):", numberOfERARuns); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Perform ER Analysis", buttonStyle, GUILayout.Width(150))) { eranalyser.StartERA(this, numberOfERARuns); Texture2D tex = eranalyser.GenerateGraphForAxes(x_axis_era, y_axis_era); DisplayTexture(tex); SwitchToERAMode(); } if (!showERATooltip && GUILayout.Button("?", GUILayout.Width(25))) { showERATooltip = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); if (showERATooltip) { GUILayout.BeginVertical(); GUILayout.Label("An ER Analysis lets you analyse the kind of content the generator is currently making. Danesh uses the generator to make " + numberOfERARuns + " pieces of content (set by 'Sample Size', above) and then plots the metric scores of each piece of content on a histogram.", tooltipStyle, GUILayout.Width(300)); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Close", GUILayout.Width(100))) { showERATooltip = false; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.EndVertical(); } GUILayout.Space(20); numberOfRERARuns = EditorGUILayout.IntField("Sample Size (RERA):", numberOfRERARuns); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Random ER Analysis", buttonStyle, GUILayout.Width(150))) { eranalyser.StartRERA(this, numberOfRERARuns); DisplayTexture(eranalyser.GenerateGraphForAxes(x_axis_era, y_axis_era)); SwitchToERAMode(); } if (!showRERATooltip && GUILayout.Button("?", GUILayout.Width(25))) { showRERATooltip = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); if (showRERATooltip) { GUILayout.BeginVertical(); GUILayout.Label("A Random ER Analysis is a special kind of ERA that lets you see what your generator can do with different parameters. It randomises the parameters of the generator each time it generates a piece of content, creating a histogram of all the different kinds of output possible.", tooltipStyle, GUILayout.Width(300)); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Close", GUILayout.Width(100))) { showERATooltip = false; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.EndVertical(); } GUILayout.Space(20); GUILayout.EndVertical(); GUILayout.EndVertical(); GUILayout.BeginVertical(GUILayout.Width(10)); GUILayout.Space(10); GUILayout.EndVertical(); GUILayout.EndHorizontal(); /* * This is the current code that detects mouse movement and position over the ERA and paints in a data point if it exists. * It needs rewriting, badly. */ if (MainTab == Tabs.ERA && Event.current.type == EventType.MouseMove) { float tex_mx = Event.current.mousePosition.x - eraRect.x; float tex_my = Event.current.mousePosition.y - eraRect.y + 5; /* * Hi, welcome to Open Source With Mike Cook, today I'll be revealing my secrets to writing the worst code in human history */ int x = (int)(100 * (tex_mx / eraRect.width)); if (x < 0) { x = 0; } if (x > 99) { x = 99; } int y = 100 - (int)(100 * (tex_my / eraRect.height)); if (y < 0) { y = 0; } if (y > 99) { y = 99; } Debug.Log("Cursor at " + tex_mx + ", " + tex_my + ". Within " + eraRect.width + ", " + eraRect.height + ". " + (tex_mx > 0 && tex_my > 0 && tex_mx < eraRect.width && tex_my < eraRect.height)); if (tex_mx > 0 && tex_my > 0 && tex_mx < eraRect.width && tex_my < eraRect.height) { Debug.Log("Cursor at " + tex_mx + ", " + tex_my + ". Within " + eraRect.width + ", " + eraRect.height + ". " + (tex_mx > 0 && tex_my > 0 && tex_mx < eraRect.width && tex_my < eraRect.height)); // int x = 100*(int)(tex_mx/eraRect.width); // int y = 100*(int)(tex_my/eraRect.height); Debug.Log("Looking for metrics " + x + ", " + y); Debug.Log(" - " + (eranalyser.eraSamples[x_axis_era][y_axis_era][x, y] != null)); Debug.Log(" - " + (eranalyser.eraSamples[x_axis_era][y_axis_era][y, x] != null)); //If the cursor target is null, be generous and find an adjacent one, because it's really hard to find the exact spot right now if (eranalyser.eraSamples[x_axis_era][y_axis_era][x, y] != null) { for (int i = -1; i < 2; i++) { for (int j = -1; j < 2; j++) { if ((i != 0 || j != 0) && x + i >= 0 && x + i < 100 && y + j >= 0 && y + j < 100 && eranalyser.eraSamples[x_axis_era][y_axis_era][x + i, y + j] != null) { x = x + i; y = y + j; break; } } } } if (eranalyser.eraSamples[x_axis_era][y_axis_era][x, y] != null && (x != last_era_x || y != last_era_y)) { Debug.Log("Generating a new preview window"); last_era_preview = VisualiseContent(eranalyser.eraSamples[x_axis_era][y_axis_era][x, y]); TextureScale.Point(last_era_preview, 100, 100); last_era_preview.Apply(); last_era_x = x; last_era_y = y; Repaint(); } if (eranalyser.eraSamples[x_axis_era][y_axis_era][x, y] == null && (x != last_era_x || y != last_era_y)) { last_era_preview = null; last_era_x = 0; last_era_y = 0; // GUI.DrawTexture(new Rect(tex_mx, tex_my, 100, 100), last_era_preview); } else { // last_era_preview = null; } } else { //Outside of the ERA, nullify last_era_preview = null; last_era_x = 0; last_era_y = 0; } } else if (MainTab == Tabs.ERA && Event.current.type == EventType.Repaint) { if (last_era_preview != null) { GUI.DrawTexture(new Rect(Event.current.mousePosition.x, Event.current.mousePosition.y, 100, 100), last_era_preview); // GUILayout.Label(last_era_preview); } } }
List <List <float> > SampleExpressiveRangeRandomly(int totalAttempts, Danesh gen) { float progressBar = 0f; EditorUtility.DisplayProgressBar("Computing Randomised Expressive Range Histogram", "Working...", progressBar); List <List <float> > res = new List <List <float> >(); List <GeneratorMetric> metrics = danesh.GetMetricsForActiveGenerator(); /* * Current: * eraSample[metric1][metric2] = object[,] of samples representing the histogram * Lot of data duplication here, not the most efficient way to do it */ eraSamples = new List <List <GeneratorSample[, ]> >(); for (int i = 0; i < metrics.Count; i++) { List <GeneratorSample[, ]> secondmetric = new List <GeneratorSample[, ]>(); for (int j = 0; j < metrics.Count; j++) { GeneratorSample[,] sampleH = new GeneratorSample[100, 100]; secondmetric.Add(sampleH); } eraSamples.Add(secondmetric); } List <GeneratorParameter> genParams = gen.GetParametersForActiveGenerator(); for (int att = 0; att < totalAttempts; att++) { //Hold this so we can find this version later object[] ps = new object[genParams.Count]; //Randomly parameterise the generator for (int i = 0; i < genParams.Count; i++) { GeneratorParameter p = genParams[i]; p.RandomiseValue(); ps[i] = p.GetValue(); } object map = danesh.GenerateContent(); List <float> nums = new List <float>(); for (int i = 0; i < metrics.Count; i++) { float score = (float)danesh.GetMetric(i, new object[] { map }); nums.Add(score); } //Update the samples list for (int i = 0; i < nums.Count; i++) { int index1 = (int)Mathf.Floor(nums[i] * 100f); if (index1 < 0) { index1 = 0; } if (index1 > 99) { index1 = 99; } for (int j = 0; j < nums.Count; j++) { int index2 = (int)Mathf.Floor(nums[j] * 100f); if (index2 < 0) { index2 = 0; } if (index2 > 99) { index2 = 99; } eraSamples[i][j][index1, index2] = new GeneratorSample(map, ps); } } res.Add(nums); EditorUtility.DisplayProgressBar("Computing Randomised Expressive Range Histogram", "Evaluating random expressive range... " + (100 * (float)att / (float)totalAttempts).ToString("F0") + " percent complete", (float)att / (float)totalAttempts); } EditorUtility.ClearProgressBar(); return(res); }
public void Apply(GeneratorParameter param, Tile[,] tiles) { if (!param.hasCityConnections) { return; } List <(Room, Room)> toConnect = GetRoomsToConnect(); foreach ((Room r, Room r2) in toConnect) { Debug.Assert(r != r2); if (r == null || r.Tiles.Count < 5) { continue; } Point start = r.MiddlePoint; //get a road tile near the middle point, if it is not a road if (tiles[start.X, start.Y].type != TileType.Road) { for (int x = start.X - 2; x <= start.X + 2; x++) { for (int y = start.Y - 2; y <= start.Y + 2; y++) { if (GeneratorHelper.IsInRange(x, y) && tiles[x, y].type == TileType.Road) { start = new Point(x, y); break; } } if (tiles[start.X, start.Y].type == TileType.Road) { break; } } } Debug.Assert(tiles[start.X, start.Y].type == TileType.Road); if (r2 != null && r2.Tiles.Count > 5) { Point target = r2.MiddlePoint; float targetDist = float.MaxValue; foreach (Point p in r2.Tiles) { if (tiles[p.X, p.Y].type == TileType.Road && tiles[p.X, p.Y].AllHeightsAreSame()) { float dist = (start - p).ToVector2().LengthSquared(); if (dist < targetDist) { target = p; targetDist = dist; } } } Debug.Assert(tiles[target.X, target.Y].type == TileType.Road); Func <Tile, bool> IsWalkable = (t) => t.IsRoadPlaceable(); Func <Tile, float> Cost = (t) => { if (t.type == TileType.Road) { return(1f); } else if (t.type == TileType.Water) { return(7f); } else if (t.type == TileType.Forest) { return(3f); } else if (t.type == TileType.House) { return(20f); } else { return(3f); } }; List <Point> path = GeneratorHelper.AStar(tiles, start, target, IsWalkable, Cost, GeneratorHelper.IterateNeighboursFourDirRoads); if (path != null && !(path.Count == 1 && path[0] == new Point(-1, -1))) { for (int k = 0; k < path.Count; k++) { Point p = path[k]; if (tiles[p.X, p.Y].type == TileType.Water || tiles[p.X, p.Y].type == TileType.Bridge) { tiles[p.X, p.Y].type = TileType.Bridge; } else { tiles[p.X, p.Y].type = TileType.Road; } } } else { Debug.WriteLine("Target not reached"); } } } }
private void CreateCitiesCellularAutomata(GeneratorParameter param, Tile[,] tiles) { var rooms = GeneratorHelper.GetCellularAutomataAsRooms(6, 53, true); HashSet <Room> toRemove = new HashSet <Room>(); int count = 7; foreach (Room room in rooms) { int size = room.Tiles.Count; if (size < 15) { toRemove.Add(room); continue; } int modX = 3; int modY = 3; if (random.NextDouble() < 0.5) { modX = random.Next(3, 6); } else { modY = random.Next(3, 6); } cities.Add(room); count += 7; double levelThree = GetPercentageOfCitizenLevel(DistrictType.Business); double levelOne = GetPercentageOfCitizenLevel(DistrictType.Suburb); foreach (Point p in room.Tiles) { Tile t = tiles[p.X, p.Y]; double prob = random.NextDouble(); DistrictType lvl = DistrictType.None; if (prob <= levelOne) { lvl = DistrictType.Suburb; } else if (prob <= levelOne + levelThree) { lvl = DistrictType.Business; } else { lvl = DistrictType.City; } if (t.type == TileType.Nothing && t.AllHeightsAreSame()) { if ((p.X % modX) == 0 || (p.Y % modY) == 0) { t.type = TileType.Road; } else { t.SetCitizenLevel(lvl); t.type = TileType.House; t.onTopIndex = param.tileset.GetRandomHouseIndex(t.citizenLevel); } } } room.Tiles.RemoveWhere((p) => tiles[p.X, p.Y].type == TileType.Water || tiles[p.X, p.Y].type == TileType.Forest); if (room.Tiles.Count < 15) { toRemove.Add(room); continue; } } cities.RemoveAll((r) => toRemove.Contains(r)); }
public void Apply(GeneratorParameter param, Tile[,] tiles) { CreateCitiesCellularAutomata(param, tiles); ConnectRoadArtifacts(param, tiles); ConnectRoadArtifacts(param, tiles); }
private void ConnectRoadArtifacts(GeneratorParameter param, Tile[,] tiles) { for (int x = 0; x < param.size.X; x++) { for (int y = 0; y < param.size.Y; y++) { Tile t = tiles[x, y]; if (t.type != TileType.Nothing || !t.IsRoadPlaceable()) { continue; } int roadNeighbours = 0; bool wasLastRoad = IsInRange(x - 1, y) && tiles[x - 1, y].type == TileType.Road; bool loops = false; if (IsInRange(x, y - 1) && tiles[x, y - 1].type == TileType.Road) { roadNeighbours++; if (wasLastRoad && IsInRange(x - 1, y - 1) && tiles[x - 1, y - 1].type == TileType.Road) { loops = true; } wasLastRoad = true; } else { wasLastRoad = false; } if (IsInRange(x + 1, y) && tiles[x + 1, y].type == TileType.Road) { roadNeighbours++; if (wasLastRoad && IsInRange(x + 1, y - 1) && tiles[x + 1, y - 1].type == TileType.Road) { loops = true; } wasLastRoad = true; } else { wasLastRoad = false; } if (IsInRange(x, y + 1) && tiles[x, y + 1].type == TileType.Road) { roadNeighbours++; if (wasLastRoad && IsInRange(x + 1, y + 1) && tiles[x + 1, y + 1].type == TileType.Road) { loops = true; } wasLastRoad = true; } else { wasLastRoad = false; } if (IsInRange(x - 1, y) && tiles[x - 1, y].type == TileType.Road) { roadNeighbours++; if (wasLastRoad && IsInRange(x - 1, y + 1) && tiles[x - 1, y + 1].type == TileType.Road) { loops = true; } wasLastRoad = true; } else { wasLastRoad = false; } if (roadNeighbours > 1 && !loops) { t.type = TileType.Road; t.onTopIndex = 0; //t.color = Color.Aquamarine; } } } }
/// <summary> /// Auto tiling the onTopIndex for the road tiles. Based on the four directional neighbour tiles calculate the roadDir index. /// </summary> private void CalculateCorrectRoadTile(GeneratorParameter param, Tile[,] tiles) { bool IsRoadOrBridge(int x, int y) { return(tiles[x, y].type == TileType.Road || tiles[x, y].type == TileType.Bridge); } //classic auto tile by giving the directional neighbour roads power of two values, result is a road dir index between 0 and 15. for (int x = 0; x < param.size.X; x++) { for (int y = 0; y < param.size.Y; y++) { Tile t = tiles[x, y]; if (t.type != TileType.Bridge && t.type != TileType.Road) { continue; } int roadDir = 0; if (IsInRange(x - 1, y) && IsRoadOrBridge(x - 1, y)) { roadDir += 8; } if (IsInRange(x + 1, y) && IsRoadOrBridge(x + 1, y)) { roadDir += 2; } if (IsInRange(x, y - 1) && IsRoadOrBridge(x, y - 1)) { roadDir += 1; } if (IsInRange(x, y + 1) && IsRoadOrBridge(x, y + 1)) { roadDir += 4; } int slope = t.GetSlopeIndex(); if (slope != 0) { if (!(slope == 6 && roadDir == 10 || slope == 12 && roadDir == 5 || slope == 9 && roadDir == 10 || slope == 3 && roadDir == 5)) { //on these slopes roads can not be placed. And it should not happen in the first place. t.type = TileType.Nothing; continue; } } t.onTopIndex = roadDir; } } //Special case: check if a curve tile could be a diagonal tile. for (int x = 0; x < param.size.X; x++) { for (int y = 0; y < param.size.Y; y++) { if (tiles[x, y].type != TileType.Road) { continue; } int roadDir = tiles[x, y].onTopIndex; if (roadDir == 9 || roadDir == 6 || roadDir == 3 || roadDir == 12) { int expectedConnectionRoadDir1 = connectedTo[roadDir]; int expectedConnectionRoadDir2 = changeTo[expectedConnectionRoadDir1]; int count = 0; foreach (Point p in GeneratorHelper.IterateNeighboursFourDir(x, y)) { if (tiles[p.X, p.Y].type == TileType.Road && (tiles[p.X, p.Y].onTopIndex == expectedConnectionRoadDir1 || tiles[p.X, p.Y].onTopIndex == expectedConnectionRoadDir2)) { count += 1; } } //if one or two tiles with expected road dir, change the road. if (count == 1 || count == 2) { tiles[x, y].onTopIndex = changeTo[roadDir]; } } } } }
public void Apply(GeneratorParameter param, Tile[,] tiles) { CalculateCorrectRoadTile(param, tiles); SetRoomsToTile(tiles); }
public List <GeneratorParameter> FindParameters(DaneshWindow d, MonoBehaviour b) { // Debug.Log("Searching for parameters... "+d.metricList.Count+" metrics found."); List <GeneratorParameter> res = new List <GeneratorParameter>(); //Collect a control sample set List <float> metricAverages = new List <float>(); List <float[]> stdev_samples = new List <float[]>(); List <float> stdev = new List <float>(); for (int i = 0; i < d.metricList.Count; i++) { metricAverages.Add(0); stdev_samples.Add(new float[numSamples]); } for (int s = 0; s < numSamples; s++) { object output = d.GenerateContent(); for (int i = 0; i < d.metricList.Count; i++) { GeneratorMetric m = d.metricList[i]; float sc = (float)m.method.Invoke(null, new object[] { output }); metricAverages[i] += sc; stdev_samples[i][s] = sc; } } //Calculate averages and standard deviation for (int i = 0; i < d.metricList.Count; i++) { metricAverages[i] = metricAverages[i] / numSamples; // Debug.Log("Average for metric "+i+": "+metricAverages[i]); float sqdif = 0; foreach (float s in stdev_samples[i]) { sqdif += Mathf.Pow(s - metricAverages[i], 2f); } sqdif = sqdif / numSamples; stdev.Add(Mathf.Sqrt(sqdif)); // Debug.Log("Standard deviation for metric "+i+": "+stdev[i]); } foreach (FieldInfo field in d.generator.GetType().GetFields()) { bool useParam = true; foreach (Attribute _attr in field.GetCustomAttributes(false)) { if (_attr is TunableAttribute) { //We already know this parameter is good so don't worry. useParam = false; } } if (!useParam) { continue; } //Remember the original value object original_value = field.GetValue(b); //Change the value to something List <object> sampleValues = GetSampleValues(field, b); // Debug.Log(sampleValues.Count+" sample values found"); //For each sample value, change the field to that value, run samples, get average foreach (object o in sampleValues) { field.SetValue(b, o); List <float> sampleData = new List <float>(); for (int i = 0; i < d.metricList.Count; i++) { sampleData.Add(0); } bool sampleFailed = false; for (int _ = 0; _ < numSamples; _++) { try{ object output = d.GenerateContent(); for (int i = 0; i < d.metricList.Count; i++) { GeneratorMetric m = d.metricList[i]; sampleData[i] += (float)m.method.Invoke(null, new object[] { output }); } } catch (Exception e) { //This failed, check the next value sampleFailed = true; break; } } if (sampleFailed) { continue; } //Did this change any of the metrics more than one standard deviation from the original sampling? bool nextParam = false; for (int i = 0; i < d.metricList.Count; i++) { sampleData[i] = sampleData[i] / numSamples; if (Mathf.Abs(sampleData[i] - metricAverages[i]) > stdev[i]) { Debug.Log("Parameter " + field.Name + " may have an impact on metrics"); nextParam = true; GeneratorParameter p = new GeneratorParameter(field.Name, original_value, original_value, original_value, field, b); p.locked = true; res.Add(p); break; } } if (nextParam) { field.SetValue(b, original_value); break; } } field.SetValue(b, original_value); } return(res); }
private void CreateSlopes(GeneratorParameter param, Tile[,] tiles) { bool AllHeightsHigher(int[] heights, int than) { for (int i = 0; i < heights.Length; i++) { if (heights[i] <= than) { return(false); } } return(true); } bool HasSlopeUp(SlopeIndex slope, int x, int y) { int h = tiles[x, y].GetMaxHeight(); switch (slope) { case SlopeIndex.North: if (IsInRange(x, y - 1)) { int height = tiles[x, y - 1].GetMaxHeight(); return((height == h + 1 || height == h + 2) && AllHeightsHigher(tiles[x, y - 1].height, h)); } else { return(false); } case SlopeIndex.East: if (IsInRange(x + 1, y)) { int height = tiles[x + 1, y].GetMaxHeight(); return((height == h + 1 || height == h + 2) && AllHeightsHigher(tiles[x + 1, y].height, h)); } else { return(false); } case SlopeIndex.South: if (IsInRange(x, y + 1)) { int height = tiles[x, y + 1].GetMaxHeight(); return((height == h + 1 || height == h + 2) && AllHeightsHigher(tiles[x, y + 1].height, h)); } else { return(false); } case SlopeIndex.West: if (IsInRange(x - 1, y)) { int height = tiles[x - 1, y].GetMaxHeight(); return((height == h + 1 || height == h + 2) && AllHeightsHigher(tiles[x - 1, y].height, h)); } else { return(false); } } return(false); } // check for 3 higher neighbours -> make it higher for (int x = 0; x < param.size.X; x++) { for (int y = 0; y < param.size.Y; y++) { int h = tiles[x, y].GetMaxHeight(); if (!tiles[x, y].AllHeightsAreSame()) { continue; } int higher = 0; foreach (Point p in IterateNeighboursEightDir(x, y)) { if (p.X == x || p.Y == y) { if (tiles[p.X, p.Y].GetMaxHeight() > h) { higher++; } } } if (higher >= 3) { for (int i = 0; i < tiles[x, y].height.Length; i++) { tiles[x, y].height[i] += 1; } } } } //check for 3 corner slops for (int x = 0; x < param.size.X; x++) { for (int y = 0; y < param.size.Y; y++) { /*if(tiles[x, y].type == TileType.Water) * { * tiles[x, y].height = new int[] { 5, 5, 5, 5 }; * }*/ if (!tiles[x, y].AllHeightsAreSame()) { continue; } int directions = 0; if (HasSlopeUp(SlopeIndex.North, x, y)) { directions += (int)SlopeIndex.North; } if (HasSlopeUp(SlopeIndex.East, x, y)) { directions += (int)SlopeIndex.East; } if (HasSlopeUp(SlopeIndex.South, x, y)) { directions += (int)SlopeIndex.South; } if (HasSlopeUp(SlopeIndex.West, x, y)) { directions += (int)SlopeIndex.West; } if (directions > 0) { if (directions == 3 || directions == 6 || directions == 12 || directions == 9) { int oldH = tiles[x, y].height[0]; for (int i = 0; i < 4; i++) { tiles[x, y].height[i] += 1; } if (directions == 3) { tiles[x, y].height[3]--; } if (directions == 6) { tiles[x, y].height[0]--; } if (directions == 12) { tiles[x, y].height[1]--; } if (directions == 9) { tiles[x, y].height[2]--; } } } } } //check for ramp slopes for (int x = 0; x < param.size.X; x++) { for (int y = 0; y < param.size.Y; y++) { if (!tiles[x, y].AllHeightsAreSame() || tiles[x, y].type == TileType.Water) { continue; } int directions = 0; if (HasSlopeUp(SlopeIndex.North, x, y)) { directions += (int)SlopeIndex.North; } else if (HasSlopeUp(SlopeIndex.East, x, y)) { directions += (int)SlopeIndex.East; } else if (HasSlopeUp(SlopeIndex.South, x, y)) { directions += (int)SlopeIndex.South; } else if (HasSlopeUp(SlopeIndex.West, x, y)) { directions += (int)SlopeIndex.West; } if (directions > 0) { int oldH = tiles[x, y].height[0]; for (int i = 0; i < 4; i++) { tiles[x, y].height[i] -= 1; } if ((directions & 1) == 0) //north { tiles[x, y].height[2] += 1; tiles[x, y].height[3] += 1; } if ((directions & 2) == 0) { tiles[x, y].height[0] += 1; tiles[x, y].height[3] += 1; } if ((directions & 4) == 0) { tiles[x, y].height[1] += 1; tiles[x, y].height[0] += 1; } if ((directions & 8) == 0) { tiles[x, y].height[2] += 1; tiles[x, y].height[1] += 1; } } } } // check for one-corner slops for (int x = 0; x < param.size.X; x++) { for (int y = 0; y < param.size.Y; y++) { int h = tiles[x, y].GetMaxHeight(); if (!tiles[x, y].AllHeightsAreSame() || tiles[x, y].type == TileType.Water) { continue; } //tiles[x, y].color = Color.Red; if (IsInRange(x - 1, y - 1)) { int height = tiles[x - 1, y - 1].GetMaxHeight(); if (AllHeightsHigher(tiles[x - 1, y - 1].height, h) && (height == h + 1 || height == h + 2)) { tiles[x, y].height[0] += 1; continue; } } if (IsInRange(x - 1, y + 1)) { int height = tiles[x - 1, y + 1].GetMaxHeight(); if (AllHeightsHigher(tiles[x - 1, y + 1].height, h) && (height == h + 1 || height == h + 2)) { tiles[x, y].height[3] += 1; continue; } } if (IsInRange(x + 1, y + 1)) { int height = tiles[x + 1, y + 1].GetMaxHeight(); if (AllHeightsHigher(tiles[x + 1, y + 1].height, h) && (height == h + 1 || height == h + 2)) { tiles[x, y].height[2] += 1; continue; } } if (IsInRange(x + 1, y - 1)) { int height = tiles[x + 1, y - 1].GetMaxHeight(); if (AllHeightsHigher(tiles[x + 1, y - 1].height, h) && (height == h + 1 || height == h + 2)) { tiles[x, y].height[1] += 1; continue; } } } } }