/// <summary> /// Draw gizmos /// </summary> void OnDrawGizmosSelected() { if (m_resources == null) { return; } if (m_spawner == null) { return; } if (m_terrainHeightMap == null) { return; } //Lets visualise fitness float x, y = transform.position.y, z; float xStart = transform.position.x - m_range; float xEnd = transform.position.x + m_range; float zStart = transform.position.z - m_range; float zEnd = transform.position.z + m_range; float ballsize = Mathf.Clamp(m_resolution * 0.25f, 0.5f, 5f); m_spawner.m_spawnRange = m_range; m_spawner.m_spawnerBounds = new Bounds(transform.position, new Vector3(m_range * 2f, m_range * 20f, m_range * 2f)); SpawnInfo spawnInfo = new SpawnInfo(); Vector3 location = new Vector3(); float fitness = 0f; //Create caches if ((DateTime.Now - m_lastCacheUpdateDate).TotalSeconds > 5) { m_lastCacheUpdateDate = DateTime.Now; m_spawner.DeleteSpawnCaches(); m_spawner.CreateSpawnCaches(m_selectedResourceType, m_selectedResourceIdx); //Also update the location so make moving it easier Terrain terrain = TerrainHelper.GetTerrain(transform.position); if (terrain != null) { transform.position = new Vector3(transform.position.x, terrain.SampleHeight(transform.position) + 5f, transform.position.z); } } //Set up the texture layer array in spawn info spawnInfo.m_textureStrengths = new float[Terrain.activeTerrain.terrainData.alphamapLayers]; //Now visualise fitness for (x = xStart; x < xEnd; x += m_resolution) { for (z = zStart; z < zEnd; z += m_resolution) { location.Set(x, y, z); if (m_spawner.CheckLocation(location, ref spawnInfo)) { fitness = GetFitness(ref spawnInfo); if (fitness < m_minimumFitness) { continue; } Gizmos.color = Color.Lerp(m_unfitColour, m_fitColour, fitness); Gizmos.DrawSphere(spawnInfo.m_hitLocationWU, ballsize); } } } //Now draw water //Water if (m_resources != null) { Bounds bounds = new Bounds(); if (TerrainHelper.GetTerrainBounds(transform.position, ref bounds) == true) { bounds.center = new Vector3(bounds.center.x, m_resources.m_seaLevel, bounds.center.z); bounds.size = new Vector3(bounds.size.x, 0.05f, bounds.size.z); Gizmos.color = new Color(Color.blue.r, Color.blue.g, Color.blue.b, Color.blue.a / 4f); Gizmos.DrawCube(bounds.center, bounds.size); } } }
/// <summary> /// Return fitness of the spawninfo object - not ideal as it forces closer coupling /// </summary> /// <param name="spawnInfo">Spawn infor object</param> /// <returns>Fitness at that location 0..1</returns> public float GetFitness(ref SpawnInfo spawnInfo) { //Make sure we are initialised if (!m_isInitialised) { Initialise(spawnInfo.m_spawner); } //Check for active or not if (!m_isActive) { return(0f); } //Check for virgin (clear terrain) if (m_virginTerrain == true) { if (spawnInfo.m_wasVirginTerrain != true) { return(0f); } } //Set default fitness float fitness = 1f; //Check height if (m_checkHeight) { fitness = Mathf.Min(fitness, GetHeightFitness(spawnInfo.m_terrainHeightWU, GaiaSessionManager.GetSessionManager().GetSeaLevel())); } //Check slope if (m_checkSlope && fitness > 0f) { if (m_checkType == GaiaConstants.SpawnerLocationCheckType.PointCheck) { fitness = Mathf.Min(fitness, GetSlopeFitness(spawnInfo.m_terrainSlopeWU)); } else { //fitness = Mathf.Min(fitness, GetSlopeFitness(spawnInfo.m_areaHitSlopeWU)); fitness = Mathf.Min(fitness, GetSlopeFitness(spawnInfo.m_areaAvgSlopeWU)); } } //Check textures if (m_checkTexture && fitness > 0f) { fitness = Mathf.Min(fitness, GetTextureFitness(spawnInfo.m_textureStrengths)); } //Check proximity if (m_checkProximity && fitness > 0f) { Rect area = new Rect(spawnInfo.m_hitLocationWU.x - m_maxProximity, spawnInfo.m_hitLocationWU.z - m_maxProximity, m_maxProximity * 2f, m_maxProximity * 2f); GameObject closestObject = null; //spawnInfo.m_spawner.GetClosestObject(m_proximityTag, area); if (closestObject != null) { fitness = Mathf.Min(fitness, GetProximityFitness(Vector3.Distance(closestObject.transform.position, spawnInfo.m_hitLocationWU))); } else { fitness = 0f; } } //Exit with final fitness return(fitness); }
/// <summary> /// Return the value of the least fittest object in the spawn criteria /// </summary> /// <param name="spawner">The spawner we belong to</param> /// <param name="location">The location we are checking</param> /// <param name="slope"></param> /// <returns>Fitness in range 0..1f</returns> public float GetMinFitness(ref SpawnInfo spawnInfo) { //Get the filters SpawnCritera[] filters; switch (m_selectedResourceType) { case GaiaConstants.SpawnerResourceType.TerrainDetail: { if (m_selectedResourceIdx >= spawnInfo.m_spawner.m_resources.m_detailPrototypes.Length) { return(0f); } filters = spawnInfo.m_spawner.m_resources.m_detailPrototypes[m_selectedResourceIdx].m_spawnCriteria; break; } case GaiaConstants.SpawnerResourceType.TerrainTexture: { if (m_selectedResourceIdx >= spawnInfo.m_spawner.m_resources.m_texturePrototypes.Length) { return(0f); } filters = spawnInfo.m_spawner.m_resources.m_texturePrototypes[m_selectedResourceIdx].m_spawnCriteria; break; } case GaiaConstants.SpawnerResourceType.TerrainTree: { if (m_selectedResourceIdx >= spawnInfo.m_spawner.m_resources.m_treePrototypes.Length) { return(0f); } filters = spawnInfo.m_spawner.m_resources.m_treePrototypes[m_selectedResourceIdx].m_spawnCriteria; break; } default: { if (m_selectedResourceIdx >= spawnInfo.m_spawner.m_resources.m_gameObjectPrototypes.Length) { return(0f); } filters = spawnInfo.m_spawner.m_resources.m_gameObjectPrototypes[m_selectedResourceIdx].m_spawnCriteria; break; } } //Drop out if we have no filters if (filters == null || filters.Length == 0) { return(0f); } //Now calculate fitness float minFitness = float.MaxValue; int filterIdx; SpawnCritera filter; float fitness = 0f; for (filterIdx = 0; filterIdx < filters.Length; filterIdx++) { filter = filters[filterIdx]; //Check to see of this filter needs a bounds check if (filter.m_checkType == GaiaConstants.SpawnerLocationCheckType.BoundedAreaCheck) { if (!spawnInfo.m_spawner.CheckLocationBounds(ref spawnInfo, GetMaxScaledRadius(ref spawnInfo))) { return(0f); } } //Now calculate and process fitness fitness = filter.GetFitness(ref spawnInfo); if (fitness < minFitness) { minFitness = fitness; if (minFitness <= 0f) { return(minFitness); } } } if (minFitness == float.MaxValue) { return(0f); } else { return(minFitness); } }
/// <summary> /// Call this to get the degree of completion in range 0..1. /// </summary> /// <param name="spawner">The spawner this is for</param> /// <param name="objSpawned">The object that was spawned in the spawn step (if relevant)</param> /// <returns>Return the completion in range of 0 (not started) .. 1 (completed)</returns> public override void PostSpawn(SpawnRule spawnRule, ref SpawnInfo spawnInfo) { //See if we can load the texture if (m_textureHM == null || !m_textureHM.HasData()) { return; } //Get the terrain Terrain t = Gaia.TerrainHelper.GetTerrain(spawnInfo.m_hitLocationWU); if (t == null) { return; } //Get the cached texture maps List <HeightMap> txtMaps = spawnInfo.m_spawner.GetTextureMaps(spawnInfo.m_hitTerrain.GetInstanceID()); if (txtMaps == null || m_textureIndex >= txtMaps.Count) { return; } //Make some speedy calculations float widthWU = spawnInfo.m_hitTerrain.terrainData.size.x; float depthWU = spawnInfo.m_hitTerrain.terrainData.size.z; float radiusWU = spawnRule.GetMaxScaledRadius(ref spawnInfo) * m_scaleMask; float xStartWU = spawnInfo.m_hitLocationWU.x - (radiusWU / 2f); float zStartWU = spawnInfo.m_hitLocationWU.z - (radiusWU / 2f); float xEndWU = xStartWU + radiusWU; float zEndWU = zStartWU + radiusWU; float stepWU = 0.5f; Vector3 locationWU = Vector3.zero; float xRotNU = 0f, zRotNU = 0f; float currStrength = 0f, newStrength = 1f; for (float x = xStartWU; x < xEndWU; x += stepWU) { for (float z = zStartWU; z < zEndWU; z += stepWU) { //Need to rotate x,z around the pivot by the rotation angle locationWU = new Vector3(x, spawnInfo.m_hitLocationWU.y, z); locationWU = Gaia.Utils.RotatePointAroundPivot(locationWU, spawnInfo.m_hitLocationWU, new Vector3(0f, spawnInfo.m_spawnRotationY, 0f)); //Now normalise the result xRotNU = (locationWU.x / widthWU) + 0.5f; zRotNU = (locationWU.z / depthWU) + 0.5f; //Drop out if out of bounds if (xRotNU < 0f || xRotNU >= 1f || zRotNU < 0f || zRotNU > 1f) { continue; } //Only interested in increasing values currStrength = txtMaps[m_textureIndex][zRotNU, xRotNU]; newStrength = m_textureHM[(x - xStartWU) / radiusWU, (z - zStartWU) / radiusWU]; if (newStrength > currStrength) { float delta = newStrength - currStrength; float theRest = 1f - currStrength; float adjustment = 0f; if (theRest != 0f) { adjustment = 1f - (delta / theRest); } for (int idx = 0; idx < txtMaps.Count; idx++) { if (idx == m_textureIndex) { txtMaps[idx][zRotNU, xRotNU] = newStrength; } else { txtMaps[idx][zRotNU, xRotNU] *= adjustment; } } } } } spawnInfo.m_spawner.SetTextureMapsDirty(); }