diff --git a/src/net/torvald/terrarum/weather/WeatherMixer.kt b/src/net/torvald/terrarum/weather/WeatherMixer.kt index f66f90357..11e9e03b5 100644 --- a/src/net/torvald/terrarum/weather/WeatherMixer.kt +++ b/src/net/torvald/terrarum/weather/WeatherMixer.kt @@ -280,6 +280,8 @@ internal object WeatherMixer : RNGConsumer { val oobMarginL = -0.5f * App.scr.wf private val oobMarginY = -0.5f * App.scr.hf + private val DEBUG_CAUSE_OF_DESPAWN = false + private fun updateClouds(delta: Float, world: GameWorld) { val camvec = WorldCamera.camVector val camvec2 = camvec.cpy() @@ -306,6 +308,7 @@ internal object WeatherMixer : RNGConsumer { var immDespawnCount = 0 + val immDespawnCauses = ArrayList() clouds.forEach { // do parallax scrolling it.posX += camDelta.x * cloudParallaxMultX @@ -314,12 +317,32 @@ internal object WeatherMixer : RNGConsumer { it.update(windVector) - if (it.life == 0) immDespawnCount += 1 + if (DEBUG_CAUSE_OF_DESPAWN && it.life == 0) { + immDespawnCount += 1 + immDespawnCauses.add(it.despawnCode) + } } // printdbg(this, "Newborn cloud death rate: $immDespawnCount/$cloudsSpawned") + if (DEBUG_CAUSE_OF_DESPAWN && App.IS_DEVELOPMENT_BUILD && immDespawnCount > cloudsSpawned / 4) { + val despawnCauseStats = HashMap() + immDespawnCauses.forEach { + if (despawnCauseStats[it] != null) { + despawnCauseStats[it] = despawnCauseStats[it]!! + 1 + } + else { + despawnCauseStats[it] = 1 + } + } + despawnCauseStats.forEach { s, i -> + printdbg(this, "Cause of death -- $s: $i") + } + System.exit(0) + } + + // remove clouds that are marked to be despawn var i = 0 while (true) { @@ -467,9 +490,12 @@ internal object WeatherMixer : RNGConsumer { // it does converge at ~6, but having it as an initial state does not make it stay converged repeat((currentWeather.cloudChance * 1.333f).ceilToInt()) { - val posXscr = FastMath.interpolateLinear(takeUniformRand(0f..1f), -hCloudSize, App.scr.width + hCloudSize) - val z = takeUniformRand(0.1f..ALPHA_ROLLOFF_Z - 0.1f).pow(1.5f) // clouds are more likely to spawn with low Z-value - val x = WeatherObjectCloud.screenXtoWorldX(posXscr, z) + val z = takeUniformRand(0.1f..ALPHA_ROLLOFF_Z / 4f - 0.1f).pow(1.5f) // clouds are more likely to spawn with low Z-value + + val zz = FastMath.interpolateLinear((z / ALPHA_ROLLOFF_Z) * 0.8f + 0.1f, ALPHA_ROLLOFF_Z / 4f, ALPHA_ROLLOFF_Z) + + val x = WeatherObjectCloud.screenXtoWorldX(takeUniformRand(0f..App.scr.wf), zz) + tryToSpawnCloud(currentWeather, Vector3(x, 0f, z)) } diff --git a/src/net/torvald/terrarum/weather/WeatherObjectCloud.kt b/src/net/torvald/terrarum/weather/WeatherObjectCloud.kt index ab669c9ea..1609f6e2d 100644 --- a/src/net/torvald/terrarum/weather/WeatherObjectCloud.kt +++ b/src/net/torvald/terrarum/weather/WeatherObjectCloud.kt @@ -8,6 +8,7 @@ import com.jme3.math.FastMath import net.torvald.terrarum.App import net.torvald.terrarum.App.printdbg import kotlin.math.pow +import kotlin.math.roundToInt import kotlin.math.sign /** @@ -20,9 +21,14 @@ class WeatherObjectCloud(private val texture: TextureRegion, private val flipW: } var life = 0; private set + var despawnCode = ""; private set + + private val lifespan = 40000 + ((Math.random() + Math.random()) * 20000).roundToInt() // triangular distibution of 40000..80000 private fun getZflowMult(z: Float) = z / ((z / 4f).pow(1.5f)) + private var eigenAlpha = 0f + /** * FlowVector: In which direction the cloud flows. Vec3(dX, dY, dScale) * Resulting vector: (x + dX, y + dY, scale * dScale) @@ -34,11 +40,22 @@ class WeatherObjectCloud(private val texture: TextureRegion, private val flipW: scl(vecMult) ) - alpha = if (posZ < 1f) posZ.pow(0.5f) else -((posZ - 1f) / ALPHA_ROLLOFF_Z) + 1f + eigenAlpha = if (posZ < 1f) posZ.pow(0.5f) else -((posZ - 1f) / ALPHA_ROLLOFF_Z) + 1f + + alpha = eigenAlpha * if (life < lifespan) 1f else 1f - (life - lifespan) / OLD_AGE_DECAY + val lrCoord = screenCoordBottomLRforDespawnCalculation if (lrCoord.x > WeatherMixer.oobMarginR || lrCoord.z < WeatherMixer.oobMarginL || posZ !in 0.0001f..ALPHA_ROLLOFF_Z + 1f || alpha < 0f) { flagToDespawn = true + + despawnCode = if (lrCoord.x > WeatherMixer.oobMarginR) "OUT_OF_SCREEN_RIGHT" + else if (lrCoord.z < WeatherMixer.oobMarginL) "OUT_OF_SCREEN_LEFT" + else if (posZ < 0.0001f) "OUT_OF_SCREEN_TOO_CLOSE" + else if (posZ > ALPHA_ROLLOFF_Z + 1f) "OUT_OF_SCREEN_TOO_FAR" + else if (life >= lifespan + OLD_AGE_DECAY) "OLD_AGE" + else if (alpha < 0f) "ALPHA_BELOW_ZERO" + else "UNKNOWN" } else { life += 1 @@ -115,5 +132,6 @@ class WeatherObjectCloud(private val texture: TextureRegion, private val flipW: companion object { fun screenXtoWorldX(screenX: Float, z: Float) = screenX * z - App.scr.halfwf * (z - 1f) const val ALPHA_ROLLOFF_Z = 64f + const val OLD_AGE_DECAY = 4000f } } \ No newline at end of file