weather sched progression wip

This commit is contained in:
minjaesong
2023-09-01 23:56:48 +09:00
parent abee176ef4
commit 66a103bd3a
8 changed files with 178 additions and 94 deletions

View File

@@ -1,8 +1,9 @@
{
"identifier": "generic01",
"skyboxGradColourMap": "generic_skybox.tga",
"daylightClut": "clut_daylight.tga",
"classification": "generic",
"cloudChance": 250,
"cloudChance": 125,
"cloudGamma": [0.48, 2.4],
"cloudGammaVariance": [0.1, 0.1],
"windSpeed": 0.25,
@@ -10,13 +11,13 @@
"clouds": {
"cumulonimbus": {
"filename": "cloud_large.png", "tw": 2048, "th": 1024, "probability": 0.2,
"baseScale": 2.0, "scaleVariance": 0.3333333,
"altLow": 80, "altHigh": 120
"baseScale": 4.0, "scaleVariance": 0.3333333,
"altLow": 1080, "altHigh": 1120
},
"cumulus": {
"filename": "cloud_normal.png", "tw": 1024, "th": 512, "probability": 1.0,
"baseScale": 1.0, "scaleVariance": 0.6,
"altLow": 80, "altHigh": 800
"baseScale": 2.0, "scaleVariance": 0.6,
"altLow": 1080, "altHigh": 1800
}
},
"atmoTurbidity": 3.5

View File

@@ -1,8 +1,9 @@
{
"identifier": "generic02",
"skyboxGradColourMap": "generic_skybox.tga",
"daylightClut": "clut_daylight.tga",
"classification": "generic2",
"cloudChance": 1600,
"cloudChance": 800,
"cloudGamma": [0.48, 2.4],
"cloudGammaVariance": [0.1, 0.1],
"windSpeed": 0.25,
@@ -10,18 +11,18 @@
"clouds": {
"cumulonimbus": {
"filename": "cloud_large.png", "tw": 2048, "th": 1024, "probability": 0.02,
"baseScale": 2.0, "scaleVariance": 0.3333333,
"altLow": 80, "altHigh": 120
"baseScale": 4.0, "scaleVariance": 0.3333333,
"altLow": 1080, "altHigh": 1120
},
"cumulus": {
"filename": "cloud_normal.png", "tw": 1024, "th": 512, "probability": 0.05,
"baseScale": 1.0, "scaleVariance": 0.6,
"altLow": 80, "altHigh": 800
"baseScale": 2.0, "scaleVariance": 0.6,
"altLow": 1080, "altHigh": 1800
},
"altocumulus": {
"filename": "cloud_normal.png", "tw": 1024, "th": 512, "probability": 1.0,
"baseScale": 0.5, "scaleVariance": 0.1,
"altLow": 1600, "altHigh": 2400
"baseScale": 1.0, "scaleVariance": 0.1,
"altLow": 2600, "altHigh": 3400
}
},
"atmoTurbidity": 3.5,

View File

@@ -1,4 +1,5 @@
{
"identifier": "overcast01",
"skyboxGradColourMap": "generic_skybox.tga",
"daylightClut": "clut_daylight.tga",
"classification": "overcast",
@@ -10,18 +11,18 @@
"clouds": {
"cumulus": {
"filename": "cloud_normal.png", "tw": 1024, "th": 512, "probability": 0.1,
"baseScale": 0.8, "scaleVariance": 0.6,
"altLow": 80, "altHigh": 800
"baseScale": 1.6, "scaleVariance": 0.6,
"altLow": 580, "altHigh": 1300
},
"cumulonimbus": {
"filename": "cloud_large.png", "tw": 2048, "th": 1024, "probability": 0.4,
"baseScale": 2.0, "scaleVariance": 0.3333333,
"altLow": 90, "altHigh": 120
"baseScale": 4.0, "scaleVariance": 0.3333333,
"altLow": 590, "altHigh":60
},
"nimbostratus": {
"filename": "cloud_wide.png", "tw": 4096, "th": 1024, "probability": 1.0,
"baseScale": 4.0, "scaleVariance": 0.1,
"altLow": 100, "altHigh": 100
"baseScale": 8.0, "scaleVariance": 0.1,
"altLow": 600, "altHigh": 700
}
},
"atmoTurbidity": 9.5

View File

@@ -14,6 +14,8 @@ import net.torvald.terrarum.savegame.ByteArray64GrowableOutputStream
import net.torvald.terrarum.savegame.ByteArray64InputStream
import net.torvald.terrarum.savegame.ByteArray64Reader
import net.torvald.terrarum.utils.*
import net.torvald.terrarum.weather.BaseModularWeather
import net.torvald.terrarum.weather.WeatherMixer
import net.torvald.terrarum.weather.WeatherStateBox
import org.apache.commons.codec.digest.DigestUtils
import java.io.File
@@ -217,15 +219,25 @@ object Common {
// WeatherStateBox
jsoner.setSerializer(WeatherStateBox::class.java, object : Json.Serializer<WeatherStateBox> {
override fun write(json: Json, obj: WeatherStateBox, knownType: Class<*>?) {
json.writeValue("${obj.x};${obj.p0};${obj.p1};${obj.p2};${obj.p3}")
json.writeValue("${obj.x};${obj.pM2};${obj.pM1};${obj.p0};${obj.p1};${obj.p2};${obj.p3}")
}
override fun read(json: Json, jsonData: JsonValue, type: Class<*>?): WeatherStateBox {
return jsonData.asString().split(';').map { it.toFloat() }.let {
WeatherStateBox(it[0], it[1], it[2], it[3], it[4])
WeatherStateBox(it[0], it[1], it[2], it[3], it[4], it[5], it[6])
}
}
})
// BaseModularWeather
jsoner.setSerializer(BaseModularWeather::class.java, object : Json.Serializer<BaseModularWeather> {
override fun write(json: Json, obj: BaseModularWeather, knownType: Class<*>?) {
json.writeValue(obj.identifier)
}
override fun read(json: Json, jsonData: JsonValue, type: Class<*>?): BaseModularWeather {
return WeatherMixer.weatherDict[jsonData.asString()]!!
}
})
}

View File

@@ -112,6 +112,10 @@ class BasicDebugInfoWindow : UICanvas() {
if (this == null) "null" else if (this.isNaN()) "NaN" else if (this.isInfinite()) "${if (this >= 0.0) '+' else '-'}Inf" else
"${((if (this >= 0.0) "" else "-") + "${this.absoluteValue.toInt()}").padStart(intLen)}." +
(10.0 pow fracLen.toDouble()).let { d -> (this.absoluteValue.times(d) % d).toInt().toString().padStart(fracLen, '0').padEnd(fracLen) }
private fun Float?.toIntAndFrac(intLen: Int, fracLen: Int = 4): String =
if (this == null) "null" else if (this.isNaN()) "NaN" else if (this.isInfinite()) "${if (this >= 0.0) '+' else '-'}Inf" else
"${((if (this >= 0.0) "" else "-") + "${this.absoluteValue.toInt()}").padStart(intLen)}." +
(10.0 pow fracLen.toDouble()).let { d -> (this.absoluteValue.times(d) % d).toInt().toString().padStart(fracLen, '0').padEnd(fracLen) }
private val gap = 14f
@@ -236,10 +240,10 @@ class BasicDebugInfoWindow : UICanvas() {
try {
world?.let {
val valRaw = LightmapRenderer.getLight(mouseTileX, mouseTileY)
val rawR = valRaw?.r?.toDouble().toIntAndFrac(1,3)
val rawG = valRaw?.g?.toDouble().toIntAndFrac(1,3)
val rawB = valRaw?.b?.toDouble().toIntAndFrac(1,3)
val rawA = valRaw?.a?.toDouble().toIntAndFrac(1,3)
val rawR = valRaw?.r?.toIntAndFrac(1,3)
val rawG = valRaw?.g?.toIntAndFrac(1,3)
val rawB = valRaw?.b?.toIntAndFrac(1,3)
val rawA = valRaw?.a?.toIntAndFrac(1,3)
val wallNum = it.getTileFromWall(mouseTileX, mouseTileY)
val tileNum = it.getTileFromTerrain(mouseTileX, mouseTileY)
@@ -249,7 +253,7 @@ class BasicDebugInfoWindow : UICanvas() {
App.fontSmallNumbers.draw(batch, "$ccO$TERRAIN$ccG$tileNum", gap + 7f*(tileCursX + 3), line(tileCursY))
App.fontSmallNumbers.draw(batch, "$ccO$WALL$ccG$wallNum", gap + 7f*(tileCursX + 3), line(tileCursY + 1))
App.fontSmallNumbers.draw(batch, "$ccO$LIQUID$ccG${fluid.type.value.toString().padEnd(3)}$ccO$BEAKER$ccG${fluid.amount}f", gap + 7f*(tileCursX + 3), line(tileCursY + 2))
App.fontSmallNumbers.draw(batch, "$ccO$LIQUID$ccG${fluid.type.value.toString().padEnd(3)}$ccO$BEAKER$ccG${fluid.amount.toIntAndFrac(2)}", gap + 7f*(tileCursX + 3), line(tileCursY + 2))
App.fontSmallNumbers.draw(batch, "$ccO$WIRE$ccG$wireCount ${ccY}X$ccO$mouseTileX ${ccY}Y$ccO$mouseTileY", gap + 7f*(tileCursX + 3), line(tileCursY + 3))
App.fontSmallNumbers.draw(batch, "$ccR$rawR $ccG$rawG $ccB$rawB $ccW$rawA", gap + 7f*(tileCursX + 3), line(tileCursY + 4))
@@ -344,8 +348,19 @@ class BasicDebugInfoWindow : UICanvas() {
private fun drawWeatherInfo(batch: SpriteBatch) {
drawWeatherStateBox(batch, WeatherMixer.weatherbox.windSpeed, "WindSpd", App.scr.width - 170, App.scr.height - 140 - 120, WeatherMixer.currentWeather.windSpeed * (1.0 + WeatherMixer.currentWeather.windSpeedVariance))
drawWeatherStateBox(batch, WeatherMixer.weatherbox.windDir, "WindDir", App.scr.width - 170, App.scr.height - 140)
val drawX = App.scr.width - 170
val drawXf = drawX.toFloat()
drawWeatherStateBox(batch, WeatherMixer.weatherbox.windSpeed, "WindSpd", drawX, App.scr.height - 140 - 120, WeatherMixer.currentWeather.windSpeed * (1.0 + WeatherMixer.currentWeather.windSpeedVariance))
drawWeatherStateBox(batch, WeatherMixer.weatherbox.windDir, "WindDir", drawX, App.scr.height - 140)
// draw weather schedule
val schedYstart = App.scr.height - 140 - 120 - 13f * (WeatherMixer.weatherbox.weatherSchedule.size + 3)
App.fontSmallNumbers.draw(batch, "$ccY== WeatherSched [${WeatherMixer.weatherbox.weatherSchedule.size}] ==", drawXf, schedYstart)
WeatherMixer.weatherbox.weatherSchedule.forEachIndexed { index, weather ->
val sek = if (index == 0) WeatherMixer.weatherbox.updateAkku else 0
App.fontSmallNumbers.draw(batch, "$ccY${weather.weather.identifier} $ccG${weather.duration - sek}", drawXf, schedYstart + 13 * (index + 1))
}
}
private val colHairline = Color(0xf22100ff.toInt())
@@ -468,7 +483,7 @@ class BasicDebugInfoWindow : UICanvas() {
// text
batch.color = Color.WHITE
App.fontSmallNumbers.draw(batch, "$ccY$label $ccG${box.value().toDouble().toIntAndFrac(3)}", x.toFloat(), y - 16f)
App.fontSmallNumbers.draw(batch, "$ccY$label $ccG${box.value.toDouble().toIntAndFrac(3)}", x.toFloat(), y - 15f)
}
private val processorName = App.processor.replace(Regex(""" Processor|( CPU)? @ [0-9.]+GHz"""), "") + if (App.is32BitJVM) " (32-bit)" else ""

View File

@@ -17,6 +17,7 @@ import kotlin.math.absoluteValue
* Created by minjaesong on 2016-07-11.
*/
data class BaseModularWeather(
val identifier: String,
val json: JsonValue,
var skyboxGradColourMap: GdxColorMap, // row 0: skybox grad top, row 1: skybox grad bottom, row 2: sunlight (RGBA)
val daylightClut: GdxColorMap,
@@ -30,9 +31,8 @@ data class BaseModularWeather(
val mixFrom: String? = null,
val mixPercentage: Double? = null,
var forceWindVec: Vector3? = null
) {
/**
* @param rnd random number between -1 and +1
*/

View File

@@ -29,7 +29,6 @@ import java.io.File
import java.io.FileFilter
import java.lang.Double.doubleToLongBits
import java.lang.Math.toDegrees
import java.lang.Math.toRadians
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.math.*
@@ -52,16 +51,32 @@ import kotlin.math.*
*/
internal object WeatherMixer : RNGConsumer {
val DEFAULT_WEATHER = BaseModularWeather(
"default",
JsonValue(JsonValue.ValueType.`object`),
GdxColorMap(1, 3, Color(0x55aaffff), Color(0xaaffffff.toInt()), Color.WHITE),
GdxColorMap(2, 2, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE),
"default",
0f,
0f,
0f,
Vector2(1f, 1f),
Vector2(0f, 0f),
listOf()
)
override val RNG = HQRNG()
var globalLightOverridden = false
var weatherList: HashMap<String, ArrayList<BaseModularWeather>>
val weatherDB: HashMap<String, ArrayList<BaseModularWeather>> // search by classification
val weatherDict: HashMap<String, BaseModularWeather> // search by identifier
var currentWeather: BaseModularWeather
var nextWeather: BaseModularWeather
val currentWeather: BaseModularWeather
get() = weatherbox.currentWeather
// var nextWeather: BaseModularWeather
lateinit var mixedWeather: BaseModularWeather
private var forceWindVec: Vector3? = null
val globalLightNow = Cvec(0)
private val cloudDrawColour = Color()
@@ -105,13 +120,11 @@ internal object WeatherMixer : RNGConsumer {
override fun loadFromSave(s0: Long, s1: Long) {
super.loadFromSave(s0, s1)
currentWeather = weatherList[WEATHER_GENERIC]!![0]
internalReset(s0, s1)
initClouds()
}
fun internalReset() {
currentWeather = weatherList[WEATHER_GENERIC]!![0]
internalReset(RNG.state0, RNG.state1)
initClouds()
}
@@ -127,11 +140,14 @@ internal object WeatherMixer : RNGConsumer {
clouds.clear()
cloudsSpawned = 0
forceWindVec = null
windVector = Vector3(-0.98f, 0f, 0.21f)
oldCamPos.set(WorldCamera.camVector)
weatherbox = Weatherbox()
weatherbox.initWith(weatherDict["generic01"]!!, 3600L)
// TEST FILL WITH RANDOM VALUES
(0..5).map { takeUniformRand(0f..1f) }.let {
weatherbox.windDir.pM1 = it[0]
@@ -152,7 +168,8 @@ internal object WeatherMixer : RNGConsumer {
}
init {
weatherList = HashMap<String, ArrayList<BaseModularWeather>>()
weatherDB = HashMap<String, ArrayList<BaseModularWeather>>()
weatherDict = HashMap<String, BaseModularWeather>()
// read weather descriptions from assets/weather (modular weather)
@@ -169,40 +186,16 @@ internal object WeatherMixer : RNGConsumer {
for ((modname, raw) in weatherRawValidList) {
val weather = readFromJson(modname, raw)
weatherDict[weather.identifier] = weather
// if List for the classification does not exist, make one
if (!weatherList.containsKey(weather.classification))
weatherList.put(weather.classification, ArrayList())
if (!weatherDB.containsKey(weather.classification))
weatherDB.put(weather.classification, ArrayList())
weatherList[weather.classification]!!.add(weather)
weatherDB[weather.classification]!!.add(weather)
}
// initialise
try {
weatherList["titlescreen"] = arrayListOf(weatherList[WEATHER_GENERIC]!![0].copy(windSpeed = 1f))
currentWeather = weatherList[WEATHER_GENERIC]!![0]
nextWeather = getRandomWeather(WEATHER_GENERIC)
}
catch (e: NullPointerException) {
e.printStackTrace()
val defaultWeather = BaseModularWeather(
JsonValue(JsonValue.ValueType.`object`),
GdxColorMap(1, 3, Color(0x55aaffff), Color(0xaaffffff.toInt()), Color.WHITE),
GdxColorMap(2, 2, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE),
"default",
0f,
0f,
0f,
Vector2(1f, 1f),
Vector2(0f, 0f),
listOf()
)
currentWeather = defaultWeather
nextWeather = defaultWeather
}
weatherDict["titlescreen"] = weatherDB[WEATHER_GENERIC]!![0].copy(windSpeed = 1f)
}
/**
@@ -213,7 +206,8 @@ internal object WeatherMixer : RNGConsumer {
// currentWeather = weatherList[WEATHER_GENERIC]!![0] // force set weather
updateWind(delta, world)
weatherbox.update(world)
updateWind()
updateClouds(delta, world)
@@ -230,12 +224,11 @@ internal object WeatherMixer : RNGConsumer {
this[this.lastIndex] = f
}
private val HALF_PI = 1.5707964f
private val PI = 3.1415927f
private val TWO_PI = 6.2831855f
private val THREE_PI = 9.424778f
private val WIND_DIR_TIME_UNIT = 14400f // every 4hr
private val WIND_SPEED_TIME_UNIT = 3600f // every 1hr
// see: https://stackoverflow.com/questions/2708476/rotation-interpolation/14498790#14498790
private fun getShortestAngle(start: Float, end: Float) =
@@ -243,22 +236,20 @@ internal object WeatherMixer : RNGConsumer {
if (it > PI) it - TWO_PI else it
}
private fun updateWind(delta: Float, world: GameWorld) {
private fun updateWind() {
val currentWindSpeed = weatherbox.windSpeed.value
val currentWindDir = weatherbox.windDir.value * HALF_PI
val currentWindSpeed = weatherbox.windSpeed.getAndUpdate( world.worldTime.timeDelta / WIND_SPEED_TIME_UNIT) {
currentWeather.getRandomWindSpeed(takeUniformRand(-1f..1f))
}
val currentWindDir = weatherbox.windDir.getAndUpdate( world.worldTime.timeDelta / WIND_DIR_TIME_UNIT) { RNG.nextFloat() * 4f } * Math.PI * 0.5
printdbg(this, "Wind speed = $currentWindSpeed")
if (currentWeather.forceWindVec != null) {
windVector.set(currentWeather.forceWindVec)
if (forceWindVec != null) {
windVector.set(forceWindVec)
}
else {
windVector.set(
(cos(currentWindDir) * currentWindSpeed).toFloat(),
(cos(currentWindDir) * currentWindSpeed),
0f,
(sin(currentWindDir) * currentWindSpeed).toFloat()
(sin(currentWindDir) * currentWindSpeed)
)
}
}
@@ -280,6 +271,7 @@ internal object WeatherMixer : RNGConsumer {
val camvec2 = camvec.cpy()
val testCamDelta = camvec.cpy().sub(oldCamPos)
// adjust camDelta to accomodate ROUNDWORLD
if (testCamDelta.x.absoluteValue > world.width * TILE_SIZEF / 2f) {
if (testCamDelta.x >= 0)
camvec2.x -= world.width * TILE_SIZEF
@@ -291,7 +283,7 @@ internal object WeatherMixer : RNGConsumer {
camDelta.set(testCamDelta)
// try to spawn an cloud
val cloudChanceEveryMin = 60f / (currentWeather.cloudChance * currentWeather.windSpeed) // if chance = 0, the result will be +inf
while (cloudUpdateAkku >= cloudChanceEveryMin) {
@@ -302,12 +294,13 @@ internal object WeatherMixer : RNGConsumer {
var immDespawnCount = 0
val immDespawnCauses = ArrayList<String>()
printdbg(this, "Wind vector = $windVector")
// move the clouds
clouds.forEach {
// do parallax scrolling
it.posX += camDelta.x * cloudParallaxMultX
it.posY += camDelta.y * cloudParallaxMultY
it.update(windVector)
if (DEBUG_CAUSE_OF_DESPAWN && it.life == 0) {
@@ -498,8 +491,8 @@ internal object WeatherMixer : RNGConsumer {
}
internal fun titleScreenInitWeather() {
currentWeather = weatherList["titlescreen"]!![0]
currentWeather.forceWindVec = Vector3(-0.98f, 0f, -0.21f)
weatherbox.initWith(weatherDict["titlescreen"]!!, Long.MAX_VALUE)
forceWindVec = Vector3(-0.98f, 0f, -0.21f)
initClouds()
}
@@ -728,7 +721,7 @@ internal object WeatherMixer : RNGConsumer {
}
}
fun getWeatherList(classification: String) = weatherList[classification]!!
fun getWeatherList(classification: String) = weatherDB[classification]!!
fun getRandomWeather(classification: String) =
getWeatherList(classification)[RNG.nextInt(getWeatherList(classification).size)]
@@ -757,7 +750,7 @@ internal object WeatherMixer : RNGConsumer {
val skybox = GdxColorMap(ModMgr.getGdxFile(modname, "$pathToImage/${skyboxInJson}"))
val daylight = GdxColorMap(ModMgr.getGdxFile(modname, "$pathToImage/${lightbox}"))
val identifier = JSON.getString("identifier")
val classification = JSON.getString("classification")
@@ -797,6 +790,7 @@ internal object WeatherMixer : RNGConsumer {
return BaseModularWeather(
identifier = identifier,
json = JSON,
skyboxGradColourMap = skybox,
daylightClut = daylight,
@@ -811,7 +805,7 @@ internal object WeatherMixer : RNGConsumer {
}
fun dispose() {
weatherList.values.forEach { list ->
weatherDB.values.forEach { list ->
list.forEach { weather ->
weather.clouds.forEach { it.spriteSheet.dispose() }
}

View File

@@ -1,15 +1,77 @@
package net.torvald.terrarum.weather
import com.jme3.math.FastMath
import net.torvald.terrarum.floorToInt
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.fmod
import kotlin.math.absoluteValue
import java.util.*
data class WeatherSchedule(val weather: BaseModularWeather = WeatherMixer.DEFAULT_WEATHER, val duration: Long = 3600)
class Weatherbox {
companion object {
private val WIND_DIR_TIME_UNIT = 3600f * 5 // every 5hr
private val WIND_SPEED_TIME_UNIT = 3600f * 2 // every 2hr
private val HALF_PIF = 1.5707964f
private val PIF = 3.1415927f
private val TWO_PIF = 6.2831855f
private val THREE_PIF = 9.424778f
}
private fun takeUniformRand(range: ClosedFloatingPointRange<Float>) =
FastMath.interpolateLinear(RNG.nextFloat(), range.start, range.endInclusive)
private fun takeTriangularRand(range: ClosedFloatingPointRange<Float>) =
FastMath.interpolateLinear((RNG.nextFloat() + RNG.nextFloat()) / 2f, range.start, range.endInclusive)
private fun takeGaussianRand(range: ClosedFloatingPointRange<Float>) =
FastMath.interpolateLinear((RNG.nextFloat() + RNG.nextFloat() + RNG.nextFloat() + RNG.nextFloat() + RNG.nextFloat() + RNG.nextFloat() + RNG.nextFloat() + RNG.nextFloat()) / 8f, range.start, range.endInclusive)
val RNG: Random
get() = WeatherMixer.RNG
val windDir = WeatherDirBox() // 0 .. 1.0
val windSpeed = WeatherStateBox() // 0 .. arbitrarily large number
val weatherSchedule: MutableList<WeatherSchedule> = mutableListOf<WeatherSchedule>()
val currentWeather: BaseModularWeather
get() = weatherSchedule[0].weather
val currentWeatherDuration: Long
get() = weatherSchedule[0].duration
fun initWith(initWeather: BaseModularWeather, duration: Long) {
weatherSchedule.add(WeatherSchedule(initWeather, duration))
}
var updateAkku = 0L; private set
fun update(world: GameWorld) {
updateWind(world)
if (updateAkku >= currentWeatherDuration) {
// TODO add more random weathers
if (weatherSchedule.size == 1) {
val newName = if (currentWeather.identifier == "generic01") "overcast01" else "generic01"
val newDuration = 3600L
weatherSchedule.add(WeatherSchedule(WeatherMixer.weatherDict[newName]!!, newDuration))
println("Queueing next weather '$newName' that will last $newDuration seconds")
}
// subtract akku by old currentWeatherDuration
updateAkku -= weatherSchedule.removeAt(0).duration
}
updateAkku += world.worldTime.timeDelta
}
private fun updateWind(world: GameWorld) {
windSpeed.update(world.worldTime.timeDelta / WIND_SPEED_TIME_UNIT) {
currentWeather.getRandomWindSpeed(takeUniformRand(-1f..1f))
}
windDir.update( world.worldTime.timeDelta / WIND_DIR_TIME_UNIT) { RNG.nextFloat() * 4f }
}
}
@@ -27,7 +89,7 @@ open class WeatherStateBox(
// - removing p4 and beyond: for faster response to the changing weather schedule and make the forecasting less accurate like irl
) {
open fun value() = interpolate(x, p0, p1, p2, p3)
open val value: Float; get() = interpolate(x, p0, p1, p2, p3)
open fun valueAt(x: Float) = when (x.floorToInt()) {
-2 -> interpolate(x + 2, pM2,pM1, p0, p1)
-1 -> interpolate(x + 1, pM1, p0, p1, p2)
@@ -38,9 +100,8 @@ open class WeatherStateBox(
else -> throw IllegalArgumentException()
}
open fun getAndUpdate(xdelta: Float, next: () -> Float): Float {
open fun update(xdelta: Float, next: () -> Float) {
synchronized(WeatherMixer.RNG) {
val y = value()
x += xdelta
while (x >= 1.0) {
x -= 1.0f
@@ -56,7 +117,6 @@ open class WeatherStateBox(
// p4 = p5
// p5 = next()
}
return y
}
}
protected fun interpolate(u: Float, p0: Float, p1: Float, p2: Float, p3: Float): Float {
@@ -85,7 +145,7 @@ class WeatherDirBox(
p2: Float = 0f,
p3: Float = 0f,
) : WeatherStateBox(x, pM2, pM1, p0, p1, p2, p3) {
override fun value() = valueAt(x)
override val value; get() = valueAt(x)
override fun valueAt(x: Float): Float {
var pM2 = pM2